mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-18 07:45:30 +00:00
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
commit
7e6ef531b7
@ -10,6 +10,7 @@ const Services = require("Services");
|
||||
const {HTMLTooltip} = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {PrefObserver} = require("devtools/client/shared/prefs");
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
|
||||
let itemIdCounter = 0;
|
||||
/**
|
||||
@ -461,8 +462,15 @@ AutocompletePopup.prototype = {
|
||||
|
||||
if (item.postLabel) {
|
||||
let postDesc = this._document.createElementNS(HTML_NS, "span");
|
||||
postDesc.textContent = item.postLabel;
|
||||
postDesc.className = "autocomplete-postlabel";
|
||||
postDesc.textContent = item.postLabel;
|
||||
// Determines if the postlabel is a valid colour or other value
|
||||
if (this._isValidColor(item.postLabel)) {
|
||||
let colorSwatch = this._document.createElementNS(HTML_NS, "span");
|
||||
colorSwatch.className = "autocomplete-swatch autocomplete-colorswatch";
|
||||
colorSwatch.style.cssText = "background-color: " + item.postLabel;
|
||||
postDesc.insertBefore(colorSwatch, postDesc.childNodes[0]);
|
||||
}
|
||||
listItem.appendChild(postDesc);
|
||||
}
|
||||
|
||||
@ -603,6 +611,18 @@ AutocompletePopup.prototype = {
|
||||
this._currentTheme = newValue;
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the specified colour object is a valid colour, and if
|
||||
* it is not a "special value"
|
||||
*
|
||||
* @return {Boolean}
|
||||
* If the object represents a proper colour or not.
|
||||
*/
|
||||
_isValidColor: function(color) {
|
||||
let colorObj = new colorUtils.CssColor(color);
|
||||
return (colorObj.valid && (!colorObj.specialValue));
|
||||
},
|
||||
|
||||
/**
|
||||
* Used by tests.
|
||||
*/
|
||||
|
@ -15,6 +15,8 @@ loadHelperScript("helper_inplace_editor.js");
|
||||
// Also using a mocked list of CSS properties to avoid autocompletion when
|
||||
// typing in "var"
|
||||
|
||||
// Used for representing the expectation of a visible color swatch
|
||||
const COLORSWATCH = true;
|
||||
// format :
|
||||
// [
|
||||
// what key to press,
|
||||
@ -22,28 +24,40 @@ loadHelperScript("helper_inplace_editor.js");
|
||||
// selected suggestion index (-1 if popup is hidden),
|
||||
// number of suggestions in the popup (0 if popup is hidden),
|
||||
// expected post label corresponding with the input box value,
|
||||
// boolean representing if there should be a colour swatch visible,
|
||||
// ]
|
||||
const testData = [
|
||||
["v", "v", -1, 0, null],
|
||||
["a", "va", -1, 0, null],
|
||||
["r", "var", -1, 0, null],
|
||||
["(", "var()", -1, 0, null],
|
||||
["-", "var(--abc)", 0, 4, "blue"],
|
||||
["VK_BACK_SPACE", "var(-)", -1, 0, null],
|
||||
["-", "var(--abc)", 0, 4, "blue"],
|
||||
["VK_DOWN", "var(--def)", 1, 4, "red"],
|
||||
["VK_DOWN", "var(--ghi)", 2, 4, "green"],
|
||||
["VK_DOWN", "var(--jkl)", 3, 4, "yellow"],
|
||||
["VK_DOWN", "var(--abc)", 0, 4, "blue"],
|
||||
["VK_DOWN", "var(--def)", 1, 4, "red"],
|
||||
["VK_LEFT", "var(--def)", -1, 0, null],
|
||||
["v", "v", -1, 0, null, !COLORSWATCH],
|
||||
["a", "va", -1, 0, null, !COLORSWATCH],
|
||||
["r", "var", -1, 0, null, !COLORSWATCH],
|
||||
["(", "var()", -1, 0, null, !COLORSWATCH],
|
||||
["-", "var(--abc)", 0, 9, "inherit", !COLORSWATCH],
|
||||
["VK_BACK_SPACE", "var(-)", -1, 0, null, !COLORSWATCH],
|
||||
["-", "var(--abc)", 0, 9, "inherit", !COLORSWATCH],
|
||||
["VK_DOWN", "var(--def)", 1, 9, "transparent", !COLORSWATCH],
|
||||
["VK_DOWN", "var(--ghi)", 2, 9, "#00FF00", COLORSWATCH],
|
||||
["VK_DOWN", "var(--jkl)", 3, 9, "rgb(255, 0, 0)", COLORSWATCH],
|
||||
["VK_DOWN", "var(--mno)", 4, 9, "hsl(120, 60%, 70%)", COLORSWATCH],
|
||||
["VK_DOWN", "var(--pqr)", 5, 9, "BlueViolet", COLORSWATCH],
|
||||
["VK_DOWN", "var(--stu)", 6, 9, "15px", !COLORSWATCH],
|
||||
["VK_DOWN", "var(--vwx)", 7, 9, "rgba(255, 0, 0, 0.4)", COLORSWATCH],
|
||||
["VK_DOWN", "var(--yz)", 8, 9, "hsla(120, 60%, 70%, 0.3)", COLORSWATCH],
|
||||
["VK_DOWN", "var(--abc)", 0, 9, "inherit", !COLORSWATCH],
|
||||
["VK_DOWN", "var(--def)", 1, 9, "transparent", !COLORSWATCH],
|
||||
["VK_DOWN", "var(--ghi)", 2, 9, "#00FF00", COLORSWATCH],
|
||||
["VK_LEFT", "var(--ghi)", -1, 0, null, !COLORSWATCH],
|
||||
];
|
||||
|
||||
const CSS_VARIABLES = [
|
||||
["--abc", "blue"],
|
||||
["--def", "red"],
|
||||
["--ghi", "green"],
|
||||
["--jkl", "yellow"]
|
||||
["--abc", "inherit"],
|
||||
["--def", "transparent"],
|
||||
["--ghi", "#00FF00"],
|
||||
["--jkl", "rgb(255, 0, 0)"],
|
||||
["--mno", "hsl(120, 60%, 70%)"],
|
||||
["--pqr", "BlueViolet"],
|
||||
["--stu", "15px"],
|
||||
["--vwx", "rgba(255, 0, 0, 0.4)"],
|
||||
["--yz", "hsla(120, 60%, 70%, 0.3)"],
|
||||
];
|
||||
|
||||
const mockGetCSSValuesForPropertyName = function(propertyName) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const { editableField } = require("devtools/client/shared/inplace-editor");
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
|
||||
/**
|
||||
* Create an inplace editor linked to a span element and click on the span to
|
||||
@ -73,10 +74,12 @@ function createSpan(doc) {
|
||||
* - {Number} index, the index of the selected suggestion in the popup
|
||||
* - {Number} total, the total number of suggestions in the popup
|
||||
* - {String} postLabel, the expected post label for the selected suggestion
|
||||
* - {Boolean} colorSwatch, if there is a swatch of color expected to be visible
|
||||
* @param {InplaceEditor} editor
|
||||
* The InplaceEditor instance being tested
|
||||
*/
|
||||
async function testCompletion([key, completion, index, total, postLabel], editor) {
|
||||
async function testCompletion([key, completion, index, total,
|
||||
postLabel, colorSwatch], editor) {
|
||||
info("Pressing key " + key);
|
||||
info("Expecting " + completion);
|
||||
|
||||
@ -112,6 +115,21 @@ async function testCompletion([key, completion, index, total, postLabel], editor
|
||||
let selectedElement = editor.popup.elements.get(selectedItem);
|
||||
ok(selectedElement.textContent.includes(postLabel),
|
||||
"Selected popup element contains the expected post-label");
|
||||
|
||||
// Determines if there is a color swatch attached to the label
|
||||
// and if the color swatch's background color matches the post label
|
||||
let swatchSpan = selectedElement.getElementsByClassName(
|
||||
"autocomplete-swatch autocomplete-colorswatch");
|
||||
if (colorSwatch) {
|
||||
ok(swatchSpan.length === 1, "Displayed the expected color swatch");
|
||||
let color = new colorUtils.CssColor(swatchSpan[0].style.backgroundColor);
|
||||
let swatchColor = color.rgba;
|
||||
color.newColor(postLabel);
|
||||
let postColor = color.rgba;
|
||||
ok(swatchColor == postColor, "Color swatch matches postLabel value");
|
||||
} else {
|
||||
ok(swatchSpan.length === 0, "As expected no swatches were available");
|
||||
}
|
||||
}
|
||||
|
||||
if (total === 0) {
|
||||
|
@ -108,6 +108,35 @@ html|button, html|select {
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.devtools-autocomplete-listbox .autocomplete-swatch {
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
/* align the swatch with its value */
|
||||
margin-top: -1px;
|
||||
margin-inline-end: 5px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.devtools-autocomplete-listbox .autocomplete-colorswatch::before {
|
||||
content: '';
|
||||
background-color: #eee;
|
||||
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),
|
||||
linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc);
|
||||
background-size: 12px 12px;
|
||||
background-position: 0 0, 6px 6px;
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
/* Rest of the dark and light theme */
|
||||
|
||||
.devtools-autocomplete-popup,
|
||||
|
@ -173,15 +173,9 @@ StructuredCloneBlob::WriteStructuredClone(JSContext* aCx, JSStructuredCloneWrite
|
||||
|
||||
aHolder->BlobImpls().AppendElements(BlobImpls());
|
||||
|
||||
auto iter = data.Iter();
|
||||
while (!iter.Done()) {
|
||||
if (!JS_WriteBytes(aWriter, iter.Data(), iter.RemainingInSegment())) {
|
||||
return false;
|
||||
}
|
||||
iter.Advance(data, iter.RemainingInSegment());
|
||||
}
|
||||
|
||||
return true;
|
||||
return data.ForEachDataChunk([&](const char* aData, size_t aSize) {
|
||||
return JS_WriteBytes(aWriter, aData, aSize);
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -4771,6 +4771,10 @@ nsIDocument::SetContainer(nsDocShell* aContainer)
|
||||
}
|
||||
|
||||
EnumerateActivityObservers(NotifyActivityChanged, nullptr);
|
||||
|
||||
// IsTopLevelWindowInactive depends on the docshell, so
|
||||
// update the cached value now that it's available.
|
||||
UpdateDocumentStates(NS_DOCUMENT_STATE_WINDOW_INACTIVE);
|
||||
if (!aContainer) {
|
||||
return;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
auto iter = Data().Iter();
|
||||
auto iter = Data().Start();
|
||||
size_t size = Data().Size();
|
||||
nsAutoCString binaryData;
|
||||
binaryData.SetLength(size);
|
||||
|
@ -8314,12 +8314,12 @@ class ObjectStoreAddOrPutRequestOp::SCInputStream final
|
||||
: public nsIInputStream
|
||||
{
|
||||
const JSStructuredCloneData& mData;
|
||||
JSStructuredCloneData::IterImpl mIter;
|
||||
JSStructuredCloneData::Iterator mIter;
|
||||
|
||||
public:
|
||||
explicit SCInputStream(const JSStructuredCloneData& aData)
|
||||
: mData(aData)
|
||||
, mIter(aData.Iter())
|
||||
, mIter(aData.Start())
|
||||
{ }
|
||||
|
||||
private:
|
||||
@ -19695,7 +19695,7 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
if (!aInfo->mData.WriteBytes(uncompressedBuffer, uncompressed.Length())) {
|
||||
if (!aInfo->mData.AppendBytes(uncompressedBuffer, uncompressed.Length())) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
@ -19780,7 +19780,7 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
|
||||
break;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!aInfo->mData.WriteBytes(buffer, numRead))) {
|
||||
if (NS_WARN_IF(!aInfo->mData.AppendBytes(buffer, numRead))) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
@ -26181,18 +26181,9 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
||||
char keyPropBuffer[keyPropSize];
|
||||
LittleEndian::writeUint64(keyPropBuffer, keyPropValue);
|
||||
|
||||
auto iter = cloneData.Iter();
|
||||
DebugOnly<bool> result =
|
||||
iter.AdvanceAcrossSegments(cloneData, cloneInfo.offsetToKeyProp());
|
||||
MOZ_ASSERT(result);
|
||||
|
||||
for (char index : keyPropBuffer) {
|
||||
char* keyPropPointer = iter.Data();
|
||||
*keyPropPointer = index;
|
||||
|
||||
result = iter.AdvanceAcrossSegments(cloneData, 1);
|
||||
MOZ_ASSERT(result);
|
||||
}
|
||||
auto iter = cloneData.Start();
|
||||
MOZ_ALWAYS_TRUE(cloneData.Advance(iter, cloneInfo.offsetToKeyProp()));
|
||||
MOZ_ALWAYS_TRUE(cloneData.UpdateBytes(iter, keyPropBuffer, keyPropSize));
|
||||
}
|
||||
}
|
||||
|
||||
@ -26218,7 +26209,7 @@ ObjectStoreAddOrPutRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
|
||||
} else {
|
||||
nsCString flatCloneData;
|
||||
flatCloneData.SetLength(cloneDataSize);
|
||||
auto iter = cloneData.Iter();
|
||||
auto iter = cloneData.Start();
|
||||
cloneData.ReadBytes(iter, flatCloneData.BeginWriting(), cloneDataSize);
|
||||
|
||||
// Compress the bytes before adding into the database.
|
||||
@ -26478,7 +26469,7 @@ SCInputStream::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
*_retval += count;
|
||||
aCount -= count;
|
||||
|
||||
mIter.Advance(mData, count);
|
||||
mData.Advance(mIter, count);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -148,7 +148,7 @@ BuildClonedMessageData(M* aManager, StructuredCloneData& aData,
|
||||
ClonedMessageData& aClonedData)
|
||||
{
|
||||
SerializedStructuredCloneBuffer& buffer = aClonedData.data();
|
||||
auto iter = aData.Data().Iter();
|
||||
auto iter = aData.Data().Start();
|
||||
size_t size = aData.Data().Size();
|
||||
bool success;
|
||||
buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
CreateFromExternalData(const char* aData, size_t aDataLength)
|
||||
{
|
||||
JSStructuredCloneData buf;
|
||||
buf.WriteBytes(aData, aDataLength);
|
||||
buf.AppendBytes(aData, aDataLength);
|
||||
RefPtr<SharedJSAllocatedData> sharedData =
|
||||
new SharedJSAllocatedData(Move(buf));
|
||||
return sharedData.forget();
|
||||
@ -65,11 +65,7 @@ public:
|
||||
CreateFromExternalData(const JSStructuredCloneData& aData)
|
||||
{
|
||||
JSStructuredCloneData buf;
|
||||
auto iter = aData.Iter();
|
||||
while (!iter.Done()) {
|
||||
buf.WriteBytes(iter.Data(), iter.RemainingInSegment());
|
||||
iter.Advance(aData, iter.RemainingInSegment());
|
||||
}
|
||||
buf.Append(aData);
|
||||
RefPtr<SharedJSAllocatedData> sharedData =
|
||||
new SharedJSAllocatedData(Move(buf));
|
||||
return sharedData.forget();
|
||||
@ -238,7 +234,7 @@ public:
|
||||
// StructuredCloneData instance is destroyed before aData is destroyed.
|
||||
bool UseExternalData(const JSStructuredCloneData& aData)
|
||||
{
|
||||
auto iter = aData.Iter();
|
||||
auto iter = aData.Start();
|
||||
bool success = false;
|
||||
mExternalData =
|
||||
aData.Borrow<js::SystemAllocPolicy>(iter, aData.Size(), &success);
|
||||
|
@ -1777,7 +1777,7 @@ WorkerPrivate::Start()
|
||||
|
||||
// aCx is null when called from the finalizer
|
||||
bool
|
||||
WorkerPrivate::NotifyPrivate(WorkerStatus aStatus)
|
||||
WorkerPrivate::Notify(WorkerStatus aStatus)
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
|
||||
@ -4345,7 +4345,7 @@ WorkerPrivate::AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget)
|
||||
#endif
|
||||
|
||||
void
|
||||
WorkerPrivate::PostMessageToParentInternal(
|
||||
WorkerPrivate::PostMessageToParent(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
|
@ -158,10 +158,7 @@ public:
|
||||
|
||||
// Called on the parent thread.
|
||||
bool
|
||||
Notify(WorkerStatus aStatus)
|
||||
{
|
||||
return NotifyPrivate(aStatus);
|
||||
}
|
||||
Notify(WorkerStatus aStatus);
|
||||
|
||||
bool
|
||||
Cancel()
|
||||
@ -178,8 +175,7 @@ public:
|
||||
bool
|
||||
Terminate()
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
return TerminatePrivate();
|
||||
return Notify(Terminating);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -291,10 +287,7 @@ public:
|
||||
PostMessageToParent(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
|
||||
}
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
PostMessageToParentMessagePort(JSContext* aCx,
|
||||
@ -1219,15 +1212,6 @@ private:
|
||||
|
||||
~WorkerPrivate();
|
||||
|
||||
bool
|
||||
NotifyPrivate(WorkerStatus aStatus);
|
||||
|
||||
bool
|
||||
TerminatePrivate()
|
||||
{
|
||||
return NotifyPrivate(Terminating);
|
||||
}
|
||||
|
||||
bool
|
||||
MayContinueRunning()
|
||||
{
|
||||
@ -1279,12 +1263,6 @@ private:
|
||||
void
|
||||
WaitForWorkerEvents();
|
||||
|
||||
void
|
||||
PostMessageToParentInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Sequence<JSObject*>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// If the worker shutdown status is equal or greater then aFailStatus, this
|
||||
// operation will fail and nullptr will be returned. See WorkerHolder.h for
|
||||
// more information about the correct value to use.
|
||||
|
@ -78,8 +78,16 @@ static CTFontRef
|
||||
CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize)
|
||||
{
|
||||
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
|
||||
// versions (see bug 1331683)
|
||||
if (!nsCocoaFeatures::OnSierraOrLater()) {
|
||||
// versions (see bug 1331683).
|
||||
//
|
||||
// And on HighSierra, CTFontCreateWithGraphicsFont properly carries over
|
||||
// variation settings from the CGFont to CTFont, so we don't need to do
|
||||
// the extra work here -- and this seems to avoid Core Text crashiness
|
||||
// seen in bug 1454094.
|
||||
//
|
||||
// So we only need to do this "the hard way" on Sierra; on other releases,
|
||||
// just let the standard CTFont function do its thing.
|
||||
if (!nsCocoaFeatures::OnSierraExactly()) {
|
||||
return CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
@ -340,13 +340,23 @@ const cairo_font_face_backend_t _cairo_quartz_font_face_backend = {
|
||||
static CTFontRef
|
||||
CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont, CGFloat aSize)
|
||||
{
|
||||
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
|
||||
// versions (see bug 1331683)
|
||||
// Declare helper provided by widget/cocoa/nsCocoaFeatures.mm
|
||||
extern bool Gecko_OnSierraOrLater();
|
||||
if (!Gecko_OnSierraOrLater()) {
|
||||
extern bool Gecko_OnSierraExactly();
|
||||
|
||||
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
|
||||
// versions (see bug 1331683).
|
||||
//
|
||||
// And on HighSierra, CTFontCreateWithGraphicsFont properly carries over
|
||||
// variation settings from the CGFont to CTFont, so we don't need to do
|
||||
// the extra work here -- and this seems to avoid Core Text crashiness
|
||||
// seen in bug 1454094.
|
||||
//
|
||||
// So we only need to do this "the hard way" on Sierra; on other releases,
|
||||
// just let the standard CTFont function do its thing.
|
||||
if (!Gecko_OnSierraExactly()) {
|
||||
return CTFontCreateWithGraphicsFont(aCGFont, aSize, NULL, NULL);
|
||||
}
|
||||
|
||||
CFDictionaryRef vars = CGFontCopyVariations(aCGFont);
|
||||
CTFontRef ctFont;
|
||||
if (vars) {
|
||||
|
@ -95,7 +95,7 @@ struct BlobItemData
|
||||
float mOpacity; // only used with nsDisplayOpacity items to detect change to opacity
|
||||
|
||||
IntRect mImageRect;
|
||||
IntPoint mGroupOffset;
|
||||
LayerIntPoint mGroupOffset;
|
||||
|
||||
BlobItemData(DIGroup* aGroup, nsDisplayItem *aItem)
|
||||
: mGroup(aGroup)
|
||||
@ -287,7 +287,7 @@ struct DIGroup
|
||||
nsRect mGroupBounds;
|
||||
int32_t mAppUnitsPerDevPixel;
|
||||
gfx::Size mScale;
|
||||
IntPoint mGroupOffset;
|
||||
LayerIntRect mLayerBounds;
|
||||
Maybe<wr::ImageKey> mKey;
|
||||
|
||||
DIGroup() : mAppUnitsPerDevPixel(0) {}
|
||||
@ -316,9 +316,9 @@ struct DIGroup
|
||||
}
|
||||
|
||||
static IntRect
|
||||
ToDeviceSpace(nsRect aBounds, Matrix& aMatrix, int32_t aAppUnitsPerDevPixel, IntPoint aOffset)
|
||||
ToDeviceSpace(nsRect aBounds, Matrix& aMatrix, int32_t aAppUnitsPerDevPixel, LayerIntPoint aOffset)
|
||||
{
|
||||
return RoundedOut(aMatrix.TransformBounds(ToRect(nsLayoutUtils::RectToGfxRect(aBounds, aAppUnitsPerDevPixel)))) - aOffset;
|
||||
return RoundedOut(aMatrix.TransformBounds(ToRect(nsLayoutUtils::RectToGfxRect(aBounds, aAppUnitsPerDevPixel)))) - aOffset.ToUnknownPoint();
|
||||
}
|
||||
|
||||
void ComputeGeometryChange(nsDisplayItem* aItem, BlobItemData* aData, Matrix& aMatrix, nsDisplayListBuilder* aBuilder)
|
||||
@ -340,8 +340,7 @@ struct DIGroup
|
||||
LayoutDeviceIntPoint offset = RoundedToInt(bounds.TopLeft());
|
||||
GP("\n");
|
||||
GP("CGC offset %d %d\n", offset.x, offset.y);
|
||||
IntSize size = mGroupBounds.Size().ScaleToNearestPixels(mScale.width, mScale.height, appUnitsPerDevPixel);
|
||||
//MOZ_RELEASE_ASSERT(mGroupOffset.x == offset.x && mGroupOffset.y == offset.y);
|
||||
LayerIntSize size = mLayerBounds.Size();
|
||||
IntRect imageRect(0, 0, size.width, size.height);
|
||||
GP("imageSize: %d %d\n", size.width, size.height);
|
||||
/*if (aItem->IsReused() && aData->mGeometry) {
|
||||
@ -357,16 +356,16 @@ struct DIGroup
|
||||
aData->mGeometry = Move(geometry);
|
||||
nsRect bounds = combined.GetBounds();
|
||||
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
aData->mRect = transformedRect.Intersect(imageRect);
|
||||
GP("CGC %s %d %d %d %d\n", aItem->Name(), bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
GP("%d %d, %f %f\n", mGroupOffset.x, mGroupOffset.y, aMatrix._11, aMatrix._22);
|
||||
GP("%d %d, %f %f\n", mLayerBounds.TopLeft().x, mLayerBounds.TopLeft().y, aMatrix._11, aMatrix._22);
|
||||
GP("mRect %d %d %d %d\n", aData->mRect.x, aData->mRect.y, aData->mRect.width, aData->mRect.height);
|
||||
InvalidateRect(aData->mRect);
|
||||
aData->mInvalid = true;
|
||||
} else if (/*aData->mIsInvalid || XXX: handle image load invalidation */ (aItem->IsInvalid(invalid) && invalid.IsEmpty())) {
|
||||
MOZ_RELEASE_ASSERT(imageRect.IsEqualEdges(aData->mImageRect));
|
||||
MOZ_RELEASE_ASSERT(mGroupOffset == aData->mGroupOffset);
|
||||
MOZ_RELEASE_ASSERT(mLayerBounds.TopLeft() == aData->mGroupOffset);
|
||||
UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
|
||||
/* Instead of doing this dance, let's just invalidate the old rect and the
|
||||
* new rect.
|
||||
@ -388,7 +387,7 @@ struct DIGroup
|
||||
InvalidateRect(aData->mRect.Intersect(imageRect));
|
||||
// We want to snap to outside pixels. When should we multiply by the matrix?
|
||||
// XXX: TransformBounds is expensive. We should avoid doing it if we have no transform
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
aData->mRect = transformedRect.Intersect(imageRect);
|
||||
InvalidateRect(aData->mRect);
|
||||
GP("new rect: %d %d %d %d\n",
|
||||
@ -399,7 +398,7 @@ struct DIGroup
|
||||
aData->mInvalid = true;
|
||||
} else {
|
||||
MOZ_RELEASE_ASSERT(imageRect.IsEqualEdges(aData->mImageRect));
|
||||
MOZ_RELEASE_ASSERT(mGroupOffset == aData->mGroupOffset);
|
||||
MOZ_RELEASE_ASSERT(mLayerBounds.TopLeft() == aData->mGroupOffset);
|
||||
GP("else invalidate: %s\n", aItem->Name());
|
||||
aData->mGeometry->MoveBy(shift);
|
||||
// this includes situations like reflow changing the position
|
||||
@ -413,7 +412,7 @@ struct DIGroup
|
||||
geometry ? geometry->ComputeInvalidationRegion() :
|
||||
aData->mGeometry->ComputeInvalidationRegion(),
|
||||
&combined);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
IntRect invalidRect = transformedRect.Intersect(imageRect);
|
||||
GP("combined not empty: mRect %d %d %d %d\n", invalidRect.x, invalidRect.y, invalidRect.width, invalidRect.height);
|
||||
// invalidate the invalidated area.
|
||||
@ -422,7 +421,7 @@ struct DIGroup
|
||||
aData->mGeometry = Move(geometry);
|
||||
|
||||
combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
|
||||
transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
aData->mRect = transformedRect.Intersect(imageRect);
|
||||
|
||||
aData->mInvalid = true;
|
||||
@ -438,7 +437,7 @@ struct DIGroup
|
||||
aData->mGeometry = Move(geometry);
|
||||
}
|
||||
combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
InvalidateRect(aData->mRect.Intersect(imageRect));
|
||||
aData->mRect = transformedRect.Intersect(imageRect);
|
||||
InvalidateRect(aData->mRect);
|
||||
@ -462,7 +461,7 @@ struct DIGroup
|
||||
aData->mGeometry = Move(geometry);
|
||||
}
|
||||
combined = clip.ApplyNonRoundedIntersection(aData->mGeometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
InvalidateRect(aData->mRect.Intersect(imageRect));
|
||||
aData->mRect = transformedRect.Intersect(imageRect);
|
||||
InvalidateRect(aData->mRect);
|
||||
@ -476,7 +475,7 @@ struct DIGroup
|
||||
UpdateContainerLayerPropertiesAndDetectChange(aItem, aData)) {
|
||||
combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
|
||||
aData->mGeometry = Move(geometry);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
InvalidateRect(aData->mRect.Intersect(imageRect));
|
||||
aData->mRect = transformedRect.Intersect(imageRect);
|
||||
InvalidateRect(aData->mRect);
|
||||
@ -484,7 +483,7 @@ struct DIGroup
|
||||
} else {
|
||||
// XXX: this code can eventually be deleted/made debug only
|
||||
combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
auto rect = transformedRect.Intersect(imageRect);
|
||||
MOZ_RELEASE_ASSERT(rect.IsEqualEdges(aData->mRect));
|
||||
GP("Layer NoChange: %s %d %d %d %d\n", aItem->Name(),
|
||||
@ -494,7 +493,7 @@ struct DIGroup
|
||||
// XXX: this code can eventually be deleted/made debug only
|
||||
UniquePtr<nsDisplayItemGeometry> geometry(aItem->AllocateGeometry(aBuilder));
|
||||
combined = clip.ApplyNonRoundedIntersection(geometry->ComputeInvalidationRegion());
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mGroupOffset);
|
||||
IntRect transformedRect = ToDeviceSpace(combined.GetBounds(), aMatrix, appUnitsPerDevPixel, mLayerBounds.TopLeft());
|
||||
auto rect = transformedRect.Intersect(imageRect);
|
||||
MOZ_RELEASE_ASSERT(rect.IsEqualEdges(aData->mRect));
|
||||
GP("NoChange: %s %d %d %d %d\n", aItem->Name(),
|
||||
@ -504,7 +503,7 @@ struct DIGroup
|
||||
}
|
||||
aData->mClip = clip;
|
||||
aData->mMatrix = aMatrix;
|
||||
aData->mGroupOffset = mGroupOffset;
|
||||
aData->mGroupOffset = mLayerBounds.TopLeft();
|
||||
aData->mImageRect = imageRect;
|
||||
GP("post mInvalidRect: %d %d %d %d\n", mInvalidRect.x, mInvalidRect.y, mInvalidRect.width, mInvalidRect.height);
|
||||
}
|
||||
@ -632,7 +631,7 @@ struct DIGroup
|
||||
nsDisplayItem* aEndItem,
|
||||
gfxContext* aContext,
|
||||
gfx::DrawEventRecorderMemory* aRecorder) {
|
||||
IntSize size = mGroupBounds.Size().ScaleToNearestPixels(mScale.width, mScale.height, aGrouper->mAppUnitsPerDevPixel);
|
||||
LayerIntSize size = mLayerBounds.Size();
|
||||
for (nsDisplayItem* item = aStartItem; item != aEndItem; item = item->GetAbove()) {
|
||||
IntRect bounds = ItemBounds(item);
|
||||
auto bottomRight = bounds.BottomRight();
|
||||
@ -916,15 +915,17 @@ Grouper::ConstructGroups(WebRenderCommandBuilder* aCommandBuilder,
|
||||
GP("Inner group size change\n");
|
||||
groupData->mFollowingGroup.ClearItems();
|
||||
if (groupData->mFollowingGroup.mKey) {
|
||||
IntSize size = currentGroup->mGroupBounds.Size().ScaleToNearestPixels(currentGroup->mScale.width, currentGroup->mScale.height, mAppUnitsPerDevPixel);
|
||||
groupData->mFollowingGroup.mInvalidRect = IntRect(IntPoint(0, 0), size);
|
||||
LayerIntRect layerBounds = LayerIntRect::FromUnknownRect(currentGroup->mGroupBounds.ScaleToOutsidePixels(currentGroup->mScale.width,
|
||||
currentGroup->mScale.height,
|
||||
mAppUnitsPerDevPixel));
|
||||
groupData->mFollowingGroup.mInvalidRect = IntRect(IntPoint(0, 0), layerBounds.Size().ToUnknownSize());
|
||||
aCommandBuilder->mManager->AddImageKeyForDiscard(groupData->mFollowingGroup.mKey.value());
|
||||
groupData->mFollowingGroup.mKey = Nothing();
|
||||
}
|
||||
}
|
||||
groupData->mFollowingGroup.mGroupBounds = currentGroup->mGroupBounds;
|
||||
groupData->mFollowingGroup.mAppUnitsPerDevPixel = currentGroup->mAppUnitsPerDevPixel;
|
||||
groupData->mFollowingGroup.mGroupOffset = currentGroup->mGroupOffset;
|
||||
groupData->mFollowingGroup.mLayerBounds = currentGroup->mLayerBounds;
|
||||
groupData->mFollowingGroup.mScale = currentGroup->mScale;
|
||||
|
||||
currentGroup = &groupData->mFollowingGroup;
|
||||
@ -1059,7 +1060,7 @@ WebRenderCommandBuilder::DoGroupingForDisplayList(nsDisplayList* aList,
|
||||
group.mAppUnitsPerDevPixel = appUnitsPerDevPixel;
|
||||
group.mGroupBounds = groupBounds;
|
||||
group.mScale = scale;
|
||||
group.mGroupOffset = group.mGroupBounds.TopLeft().ScaleToNearestPixels(scale.width, scale.height, g.mAppUnitsPerDevPixel);
|
||||
group.mLayerBounds = LayerIntRect::FromUnknownRect(group.mGroupBounds.ScaleToOutsidePixels(scale.width, scale.height, group.mAppUnitsPerDevPixel));
|
||||
group.mAnimatedGeometryRootOrigin = group.mGroupBounds.TopLeft();
|
||||
g.ConstructGroups(this, aBuilder, aResources, &group, aList, aSc);
|
||||
mScrollingHelper.EndList(aSc);
|
||||
|
@ -756,7 +756,7 @@ private:
|
||||
// work with non-system fonts. As a result, create the strike specific CTFonts from the underlying
|
||||
// CGFont.
|
||||
#ifdef MOZ_SKIA
|
||||
extern "C" bool Gecko_OnSierraOrLater();
|
||||
extern "C" bool Gecko_OnSierraExactly();
|
||||
#endif
|
||||
static UniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize,
|
||||
const CGAffineTransform* transform)
|
||||
@ -774,8 +774,16 @@ static UniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFlo
|
||||
|
||||
#ifdef MOZ_SKIA
|
||||
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
|
||||
// versions (see bug 1331683)
|
||||
if (Gecko_OnSierraOrLater())
|
||||
// versions (see bug 1331683).
|
||||
//
|
||||
// And on HighSierra, CTFontCreateWithGraphicsFont properly carries over
|
||||
// variation settings from the CGFont to CTFont, so we don't need to do
|
||||
// the extra work here -- and this seems to avoid Core Text crashiness
|
||||
// seen in bug 1454094.
|
||||
//
|
||||
// So we only need to do this "the hard way" on Sierra; on other releases,
|
||||
// just let the standard CTFont function do its thing.
|
||||
if (Gecko_OnSierraExactly())
|
||||
#endif
|
||||
{
|
||||
// Not UniqueCFRef<> because CGFontCopyVariations can return null!
|
||||
|
@ -424,8 +424,16 @@ gfxMacFont::CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont,
|
||||
CTFontDescriptorRef aFontDesc)
|
||||
{
|
||||
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
|
||||
// versions (see bug 1331683)
|
||||
if (!nsCocoaFeatures::OnSierraOrLater()) {
|
||||
// versions (see bug 1331683).
|
||||
//
|
||||
// And on HighSierra, CTFontCreateWithGraphicsFont properly carries over
|
||||
// variation settings from the CGFont to CTFont, so we don't need to do
|
||||
// the extra work here -- and this seems to avoid Core Text crashiness
|
||||
// seen in bug 1454094.
|
||||
//
|
||||
// So we only need to do this "the hard way" on Sierra; on other releases,
|
||||
// just let the standard CTFont function do its thing.
|
||||
if (!nsCocoaFeatures::OnSierraExactly()) {
|
||||
return CTFontCreateWithGraphicsFont(aCGFont, aSize, nullptr, aFontDesc);
|
||||
}
|
||||
|
||||
|
@ -78,11 +78,7 @@ struct SerializedStructuredCloneBuffer final
|
||||
operator=(const SerializedStructuredCloneBuffer& aOther)
|
||||
{
|
||||
data.Clear();
|
||||
auto iter = aOther.data.Iter();
|
||||
while (!iter.Done()) {
|
||||
data.WriteBytes(iter.Data(), iter.RemainingInSegment());
|
||||
iter.Advance(aOther.data, iter.RemainingInSegment());
|
||||
}
|
||||
data.Append(aOther.data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -837,11 +833,9 @@ struct ParamTraits<JSStructuredCloneData>
|
||||
{
|
||||
MOZ_ASSERT(!(aParam.Size() % sizeof(uint64_t)));
|
||||
WriteParam(aMsg, aParam.Size());
|
||||
auto iter = aParam.Iter();
|
||||
while (!iter.Done()) {
|
||||
aMsg->WriteBytes(iter.Data(), iter.RemainingInSegment(), sizeof(uint64_t));
|
||||
iter.Advance(aParam, iter.RemainingInSegment());
|
||||
}
|
||||
aParam.ForEachDataChunk([&](const char* aData, size_t aSize) {
|
||||
return aMsg->WriteBytes(aData, aSize, sizeof(uint64_t));
|
||||
});
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/BufferList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -339,52 +340,138 @@ namespace js
|
||||
private:
|
||||
js::Vector<js::SharedArrayRawBuffer*, 0, js::SystemAllocPolicy> refs_;
|
||||
};
|
||||
|
||||
template <typename T, typename AllocPolicy> struct BufferIterator;
|
||||
}
|
||||
|
||||
class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) :
|
||||
public mozilla::BufferList<js::SystemAllocPolicy>
|
||||
{
|
||||
typedef js::SystemAllocPolicy AllocPolicy;
|
||||
typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
|
||||
/**
|
||||
* JSStructuredCloneData represents structured clone data together with the
|
||||
* information needed to read/write/transfer/free the records within it, in the
|
||||
* form of a set of callbacks.
|
||||
*/
|
||||
class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) {
|
||||
public:
|
||||
using BufferList = mozilla::BufferList<js::SystemAllocPolicy>;
|
||||
using Iterator = BufferList::IterImpl;
|
||||
|
||||
static const size_t kInitialSize = 0;
|
||||
static const size_t kInitialCapacity = 4096;
|
||||
private:
|
||||
static const size_t kStandardCapacity = 4096;
|
||||
|
||||
BufferList bufList_;
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks_ = nullptr;
|
||||
void* closure_ = nullptr;
|
||||
OwnTransferablePolicy ownTransferables_ = OwnTransferablePolicy::NoTransferables;
|
||||
js::SharedArrayRawBufferRefs refsHeld_;
|
||||
|
||||
void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure,
|
||||
OwnTransferablePolicy policy) {
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = policy;
|
||||
}
|
||||
|
||||
friend struct JSStructuredCloneWriter;
|
||||
friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
|
||||
template <typename T, typename AllocPolicy> friend struct js::BufferIterator;
|
||||
|
||||
public:
|
||||
explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy())
|
||||
: BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP)
|
||||
public:
|
||||
// The constructor must be infallible but SystemAllocPolicy is not, so both
|
||||
// the initial size and initial capacity of the BufferList must be zero.
|
||||
explicit JSStructuredCloneData()
|
||||
: bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy())
|
||||
, callbacks_(nullptr)
|
||||
, closure_(nullptr)
|
||||
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
|
||||
{}
|
||||
MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
|
||||
: BufferList(Move(buffers))
|
||||
: bufList_(mozilla::Move(buffers))
|
||||
, callbacks_(nullptr)
|
||||
, closure_(nullptr)
|
||||
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
|
||||
{}
|
||||
JSStructuredCloneData(JSStructuredCloneData&& other) = default;
|
||||
JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
|
||||
~JSStructuredCloneData();
|
||||
~JSStructuredCloneData() { discardTransferables(); }
|
||||
|
||||
using BufferList::BufferList;
|
||||
void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure,
|
||||
OwnTransferablePolicy policy)
|
||||
{
|
||||
callbacks_ = callbacks;
|
||||
closure_ = closure;
|
||||
ownTransferables_ = policy;
|
||||
}
|
||||
|
||||
bool Init(size_t initialCapacity = 0) { return bufList_.Init(0, initialCapacity); }
|
||||
|
||||
size_t Size() const { return bufList_.Size(); }
|
||||
|
||||
const Iterator Start() const { return bufList_.Iter(); }
|
||||
|
||||
bool Advance(Iterator& iter, size_t distance) const {
|
||||
return iter.AdvanceAcrossSegments(bufList_, distance);
|
||||
}
|
||||
|
||||
bool ReadBytes(Iterator& iter, char* buffer, size_t size) const {
|
||||
return bufList_.ReadBytes(iter, buffer, size);
|
||||
}
|
||||
|
||||
// Append new data to the end of the buffer.
|
||||
bool AppendBytes(const char* data, size_t size) {
|
||||
return bufList_.WriteBytes(data, size);
|
||||
}
|
||||
|
||||
// Update data stored within the existing buffer. There must be at least
|
||||
// 'size' bytes between the position of 'iter' and the end of the buffer.
|
||||
bool UpdateBytes(Iterator& iter, const char* data, size_t size) const {
|
||||
while (size > 0) {
|
||||
size_t remaining = iter.RemainingInSegment();
|
||||
size_t nbytes = std::min(remaining, size);
|
||||
memcpy(iter.Data(), data, nbytes);
|
||||
data += nbytes;
|
||||
size -= nbytes;
|
||||
iter.Advance(bufList_, nbytes);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
char* AllocateBytes(size_t maxSize, size_t* size) {
|
||||
return bufList_.AllocateBytes(maxSize, size);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
discardTransferables();
|
||||
bufList_.Clear();
|
||||
}
|
||||
|
||||
template<typename BorrowingAllocPolicy>
|
||||
mozilla::BufferList<BorrowingAllocPolicy> Borrow(Iterator& iter, size_t size, bool* success,
|
||||
BorrowingAllocPolicy ap = BorrowingAllocPolicy()) const
|
||||
{
|
||||
return bufList_.Borrow<BorrowingAllocPolicy>(iter, size, success);
|
||||
}
|
||||
|
||||
// Iterate over all contained data, one BufferList segment's worth at a
|
||||
// time, and invoke the given FunctionToApply with the data pointer and
|
||||
// size. The function should return a bool value, and this loop will exit
|
||||
// with false if the function ever returns false.
|
||||
template <typename FunctionToApply>
|
||||
bool ForEachDataChunk(FunctionToApply&& function) const {
|
||||
Iterator iter = bufList_.Iter();
|
||||
while (!iter.Done()) {
|
||||
if (!function(iter.Data(), iter.RemainingInSegment()))
|
||||
return false;
|
||||
iter.Advance(bufList_, iter.RemainingInSegment());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append the entire contents of other's bufList_ to our own.
|
||||
bool Append(const JSStructuredCloneData& other) {
|
||||
return other.ForEachDataChunk([&](const char* data, size_t size) {
|
||||
return AppendBytes(data, size);
|
||||
});
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) {
|
||||
return bufList_.SizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
void discardTransferables();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -420,7 +507,18 @@ JS_PUBLIC_API(bool)
|
||||
JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
|
||||
|
||||
/** RAII sugar for JS_WriteStructuredClone. */
|
||||
/**
|
||||
* The C-style API calls to read and write structured clones are fragile --
|
||||
* they rely on the caller to properly handle ownership of the clone data, and
|
||||
* the handling of the input data as well as the interpretation of the contents
|
||||
* of the clone buffer are dependent on the callbacks passed in. If you
|
||||
* serialize and deserialize with different callbacks, the results are
|
||||
* questionable.
|
||||
*
|
||||
* JSAutoStructuredCloneBuffer wraps things up in an RAII class for data
|
||||
* management, and uses the same callbacks for both writing and reading
|
||||
* (serializing and deserializing).
|
||||
*/
|
||||
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
const JS::StructuredCloneScope scope_;
|
||||
JSStructuredCloneData data_;
|
||||
@ -431,7 +529,7 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
const JSStructuredCloneCallbacks* callbacks, void* closure)
|
||||
: scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
|
||||
{
|
||||
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
|
||||
data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
|
||||
}
|
||||
|
||||
JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
|
||||
@ -442,12 +540,7 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
JSStructuredCloneData& data() { return data_; }
|
||||
bool empty() const { return !data_.Size(); }
|
||||
|
||||
void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
|
||||
|
||||
/** Copy some memory. It will be automatically freed by the destructor. */
|
||||
bool copy(JSContext* cx, const JSStructuredCloneData& data,
|
||||
uint32_t version=JS_STRUCTURED_CLONE_VERSION,
|
||||
const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Adopt some memory. It will be automatically freed by the destructor.
|
||||
|
@ -28,6 +28,8 @@ name = "typedarray"
|
||||
[[test]]
|
||||
name = "stack_limit"
|
||||
[[test]]
|
||||
name = "value"
|
||||
[[test]]
|
||||
name = "vec_conversion"
|
||||
|
||||
[lib]
|
||||
|
@ -887,12 +887,10 @@ GetLengthOfJSStructuredCloneData(JSStructuredCloneData* data)
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
auto iter = data->Iter();
|
||||
while (!iter.Done()) {
|
||||
size_t len_of_this_segment = iter.RemainingInSegment();
|
||||
len += len_of_this_segment;
|
||||
iter.Advance(*data, len_of_this_segment);
|
||||
}
|
||||
data->ForEachDataChunk([&](const char* bytes, size_t size) {
|
||||
len += size;
|
||||
return true;
|
||||
});
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -905,13 +903,11 @@ CopyJSStructuredCloneData(JSStructuredCloneData* src, uint8_t* dest)
|
||||
|
||||
size_t bytes_copied = 0;
|
||||
|
||||
auto iter = src->Iter();
|
||||
while (!iter.Done()) {
|
||||
size_t len_of_this_segment = iter.RemainingInSegment();
|
||||
memcpy(dest + bytes_copied, iter.Data(), len_of_this_segment);
|
||||
bytes_copied += len_of_this_segment;
|
||||
iter.Advance(*src, len_of_this_segment);
|
||||
}
|
||||
src->ForEachDataChunk([&](const char* bytes, size_t size) {
|
||||
memcpy(dest, bytes, size);
|
||||
dest += size;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
bool
|
||||
@ -920,7 +916,7 @@ WriteBytesToJSStructuredCloneData(const uint8_t* src, size_t len, JSStructuredCl
|
||||
assert(src != nullptr);
|
||||
assert(dest != nullptr);
|
||||
|
||||
return dest->WriteBytes(reinterpret_cast<const char*>(src), len);
|
||||
return dest->AppendBytes(reinterpret_cast<const char*>(src), len);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
@ -351,7 +351,7 @@ impl JS::Value {
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub fn is_symbol(&self) -> bool {
|
||||
unsafe {
|
||||
self.asBits() == ValueShiftedTag::SYMBOL as u64
|
||||
(self.asBits() >> JSVAL_TAG_SHIFT) == ValueTag::SYMBOL as u64
|
||||
}
|
||||
}
|
||||
|
||||
|
50
js/rust/tests/value.rs
Normal file
50
js/rust/tests/value.rs
Normal file
@ -0,0 +1,50 @@
|
||||
/* 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/. */
|
||||
|
||||
#[macro_use]
|
||||
extern crate js;
|
||||
|
||||
use js::jsapi::root::JS::CompartmentOptions;
|
||||
use js::jsapi::root::JS_NewGlobalObject;
|
||||
use js::jsapi::root::JS::OnNewGlobalHookOption;
|
||||
use js::jsval::UndefinedValue;
|
||||
use js::rust::{Runtime, SIMPLE_GLOBAL_CLASS};
|
||||
|
||||
use std::ptr;
|
||||
|
||||
#[test]
|
||||
fn is_symbol() {
|
||||
let rt = Runtime::new(false).unwrap();
|
||||
let cx = rt.cx();
|
||||
|
||||
unsafe {
|
||||
rooted!(in(cx) let global =
|
||||
JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
|
||||
OnNewGlobalHookOption::FireOnNewGlobalHook,
|
||||
&CompartmentOptions::default())
|
||||
);
|
||||
rooted!(in(cx) let mut rval = UndefinedValue());
|
||||
assert!(rt.evaluate_script(global.handle(), "Symbol('test')",
|
||||
"test", 1, rval.handle_mut()).is_ok());
|
||||
assert!(rval.is_symbol());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_symbol() {
|
||||
let rt = Runtime::new(false).unwrap();
|
||||
let cx = rt.cx();
|
||||
|
||||
unsafe {
|
||||
rooted!(in(cx) let global =
|
||||
JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
|
||||
OnNewGlobalHookOption::FireOnNewGlobalHook,
|
||||
&CompartmentOptions::default())
|
||||
);
|
||||
rooted!(in(cx) let mut rval = UndefinedValue());
|
||||
assert!(rt.evaluate_script(global.handle(), "'not a symbol'",
|
||||
"test", 1, rval.handle_mut()).is_ok());
|
||||
assert!(!rval.is_symbol());
|
||||
}
|
||||
}
|
@ -2833,13 +2833,13 @@ class CloneBufferObject : public NativeObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto buf = js::MakeUnique<JSStructuredCloneData>(0, 0, nbytes);
|
||||
if (!buf || !buf->Init(nbytes, nbytes)) {
|
||||
auto buf = js::MakeUnique<JSStructuredCloneData>();
|
||||
if (!buf || !buf->Init(nbytes)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
js_memcpy(buf->Start(), data, nbytes);
|
||||
MOZ_ALWAYS_TRUE(buf->AppendBytes((const char*)data, nbytes));
|
||||
obj->discard();
|
||||
obj->setData(buf.release(), true);
|
||||
|
||||
@ -2893,7 +2893,7 @@ class CloneBufferObject : public NativeObject {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
auto iter = data->Iter();
|
||||
auto iter = data->Start();
|
||||
data->ReadBytes(iter, buffer.get(), size);
|
||||
JSString* str = JS_NewStringCopyN(cx, buffer.get(), size);
|
||||
if (!str)
|
||||
@ -2923,7 +2923,7 @@ class CloneBufferObject : public NativeObject {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
auto iter = data->Iter();
|
||||
auto iter = data->Start();
|
||||
data->ReadBytes(iter, buffer.get(), size);
|
||||
JSObject* arrayBuffer = JS_NewArrayBufferWithContents(cx, size, buffer.release());
|
||||
if (!arrayBuffer)
|
||||
@ -3098,9 +3098,7 @@ Deserialize(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!JS_StructuredCloneHasTransferables(*obj->data(), &hasTransferable))
|
||||
return false;
|
||||
|
||||
if (obj->isSynthetic() &&
|
||||
(scope != JS::StructuredCloneScope::DifferentProcess || hasTransferable))
|
||||
{
|
||||
if (obj->isSynthetic() && scope != JS::StructuredCloneScope::DifferentProcess) {
|
||||
JS_ReportErrorASCII(cx, "clone buffer data is synthetic but may contain pointers");
|
||||
return false;
|
||||
}
|
||||
|
@ -934,7 +934,7 @@ MaybeUnwrapArrayWrapper(JSObject* obj)
|
||||
}
|
||||
|
||||
static MOZ_ALWAYS_INLINE JSString*
|
||||
NewUCString(JSContext* cx, const AutoString& from)
|
||||
NewUCString(JSContext* cx, const AutoStringChars&& from)
|
||||
{
|
||||
return JS_NewUCStringCopyN(cx, from.begin(), from.length());
|
||||
}
|
||||
@ -982,7 +982,7 @@ GetErrorMessage(void* userRef, const unsigned errorNumber)
|
||||
static const char*
|
||||
EncodeLatin1(JSContext* cx, AutoString& str, JSAutoByteString& bytes)
|
||||
{
|
||||
return bytes.encodeLatin1(cx, NewUCString(cx, str));
|
||||
return bytes.encodeLatin1(cx, NewUCString(cx, str.finish()));
|
||||
}
|
||||
|
||||
static const char*
|
||||
@ -1014,12 +1014,12 @@ BuildCStyleTypeSource(JSContext* cx, JSObject* typeObj_, AutoString& source)
|
||||
switch (CType::GetTypeCode(typeObj)) {
|
||||
#define BUILD_SOURCE(name, fromType, ffiType) \
|
||||
case TYPE_##name: \
|
||||
AppendString(source, #name); \
|
||||
AppendString(cx, source, #name); \
|
||||
break;
|
||||
CTYPES_FOR_EACH_TYPE(BUILD_SOURCE)
|
||||
#undef BUILD_SOURCE
|
||||
case TYPE_void_t:
|
||||
AppendString(source, "void");
|
||||
AppendString(cx, source, "void");
|
||||
break;
|
||||
case TYPE_pointer: {
|
||||
unsigned ptrCount = 0;
|
||||
@ -1041,8 +1041,8 @@ BuildCStyleTypeSource(JSContext* cx, JSObject* typeObj_, AutoString& source)
|
||||
}
|
||||
case TYPE_struct: {
|
||||
RootedString name(cx, CType::GetName(cx, typeObj));
|
||||
AppendString(source, "struct ");
|
||||
AppendString(source, name);
|
||||
AppendString(cx, source, "struct ");
|
||||
AppendString(cx, source, name);
|
||||
break;
|
||||
}
|
||||
case TYPE_function:
|
||||
@ -1062,28 +1062,28 @@ BuildCStyleFunctionTypeSource(JSContext* cx, HandleObject typeObj,
|
||||
|
||||
FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
|
||||
BuildCStyleTypeSource(cx, fninfo->mReturnType, source);
|
||||
AppendString(source, " ");
|
||||
AppendString(cx, source, " ");
|
||||
if (nameStr) {
|
||||
MOZ_ASSERT(ptrCount == 0);
|
||||
AppendString(source, nameStr);
|
||||
AppendString(cx, source, nameStr);
|
||||
} else if (ptrCount) {
|
||||
AppendString(source, "(");
|
||||
AppendString(cx, source, "(");
|
||||
AppendChars(source, '*', ptrCount);
|
||||
AppendString(source, ")");
|
||||
AppendString(cx, source, ")");
|
||||
}
|
||||
AppendString(source, "(");
|
||||
AppendString(cx, source, "(");
|
||||
if (fninfo->mArgTypes.length() > 0) {
|
||||
for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
|
||||
BuildCStyleTypeSource(cx, fninfo->mArgTypes[i], source);
|
||||
if (i != fninfo->mArgTypes.length() - 1 || fninfo->mIsVariadic) {
|
||||
AppendString(source, ", ");
|
||||
AppendString(cx, source, ", ");
|
||||
}
|
||||
}
|
||||
if (fninfo->mIsVariadic) {
|
||||
AppendString(source, "...");
|
||||
AppendString(cx, source, "...");
|
||||
}
|
||||
}
|
||||
AppendString(source, ")");
|
||||
AppendString(cx, source, ")");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1108,10 +1108,10 @@ BuildFunctionTypeSource(JSContext* cx, HandleObject funObj, AutoString& source)
|
||||
RootedString funcStr(cx, JS_ValueToSource(cx, funVal));
|
||||
if (!funcStr) {
|
||||
JS_ClearPendingException(cx);
|
||||
AppendString(source, "<<error converting function to string>>");
|
||||
AppendString(cx, source, "<<error converting function to string>>");
|
||||
return;
|
||||
}
|
||||
AppendString(source, funcStr);
|
||||
AppendString(cx, source, funcStr);
|
||||
}
|
||||
|
||||
enum class ConversionType {
|
||||
@ -1131,22 +1131,22 @@ BuildConversionPosition(JSContext* cx, ConversionType convType,
|
||||
case ConversionType::Argument: {
|
||||
MOZ_ASSERT(funObj);
|
||||
|
||||
AppendString(source, " at argument ");
|
||||
AppendString(cx, source, " at argument ");
|
||||
AppendUInt(source, argIndex + 1);
|
||||
AppendString(source, " of ");
|
||||
AppendString(cx, source, " of ");
|
||||
BuildFunctionTypeSource(cx, funObj, source);
|
||||
break;
|
||||
}
|
||||
case ConversionType::Finalizer:
|
||||
MOZ_ASSERT(funObj);
|
||||
|
||||
AppendString(source, " at argument 1 of ");
|
||||
AppendString(cx, source, " at argument 1 of ");
|
||||
BuildFunctionTypeSource(cx, funObj, source);
|
||||
break;
|
||||
case ConversionType::Return:
|
||||
MOZ_ASSERT(funObj);
|
||||
|
||||
AppendString(source, " at the return value of ");
|
||||
AppendString(cx, source, " at the return value of ");
|
||||
BuildFunctionTypeSource(cx, funObj, source);
|
||||
break;
|
||||
default:
|
||||
@ -1195,6 +1195,8 @@ ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
|
||||
AutoString arrSource;
|
||||
JSAutoByteString arrBytes;
|
||||
BuildTypeSource(cx, arrObj, true, arrSource);
|
||||
if (!arrSource)
|
||||
return false;
|
||||
const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
|
||||
if (!arrStr)
|
||||
return false;
|
||||
@ -1215,6 +1217,8 @@ ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
|
||||
AutoString structSource;
|
||||
JSAutoByteString structBytes;
|
||||
BuildTypeSource(cx, arrObj, true, structSource);
|
||||
if (!structSource)
|
||||
return false;
|
||||
const char* structStr = EncodeLatin1(cx, structSource, structBytes);
|
||||
if (!structStr)
|
||||
return false;
|
||||
@ -1224,6 +1228,8 @@ ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
|
||||
if (funObj) {
|
||||
AutoString posSource;
|
||||
BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
|
||||
if (!posSource)
|
||||
return false;
|
||||
posStr = EncodeLatin1(cx, posSource, posBytes);
|
||||
if (!posStr)
|
||||
return false;
|
||||
@ -1252,6 +1258,8 @@ ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
|
||||
AutoString funSource;
|
||||
JSAutoByteString funBytes;
|
||||
BuildFunctionTypeSource(cx, funObj, funSource);
|
||||
if (!funSource)
|
||||
return false;
|
||||
const char* funStr = EncodeLatin1(cx, funSource, funBytes);
|
||||
if (!funStr)
|
||||
return false;
|
||||
@ -1267,6 +1275,8 @@ ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
|
||||
AutoString funSource;
|
||||
JSAutoByteString funBytes;
|
||||
BuildFunctionTypeSource(cx, funObj, funSource);
|
||||
if (!funSource)
|
||||
return false;
|
||||
const char* funStr = EncodeLatin1(cx, funSource, funBytes);
|
||||
if (!funStr)
|
||||
return false;
|
||||
@ -1281,6 +1291,8 @@ ConvError(JSContext* cx, const char* expectedStr, HandleValue actual,
|
||||
AutoString funSource;
|
||||
JSAutoByteString funBytes;
|
||||
BuildFunctionTypeSource(cx, funObj, funSource);
|
||||
if (!funSource)
|
||||
return false;
|
||||
const char* funStr = EncodeLatin1(cx, funSource, funBytes);
|
||||
if (!funStr)
|
||||
return false;
|
||||
@ -1312,6 +1324,8 @@ ConvError(JSContext* cx, HandleObject expectedType, HandleValue actual,
|
||||
AutoString expectedSource;
|
||||
JSAutoByteString expectedBytes;
|
||||
BuildTypeSource(cx, expectedType, true, expectedSource);
|
||||
if (!expectedSource)
|
||||
return false;
|
||||
const char* expectedStr = EncodeLatin1(cx, expectedSource, expectedBytes);
|
||||
if (!expectedStr)
|
||||
return false;
|
||||
@ -1366,6 +1380,8 @@ ArrayLengthMismatch(JSContext* cx, unsigned expectedLength, HandleObject arrObj,
|
||||
AutoString arrSource;
|
||||
JSAutoByteString arrBytes;
|
||||
BuildTypeSource(cx, arrObj, true, arrSource);
|
||||
if (!arrSource)
|
||||
return false;
|
||||
const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
|
||||
if (!arrStr)
|
||||
return false;
|
||||
@ -1396,6 +1412,8 @@ ArrayLengthOverflow(JSContext* cx, unsigned expectedLength, HandleObject arrObj,
|
||||
AutoString arrSource;
|
||||
JSAutoByteString arrBytes;
|
||||
BuildTypeSource(cx, arrObj, true, arrSource);
|
||||
if (!arrSource)
|
||||
return false;
|
||||
const char* arrStr = EncodeLatin1(cx, arrSource, arrBytes);
|
||||
if (!arrStr)
|
||||
return false;
|
||||
@ -1461,6 +1479,8 @@ EmptyFinalizerError(JSContext* cx, ConversionType convType,
|
||||
if (funObj) {
|
||||
AutoString posSource;
|
||||
BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
|
||||
if (!posSource)
|
||||
return false;
|
||||
posStr = EncodeLatin1(cx, posSource, posBytes);
|
||||
if (!posStr)
|
||||
return false;
|
||||
@ -1490,6 +1510,8 @@ FieldCountMismatch(JSContext* cx,
|
||||
AutoString structSource;
|
||||
JSAutoByteString structBytes;
|
||||
BuildTypeSource(cx, structObj, true, structSource);
|
||||
if (!structSource)
|
||||
return false;
|
||||
const char* structStr = EncodeLatin1(cx, structSource, structBytes);
|
||||
if (!structStr)
|
||||
return false;
|
||||
@ -1504,6 +1526,8 @@ FieldCountMismatch(JSContext* cx,
|
||||
if (funObj) {
|
||||
AutoString posSource;
|
||||
BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
|
||||
if (!posSource)
|
||||
return false;
|
||||
posStr = EncodeLatin1(cx, posSource, posBytes);
|
||||
if (!posStr)
|
||||
return false;
|
||||
@ -1633,6 +1657,8 @@ FinalizerSizeError(JSContext* cx, HandleObject funObj, HandleValue actual)
|
||||
AutoString funSource;
|
||||
JSAutoByteString funBytes;
|
||||
BuildFunctionTypeSource(cx, funObj, funSource);
|
||||
if (!funSource)
|
||||
return false;
|
||||
const char* funStr = EncodeLatin1(cx, funSource, funBytes);
|
||||
if (!funStr)
|
||||
return false;
|
||||
@ -1656,6 +1682,8 @@ FunctionArgumentLengthMismatch(JSContext* cx,
|
||||
} else {
|
||||
BuildFunctionTypeSource(cx, typeObj, funSource);
|
||||
}
|
||||
if (!funSource)
|
||||
return false;
|
||||
const char* funStr = EncodeLatin1(cx, funSource, funBytes);
|
||||
if (!funStr)
|
||||
return false;
|
||||
@ -1809,6 +1837,8 @@ NonPrimitiveError(JSContext* cx, HandleObject typeObj)
|
||||
AutoString typeSource;
|
||||
JSAutoByteString typeBytes;
|
||||
BuildTypeSource(cx, typeObj, true, typeSource);
|
||||
if (!typeSource)
|
||||
return false;
|
||||
const char* typeStr = EncodeLatin1(cx, typeSource, typeBytes);
|
||||
if (!typeStr)
|
||||
return false;
|
||||
@ -1866,6 +1896,8 @@ PropNameNonStringError(JSContext* cx, HandleId id, HandleValue actual,
|
||||
if (funObj) {
|
||||
AutoString posSource;
|
||||
BuildConversionPosition(cx, convType, funObj, argIndex, posSource);
|
||||
if (!posSource)
|
||||
return false;
|
||||
posStr = EncodeLatin1(cx, posSource, posBytes);
|
||||
if (!posStr)
|
||||
return false;
|
||||
@ -1918,8 +1950,9 @@ UndefinedSizeCastError(JSContext* cx, HandleObject targetTypeObj)
|
||||
AutoString targetTypeSource;
|
||||
JSAutoByteString targetTypeBytes;
|
||||
BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
|
||||
const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource,
|
||||
targetTypeBytes);
|
||||
if (!targetTypeSource)
|
||||
return false;
|
||||
const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource, targetTypeBytes);
|
||||
if (!targetTypeStr)
|
||||
return false;
|
||||
|
||||
@ -1936,16 +1969,18 @@ SizeMismatchCastError(JSContext* cx,
|
||||
AutoString sourceTypeSource;
|
||||
JSAutoByteString sourceTypeBytes;
|
||||
BuildTypeSource(cx, sourceTypeObj, true, sourceTypeSource);
|
||||
const char* sourceTypeStr = EncodeLatin1(cx, sourceTypeSource,
|
||||
sourceTypeBytes);
|
||||
if (!sourceTypeSource)
|
||||
return false;
|
||||
const char* sourceTypeStr = EncodeLatin1(cx, sourceTypeSource, sourceTypeBytes);
|
||||
if (!sourceTypeStr)
|
||||
return false;
|
||||
|
||||
AutoString targetTypeSource;
|
||||
JSAutoByteString targetTypeBytes;
|
||||
BuildTypeSource(cx, targetTypeObj, true, targetTypeSource);
|
||||
const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource,
|
||||
targetTypeBytes);
|
||||
if (!targetTypeSource)
|
||||
return false;
|
||||
const char* targetTypeStr = EncodeLatin1(cx, targetTypeSource, targetTypeBytes);
|
||||
if (!targetTypeStr)
|
||||
return false;
|
||||
|
||||
@ -3192,9 +3227,9 @@ jsvalToPtrExplicit(JSContext* cx, HandleValue val, uintptr_t* result)
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class IntegerType, class CharType, size_t N, class AP>
|
||||
template<class IntegerType, class CharType, size_t N>
|
||||
void
|
||||
IntegerToString(IntegerType i, int radix, mozilla::Vector<CharType, N, AP>& result)
|
||||
IntegerToString(IntegerType i, int radix, StringBuilder<CharType, N>& result)
|
||||
{
|
||||
JS_STATIC_ASSERT(numeric_limits<IntegerType>::is_exact);
|
||||
|
||||
@ -3989,7 +4024,7 @@ BuildTypeName(JSContext* cx, JSObject* typeObj_)
|
||||
switch (currentGrouping) {
|
||||
case TYPE_pointer: {
|
||||
// Pointer types go on the left.
|
||||
PrependString(result, "*");
|
||||
PrependString(cx, result, "*");
|
||||
|
||||
typeObj = PointerType::GetBaseType(typeObj);
|
||||
prevGrouping = currentGrouping;
|
||||
@ -3998,17 +4033,17 @@ BuildTypeName(JSContext* cx, JSObject* typeObj_)
|
||||
case TYPE_array: {
|
||||
if (prevGrouping == TYPE_pointer) {
|
||||
// Outer type is pointer, inner type is array. Grouping is required.
|
||||
PrependString(result, "(");
|
||||
AppendString(result, ")");
|
||||
PrependString(cx, result, "(");
|
||||
AppendString(cx, result, ")");
|
||||
}
|
||||
|
||||
// Array types go on the right.
|
||||
AppendString(result, "[");
|
||||
AppendString(cx, result, "[");
|
||||
size_t length;
|
||||
if (ArrayType::GetSafeLength(typeObj, &length))
|
||||
IntegerToString(length, 10, result);
|
||||
|
||||
AppendString(result, "]");
|
||||
AppendString(cx, result, "]");
|
||||
|
||||
typeObj = ArrayType::GetBaseType(typeObj);
|
||||
prevGrouping = currentGrouping;
|
||||
@ -4024,34 +4059,34 @@ BuildTypeName(JSContext* cx, JSObject* typeObj_)
|
||||
// can't return functions.
|
||||
ABICode abi = GetABICode(fninfo->mABI);
|
||||
if (abi == ABI_STDCALL)
|
||||
PrependString(result, "__stdcall");
|
||||
PrependString(cx, result, "__stdcall");
|
||||
else if (abi == ABI_THISCALL)
|
||||
PrependString(result, "__thiscall");
|
||||
PrependString(cx, result, "__thiscall");
|
||||
else if (abi == ABI_WINAPI)
|
||||
PrependString(result, "WINAPI");
|
||||
PrependString(cx, result, "WINAPI");
|
||||
|
||||
// Function application binds more tightly than dereferencing, so
|
||||
// wrap pointer types in parens. Functions can't return functions
|
||||
// (only pointers to them), and arrays can't hold functions
|
||||
// (similarly), so we don't need to address those cases.
|
||||
if (prevGrouping == TYPE_pointer) {
|
||||
PrependString(result, "(");
|
||||
AppendString(result, ")");
|
||||
PrependString(cx, result, "(");
|
||||
AppendString(cx, result, ")");
|
||||
}
|
||||
|
||||
// Argument list goes on the right.
|
||||
AppendString(result, "(");
|
||||
AppendString(cx, result, "(");
|
||||
for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
|
||||
RootedObject argType(cx, fninfo->mArgTypes[i]);
|
||||
JSString* argName = CType::GetName(cx, argType);
|
||||
AppendString(result, argName);
|
||||
AppendString(cx, result, argName);
|
||||
if (i != fninfo->mArgTypes.length() - 1 ||
|
||||
fninfo->mIsVariadic)
|
||||
AppendString(result, ", ");
|
||||
AppendString(cx, result, ", ");
|
||||
}
|
||||
if (fninfo->mIsVariadic)
|
||||
AppendString(result, "...");
|
||||
AppendString(result, ")");
|
||||
AppendString(cx, result, "...");
|
||||
AppendString(cx, result, ")");
|
||||
|
||||
// Set 'typeObj' to the return type, and let the loop process it.
|
||||
// 'prevGrouping' doesn't matter here, because functions cannot return
|
||||
@ -4069,12 +4104,14 @@ BuildTypeName(JSContext* cx, JSObject* typeObj_)
|
||||
// If prepending the base type name directly would splice two
|
||||
// identifiers, insert a space.
|
||||
if (IsAsciiAlpha(result[0]) || result[0] == '_')
|
||||
PrependString(result, " ");
|
||||
PrependString(cx, result, " ");
|
||||
|
||||
// Stick the base type and derived type parts together.
|
||||
JSString* baseName = CType::GetName(cx, typeObj);
|
||||
PrependString(result, baseName);
|
||||
return NewUCString(cx, result);
|
||||
PrependString(cx, result, baseName);
|
||||
if (!result)
|
||||
return nullptr;
|
||||
return NewUCString(cx, result.finish());
|
||||
}
|
||||
|
||||
// Given a CType 'typeObj', generate a string 'result' such that 'eval(result)'
|
||||
@ -4082,7 +4119,7 @@ BuildTypeName(JSContext* cx, JSObject* typeObj_)
|
||||
// StructType 't' is bound to an in-scope variable of name 't.name', and use
|
||||
// that variable in place of generating a string to construct the type 't'.
|
||||
// (This means the type comparison function CType::TypesEqual will return true
|
||||
// when comparing the input and output of BuildTypeSource, since struct
|
||||
// when comparing the input and output of AppendTypeSource, since struct
|
||||
// equality is determined by strict JSObject pointer equality.)
|
||||
static void
|
||||
BuildTypeSource(JSContext* cx,
|
||||
@ -4099,9 +4136,9 @@ BuildTypeSource(JSContext* cx,
|
||||
CTYPES_FOR_EACH_TYPE(CASE_FOR_TYPE)
|
||||
#undef CASE_FOR_TYPE
|
||||
{
|
||||
AppendString(result, "ctypes.");
|
||||
AppendString(cx, result, "ctypes.");
|
||||
JSString* nameStr = CType::GetName(cx, typeObj);
|
||||
AppendString(result, nameStr);
|
||||
AppendString(cx, result, nameStr);
|
||||
break;
|
||||
}
|
||||
case TYPE_pointer: {
|
||||
@ -4109,32 +4146,32 @@ BuildTypeSource(JSContext* cx,
|
||||
|
||||
// Specialcase ctypes.voidptr_t.
|
||||
if (CType::GetTypeCode(baseType) == TYPE_void_t) {
|
||||
AppendString(result, "ctypes.voidptr_t");
|
||||
AppendString(cx, result, "ctypes.voidptr_t");
|
||||
break;
|
||||
}
|
||||
|
||||
// Recursively build the source string, and append '.ptr'.
|
||||
BuildTypeSource(cx, baseType, makeShort, result);
|
||||
AppendString(result, ".ptr");
|
||||
AppendString(cx, result, ".ptr");
|
||||
break;
|
||||
}
|
||||
case TYPE_function: {
|
||||
FunctionInfo* fninfo = FunctionType::GetFunctionInfo(typeObj);
|
||||
|
||||
AppendString(result, "ctypes.FunctionType(");
|
||||
AppendString(cx, result, "ctypes.FunctionType(");
|
||||
|
||||
switch (GetABICode(fninfo->mABI)) {
|
||||
case ABI_DEFAULT:
|
||||
AppendString(result, "ctypes.default_abi, ");
|
||||
AppendString(cx, result, "ctypes.default_abi, ");
|
||||
break;
|
||||
case ABI_STDCALL:
|
||||
AppendString(result, "ctypes.stdcall_abi, ");
|
||||
AppendString(cx, result, "ctypes.stdcall_abi, ");
|
||||
break;
|
||||
case ABI_THISCALL:
|
||||
AppendString(result, "ctypes.thiscall_abi, ");
|
||||
AppendString(cx, result, "ctypes.thiscall_abi, ");
|
||||
break;
|
||||
case ABI_WINAPI:
|
||||
AppendString(result, "ctypes.winapi_abi, ");
|
||||
AppendString(cx, result, "ctypes.winapi_abi, ");
|
||||
break;
|
||||
case INVALID_ABI:
|
||||
MOZ_CRASH("invalid abi");
|
||||
@ -4145,19 +4182,19 @@ BuildTypeSource(JSContext* cx,
|
||||
BuildTypeSource(cx, fninfo->mReturnType, true, result);
|
||||
|
||||
if (fninfo->mArgTypes.length() > 0) {
|
||||
AppendString(result, ", [");
|
||||
AppendString(cx, result, ", [");
|
||||
for (size_t i = 0; i < fninfo->mArgTypes.length(); ++i) {
|
||||
BuildTypeSource(cx, fninfo->mArgTypes[i], true, result);
|
||||
if (i != fninfo->mArgTypes.length() - 1 ||
|
||||
fninfo->mIsVariadic)
|
||||
AppendString(result, ", ");
|
||||
AppendString(cx, result, ", ");
|
||||
}
|
||||
if (fninfo->mIsVariadic)
|
||||
AppendString(result, "\"...\"");
|
||||
AppendString(result, "]");
|
||||
AppendString(cx, result, "\"...\"");
|
||||
AppendString(cx, result, "]");
|
||||
}
|
||||
|
||||
AppendString(result, ")");
|
||||
AppendString(cx, result, ")");
|
||||
break;
|
||||
}
|
||||
case TYPE_array: {
|
||||
@ -4166,13 +4203,13 @@ BuildTypeSource(JSContext* cx,
|
||||
// is undefined.
|
||||
JSObject* baseType = ArrayType::GetBaseType(typeObj);
|
||||
BuildTypeSource(cx, baseType, makeShort, result);
|
||||
AppendString(result, ".array(");
|
||||
AppendString(cx, result, ".array(");
|
||||
|
||||
size_t length;
|
||||
if (ArrayType::GetSafeLength(typeObj, &length))
|
||||
IntegerToString(length, 10, result);
|
||||
|
||||
AppendString(result, ")");
|
||||
AppendString(cx, result, ")");
|
||||
break;
|
||||
}
|
||||
case TYPE_struct: {
|
||||
@ -4181,22 +4218,22 @@ BuildTypeSource(JSContext* cx,
|
||||
if (makeShort) {
|
||||
// Shorten the type declaration by assuming that StructType 't' is bound
|
||||
// to an in-scope variable of name 't.name'.
|
||||
AppendString(result, name);
|
||||
AppendString(cx, result, name);
|
||||
break;
|
||||
}
|
||||
|
||||
// Write the full struct declaration.
|
||||
AppendString(result, "ctypes.StructType(\"");
|
||||
AppendString(result, name);
|
||||
AppendString(result, "\"");
|
||||
AppendString(cx, result, "ctypes.StructType(\"");
|
||||
AppendString(cx, result, name);
|
||||
AppendString(cx, result, "\"");
|
||||
|
||||
// If it's an opaque struct, we're done.
|
||||
if (!CType::IsSizeDefined(typeObj)) {
|
||||
AppendString(result, ")");
|
||||
AppendString(cx, result, ")");
|
||||
break;
|
||||
}
|
||||
|
||||
AppendString(result, ", [");
|
||||
AppendString(cx, result, ", [");
|
||||
|
||||
const FieldInfoHash* fields = StructType::GetFieldInfo(typeObj);
|
||||
size_t length = fields->count();
|
||||
@ -4209,16 +4246,16 @@ BuildTypeSource(JSContext* cx,
|
||||
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
const FieldInfoHash::Entry* entry = fieldsArray[i];
|
||||
AppendString(result, "{ \"");
|
||||
AppendString(result, entry->key());
|
||||
AppendString(result, "\": ");
|
||||
AppendString(cx, result, "{ \"");
|
||||
AppendString(cx, result, entry->key());
|
||||
AppendString(cx, result, "\": ");
|
||||
BuildTypeSource(cx, entry->value().mType, true, result);
|
||||
AppendString(result, " }");
|
||||
AppendString(cx, result, " }");
|
||||
if (i != length - 1)
|
||||
AppendString(result, ", ");
|
||||
AppendString(cx, result, ", ");
|
||||
}
|
||||
|
||||
AppendString(result, "])");
|
||||
AppendString(cx, result, "])");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -4234,7 +4271,7 @@ BuildTypeSource(JSContext* cx,
|
||||
// resulting string can ImplicitConvert successfully if passed to another data
|
||||
// constructor. (This is important when called recursively, since fields of
|
||||
// structs and arrays are converted with ImplicitConvert.)
|
||||
static bool
|
||||
static MOZ_MUST_USE bool
|
||||
BuildDataSource(JSContext* cx,
|
||||
HandleObject typeObj,
|
||||
void* data,
|
||||
@ -4245,9 +4282,9 @@ BuildDataSource(JSContext* cx,
|
||||
switch (type) {
|
||||
case TYPE_bool:
|
||||
if (*static_cast<bool*>(data))
|
||||
AppendString(result, "true");
|
||||
AppendString(cx, result, "true");
|
||||
else
|
||||
AppendString(result, "false");
|
||||
AppendString(cx, result, "false");
|
||||
break;
|
||||
#define INTEGRAL_CASE(name, type, ffiType) \
|
||||
case TYPE_##name: \
|
||||
@ -4260,12 +4297,12 @@ BuildDataSource(JSContext* cx,
|
||||
case TYPE_##name: \
|
||||
/* Serialize as a wrapped decimal integer. */ \
|
||||
if (!numeric_limits<type>::is_signed) \
|
||||
AppendString(result, "ctypes.UInt64(\""); \
|
||||
AppendString(cx, result, "ctypes.UInt64(\""); \
|
||||
else \
|
||||
AppendString(result, "ctypes.Int64(\""); \
|
||||
AppendString(cx, result, "ctypes.Int64(\""); \
|
||||
\
|
||||
IntegerToString(*static_cast<type*>(data), 10, result); \
|
||||
AppendString(result, "\")"); \
|
||||
AppendString(cx, result, "\")"); \
|
||||
break;
|
||||
CTYPES_FOR_EACH_WRAPPED_INT_TYPE(WRAPPED_INT_CASE)
|
||||
#undef WRAPPED_INT_CASE
|
||||
@ -4302,7 +4339,7 @@ BuildDataSource(JSContext* cx,
|
||||
if (!src)
|
||||
return false;
|
||||
|
||||
AppendString(result, src);
|
||||
AppendString(cx, result, src);
|
||||
break;
|
||||
}
|
||||
case TYPE_pointer:
|
||||
@ -4311,17 +4348,17 @@ BuildDataSource(JSContext* cx,
|
||||
// The result must be able to ImplicitConvert successfully.
|
||||
// Wrap in a type constructor, then serialize for ExplicitConvert.
|
||||
BuildTypeSource(cx, typeObj, true, result);
|
||||
AppendString(result, "(");
|
||||
AppendString(cx, result, "(");
|
||||
}
|
||||
|
||||
// Serialize the pointer value as a wrapped hexadecimal integer.
|
||||
uintptr_t ptr = *static_cast<uintptr_t*>(data);
|
||||
AppendString(result, "ctypes.UInt64(\"0x");
|
||||
AppendString(cx, result, "ctypes.UInt64(\"0x");
|
||||
IntegerToString(ptr, 16, result);
|
||||
AppendString(result, "\")");
|
||||
AppendString(cx, result, "\")");
|
||||
|
||||
if (isImplicit)
|
||||
AppendString(result, ")");
|
||||
AppendString(cx, result, ")");
|
||||
|
||||
break;
|
||||
}
|
||||
@ -4329,7 +4366,7 @@ BuildDataSource(JSContext* cx,
|
||||
// Serialize each element of the array recursively. Each element must
|
||||
// be able to ImplicitConvert successfully.
|
||||
RootedObject baseType(cx, ArrayType::GetBaseType(typeObj));
|
||||
AppendString(result, "[");
|
||||
AppendString(cx, result, "[");
|
||||
|
||||
size_t length = ArrayType::GetLength(typeObj);
|
||||
size_t elementSize = CType::GetSize(baseType);
|
||||
@ -4339,9 +4376,9 @@ BuildDataSource(JSContext* cx,
|
||||
return false;
|
||||
|
||||
if (i + 1 < length)
|
||||
AppendString(result, ", ");
|
||||
AppendString(cx, result, ", ");
|
||||
}
|
||||
AppendString(result, "]");
|
||||
AppendString(cx, result, "]");
|
||||
break;
|
||||
}
|
||||
case TYPE_struct: {
|
||||
@ -4349,7 +4386,7 @@ BuildDataSource(JSContext* cx,
|
||||
// The result must be able to ImplicitConvert successfully.
|
||||
// Serialize the data as an object with properties, rather than
|
||||
// a sequence of arguments to the StructType constructor.
|
||||
AppendString(result, "{");
|
||||
AppendString(cx, result, "{");
|
||||
}
|
||||
|
||||
// Serialize each field of the struct recursively. Each field must
|
||||
@ -4367,9 +4404,9 @@ BuildDataSource(JSContext* cx,
|
||||
const FieldInfoHash::Entry* entry = fieldsArray[i];
|
||||
|
||||
if (isImplicit) {
|
||||
AppendString(result, "\"");
|
||||
AppendString(result, entry->key());
|
||||
AppendString(result, "\": ");
|
||||
AppendString(cx, result, "\"");
|
||||
AppendString(cx, result, entry->key());
|
||||
AppendString(cx, result, "\": ");
|
||||
}
|
||||
|
||||
char* fieldData = static_cast<char*>(data) + entry->value().mOffset;
|
||||
@ -4378,11 +4415,11 @@ BuildDataSource(JSContext* cx,
|
||||
return false;
|
||||
|
||||
if (i + 1 != length)
|
||||
AppendString(result, ", ");
|
||||
AppendString(cx, result, ", ");
|
||||
}
|
||||
|
||||
if (isImplicit)
|
||||
AppendString(result, "}");
|
||||
AppendString(cx, result, "}");
|
||||
|
||||
break;
|
||||
}
|
||||
@ -4997,9 +5034,11 @@ CType::ToString(JSContext* cx, unsigned argc, Value* vp)
|
||||
JSString* result;
|
||||
if (CType::IsCType(obj)) {
|
||||
AutoString type;
|
||||
AppendString(type, "type ");
|
||||
AppendString(type, GetName(cx, obj));
|
||||
result = NewUCString(cx, type);
|
||||
AppendString(cx, type, "type ");
|
||||
AppendString(cx, type, GetName(cx, obj));
|
||||
if (!type)
|
||||
return false;
|
||||
result = NewUCString(cx, type.finish());
|
||||
}
|
||||
else {
|
||||
result = JS_NewStringCopyZ(cx, "[CType proto object]");
|
||||
@ -5029,7 +5068,9 @@ CType::ToSource(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (CType::IsCType(obj)) {
|
||||
AutoString source;
|
||||
BuildTypeSource(cx, obj, false, source);
|
||||
result = NewUCString(cx, source);
|
||||
if (!source)
|
||||
return false;
|
||||
result = NewUCString(cx, source.finish());
|
||||
} else {
|
||||
result = JS_NewStringCopyZ(cx, "[CType proto object]");
|
||||
}
|
||||
@ -6805,7 +6846,8 @@ PrepareCIF(JSContext* cx,
|
||||
}
|
||||
|
||||
void
|
||||
FunctionType::BuildSymbolName(JSString* name,
|
||||
FunctionType::BuildSymbolName(JSContext* cx,
|
||||
JSString* name,
|
||||
JSObject* typeObj,
|
||||
AutoCString& result)
|
||||
{
|
||||
@ -6816,7 +6858,7 @@ FunctionType::BuildSymbolName(JSString* name,
|
||||
case ABI_THISCALL:
|
||||
case ABI_WINAPI:
|
||||
// For cdecl or WINAPI functions, no mangling is necessary.
|
||||
AppendString(result, name);
|
||||
AppendString(cx, result, name);
|
||||
break;
|
||||
|
||||
case ABI_STDCALL: {
|
||||
@ -6825,9 +6867,9 @@ FunctionType::BuildSymbolName(JSString* name,
|
||||
// _foo@40
|
||||
// where 'foo' is the function name, and '40' is the aligned size of the
|
||||
// arguments.
|
||||
AppendString(result, "_");
|
||||
AppendString(result, name);
|
||||
AppendString(result, "@");
|
||||
AppendString(cx, result, "_");
|
||||
AppendString(cx, result, name);
|
||||
AppendString(cx, result, "@");
|
||||
|
||||
// Compute the suffix by aligning each argument to sizeof(ffi_arg).
|
||||
size_t size = 0;
|
||||
@ -6840,7 +6882,7 @@ FunctionType::BuildSymbolName(JSString* name,
|
||||
#elif defined(_WIN64)
|
||||
// On Win64, stdcall is an alias to the default ABI for compatibility, so no
|
||||
// mangling is done.
|
||||
AppendString(result, name);
|
||||
AppendString(cx, result, name);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@ -8059,13 +8101,14 @@ CData::GetSourceString(JSContext* cx, HandleObject typeObj, void* data)
|
||||
// bound to a variable in the current scope.)
|
||||
AutoString source;
|
||||
BuildTypeSource(cx, typeObj, true, source);
|
||||
AppendString(source, "(");
|
||||
AppendString(cx, source, "(");
|
||||
if (!BuildDataSource(cx, typeObj, data, false, source))
|
||||
source.handle(false);
|
||||
AppendString(cx, source, ")");
|
||||
if (!source)
|
||||
return nullptr;
|
||||
|
||||
AppendString(source, ")");
|
||||
|
||||
return NewUCString(cx, source);
|
||||
return NewUCString(cx, source.finish());
|
||||
}
|
||||
|
||||
bool
|
||||
@ -8143,13 +8186,13 @@ CDataFinalizer::Methods::ToSource(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
AutoString source;
|
||||
AppendString(source, "ctypes.CDataFinalizer(");
|
||||
AppendString(cx, source, "ctypes.CDataFinalizer(");
|
||||
JSString* srcValue = CData::GetSourceString(cx, objType, p->cargs);
|
||||
if (!srcValue) {
|
||||
return false;
|
||||
}
|
||||
AppendString(source, srcValue);
|
||||
AppendString(source, ", ");
|
||||
AppendString(cx, source, srcValue);
|
||||
AppendString(cx, source, ", ");
|
||||
Value valCodePtrType = JS_GetReservedSlot(objThis,
|
||||
SLOT_DATAFINALIZER_CODETYPE);
|
||||
if (valCodePtrType.isPrimitive()) {
|
||||
@ -8162,9 +8205,11 @@ CDataFinalizer::Methods::ToSource(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
}
|
||||
|
||||
AppendString(source, srcDispose);
|
||||
AppendString(source, ")");
|
||||
strMessage = NewUCString(cx, source);
|
||||
AppendString(cx, source, srcDispose);
|
||||
AppendString(cx, source, ")");
|
||||
if (!source)
|
||||
return false;
|
||||
strMessage = NewUCString(cx, source.finish());
|
||||
}
|
||||
|
||||
if (!strMessage) {
|
||||
@ -8744,7 +8789,9 @@ Int64Base::ToString(JSContext* cx,
|
||||
IntegerToString(static_cast<int64_t>(GetInt(obj)), radix, intString);
|
||||
}
|
||||
|
||||
JSString* result = NewUCString(cx, intString);
|
||||
if (!intString)
|
||||
return false;
|
||||
JSString* result = NewUCString(cx, intString.finish());
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
@ -8768,15 +8815,17 @@ Int64Base::ToSource(JSContext* cx,
|
||||
// Return a decimal string suitable for constructing the number.
|
||||
AutoString source;
|
||||
if (isUnsigned) {
|
||||
AppendString(source, "ctypes.UInt64(\"");
|
||||
AppendString(cx, source, "ctypes.UInt64(\"");
|
||||
IntegerToString(GetInt(obj), 10, source);
|
||||
} else {
|
||||
AppendString(source, "ctypes.Int64(\"");
|
||||
AppendString(cx, source, "ctypes.Int64(\"");
|
||||
IntegerToString(static_cast<int64_t>(GetInt(obj)), 10, source);
|
||||
}
|
||||
AppendString(source, "\")");
|
||||
AppendString(cx, source, "\")");
|
||||
if (!source)
|
||||
return false;
|
||||
|
||||
JSString* result = NewUCString(cx, source);
|
||||
JSString* result = NewUCString(cx, source.finish());
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
|
@ -26,16 +26,95 @@ namespace ctypes {
|
||||
** Utility classes
|
||||
*******************************************************************************/
|
||||
|
||||
// String and AutoString classes, based on Vector.
|
||||
typedef Vector<char16_t, 0, SystemAllocPolicy> String;
|
||||
typedef Vector<char16_t, 64, SystemAllocPolicy> AutoString;
|
||||
typedef Vector<char, 0, SystemAllocPolicy> CString;
|
||||
typedef Vector<char, 64, SystemAllocPolicy> AutoCString;
|
||||
// CTypes builds a number of strings. StringBuilder allows repeated appending
|
||||
// with a single error check at the end. Only the Vector methods required for
|
||||
// building the string are exposed.
|
||||
|
||||
template <class CharT, size_t N>
|
||||
class StringBuilder {
|
||||
Vector<CharT, N, SystemAllocPolicy> v;
|
||||
|
||||
// Have any (OOM) errors been encountered while constructing this string?
|
||||
bool errored { false };
|
||||
|
||||
#ifdef DEBUG
|
||||
// Have we finished building this string?
|
||||
bool finished { false };
|
||||
|
||||
// Did we check for errors?
|
||||
mutable bool checked { false };
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
explicit operator bool() const {
|
||||
#ifdef DEBUG
|
||||
checked = true;
|
||||
#endif
|
||||
return !errored;
|
||||
}
|
||||
|
||||
// Handle the result of modifying the string, by remembering the persistent
|
||||
// errored status.
|
||||
bool handle(bool result) {
|
||||
MOZ_ASSERT(!finished);
|
||||
if (!result)
|
||||
errored = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool resize(size_t n) {
|
||||
return handle(v.resize(n));
|
||||
}
|
||||
|
||||
CharT& operator[](size_t index) { return v[index]; }
|
||||
const CharT& operator[](size_t index) const { return v[index]; }
|
||||
size_t length() const { return v.length(); }
|
||||
|
||||
template<typename U> MOZ_MUST_USE bool append(U&& u) {
|
||||
return handle(v.append(u));
|
||||
}
|
||||
|
||||
template<typename U> MOZ_MUST_USE bool append(const U* begin, const U* end) {
|
||||
return handle(v.append(begin, end));
|
||||
}
|
||||
|
||||
template<typename U> MOZ_MUST_USE bool append(const U* begin, size_t len) {
|
||||
return handle(v.append(begin, len));
|
||||
}
|
||||
|
||||
CharT* begin() {
|
||||
MOZ_ASSERT(!finished);
|
||||
return v.begin();
|
||||
}
|
||||
|
||||
// finish() produces the results of the string building, and is required as
|
||||
// the last thing before the string contents are used. The StringBuilder must
|
||||
// be checked for errors before calling this, however.
|
||||
Vector<CharT, N, SystemAllocPolicy>&& finish() {
|
||||
MOZ_ASSERT(!errored);
|
||||
MOZ_ASSERT(!finished);
|
||||
MOZ_ASSERT(checked);
|
||||
#ifdef DEBUG
|
||||
finished = true;
|
||||
#endif
|
||||
return mozilla::Move(v);
|
||||
}
|
||||
};
|
||||
|
||||
// Note that these strings do not have any inline storage, because we use move
|
||||
// constructors to pass the data around and inline storage would necessitate
|
||||
// copying.
|
||||
typedef StringBuilder<char16_t, 0> AutoString;
|
||||
typedef StringBuilder<char, 0> AutoCString;
|
||||
|
||||
typedef Vector<char16_t, 0, SystemAllocPolicy> AutoStringChars;
|
||||
typedef Vector<char, 0, SystemAllocPolicy> AutoCStringChars;
|
||||
|
||||
// Convenience functions to append, insert, and compare Strings.
|
||||
template <class T, size_t N, class AP, size_t ArrayLength>
|
||||
template <class T, size_t N, size_t ArrayLength>
|
||||
void
|
||||
AppendString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
|
||||
AppendString(JSContext* cx, StringBuilder<T, N>& v, const char (&array)[ArrayLength])
|
||||
{
|
||||
// Don't include the trailing '\0'.
|
||||
size_t alen = ArrayLength - 1;
|
||||
@ -47,9 +126,9 @@ AppendString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
|
||||
v[i + vlen] = array[i];
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class T, size_t N>
|
||||
void
|
||||
AppendChars(mozilla::Vector<T, N, AP>& v, const char c, size_t count)
|
||||
AppendChars(StringBuilder<T, N>& v, const char c, size_t count)
|
||||
{
|
||||
size_t vlen = v.length();
|
||||
if (!v.resize(vlen + count))
|
||||
@ -59,9 +138,9 @@ AppendChars(mozilla::Vector<T, N, AP>& v, const char c, size_t count)
|
||||
v[i + vlen] = c;
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class T, size_t N>
|
||||
void
|
||||
AppendUInt(mozilla::Vector<T, N, AP>& v, unsigned n)
|
||||
AppendUInt(StringBuilder<T, N>& v, unsigned n)
|
||||
{
|
||||
char array[16];
|
||||
size_t alen = SprintfLiteral(array, "%u", n);
|
||||
@ -75,18 +154,18 @@ AppendUInt(mozilla::Vector<T, N, AP>& v, unsigned n)
|
||||
|
||||
template <class T, size_t N, size_t M, class AP>
|
||||
void
|
||||
AppendString(mozilla::Vector<T, N, AP>& v, mozilla::Vector<T, M, AP>& w)
|
||||
AppendString(JSContext* cx, StringBuilder<T, N>& v, mozilla::Vector<T, M, AP>& w)
|
||||
{
|
||||
if (!v.append(w.begin(), w.length()))
|
||||
return;
|
||||
}
|
||||
|
||||
template <size_t N, class AP>
|
||||
template <size_t N>
|
||||
void
|
||||
AppendString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
|
||||
AppendString(JSContext* cx, StringBuilder<char16_t, N>& v, JSString* str)
|
||||
{
|
||||
MOZ_ASSERT(str);
|
||||
JSLinearString* linear = str->ensureLinear(nullptr);
|
||||
JSLinearString* linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return;
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
@ -99,9 +178,9 @@ AppendString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t N, class AP>
|
||||
template <size_t N>
|
||||
void
|
||||
AppendString(mozilla::Vector<char, N, AP>& v, JSString* str)
|
||||
AppendString(JSContext* cx, StringBuilder<char, N>& v, JSString* str)
|
||||
{
|
||||
MOZ_ASSERT(str);
|
||||
size_t vlen = v.length();
|
||||
@ -109,7 +188,7 @@ AppendString(mozilla::Vector<char, N, AP>& v, JSString* str)
|
||||
if (!v.resize(vlen + alen))
|
||||
return;
|
||||
|
||||
JSLinearString* linear = str->ensureLinear(nullptr);
|
||||
JSLinearString* linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return;
|
||||
|
||||
@ -125,9 +204,9 @@ AppendString(mozilla::Vector<char, N, AP>& v, JSString* str)
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP, size_t ArrayLength>
|
||||
template <class T, size_t N, size_t ArrayLength>
|
||||
void
|
||||
PrependString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
|
||||
PrependString(JSContext* cx, StringBuilder<T, N>& v, const char (&array)[ArrayLength])
|
||||
{
|
||||
// Don't include the trailing '\0'.
|
||||
size_t alen = ArrayLength - 1;
|
||||
@ -143,9 +222,9 @@ PrependString(mozilla::Vector<T, N, AP>& v, const char (&array)[ArrayLength])
|
||||
v[i] = array[i];
|
||||
}
|
||||
|
||||
template <size_t N, class AP>
|
||||
template <size_t N>
|
||||
void
|
||||
PrependString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
|
||||
PrependString(JSContext* cx, StringBuilder<char16_t, N>& v, JSString* str)
|
||||
{
|
||||
MOZ_ASSERT(str);
|
||||
size_t vlen = v.length();
|
||||
@ -153,7 +232,7 @@ PrependString(mozilla::Vector<char16_t, N, AP>& v, JSString* str)
|
||||
if (!v.resize(vlen + alen))
|
||||
return;
|
||||
|
||||
JSLinearString* linear = str->ensureLinear(nullptr);
|
||||
JSLinearString* linear = str->ensureLinear(cx);
|
||||
if (!linear)
|
||||
return;
|
||||
|
||||
@ -502,7 +581,7 @@ namespace FunctionType {
|
||||
JSObject* refObj, PRFuncPtr fnptr, JSObject* result);
|
||||
|
||||
FunctionInfo* GetFunctionInfo(JSObject* obj);
|
||||
void BuildSymbolName(JSString* name, JSObject* typeObj,
|
||||
void BuildSymbolName(JSContext* cx, JSString* name, JSObject* typeObj,
|
||||
AutoCString& result);
|
||||
} // namespace FunctionType
|
||||
|
||||
|
@ -72,12 +72,14 @@ Library::Name(JSContext* cx, unsigned argc, Value* vp)
|
||||
}
|
||||
|
||||
AutoString resultString;
|
||||
AppendString(resultString, DLL_PREFIX);
|
||||
AppendString(resultString, str);
|
||||
AppendString(resultString, DLL_SUFFIX);
|
||||
AppendString(cx, resultString, DLL_PREFIX);
|
||||
AppendString(cx, resultString, str);
|
||||
AppendString(cx, resultString, DLL_SUFFIX);
|
||||
if (!resultString)
|
||||
return false;
|
||||
auto resultStr = resultString.finish();
|
||||
|
||||
JSString* result = JS_NewUCStringCopyN(cx, resultString.begin(),
|
||||
resultString.length());
|
||||
JSString* result = JS_NewUCStringCopyN(cx, resultStr.begin(), resultStr.length());
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
@ -339,11 +341,13 @@ Library::Declare(JSContext* cx, unsigned argc, Value* vp)
|
||||
AutoCString symbol;
|
||||
if (isFunction) {
|
||||
// Build the symbol, with mangling if necessary.
|
||||
FunctionType::BuildSymbolName(nameStr, fnObj, symbol);
|
||||
AppendString(symbol, "\0");
|
||||
FunctionType::BuildSymbolName(cx, nameStr, fnObj, symbol);
|
||||
AppendString(cx, symbol, "\0");
|
||||
if (!symbol)
|
||||
return false;
|
||||
|
||||
// Look up the function symbol.
|
||||
fnptr = PR_FindFunctionSymbol(library, symbol.begin());
|
||||
fnptr = PR_FindFunctionSymbol(library, symbol.finish().begin());
|
||||
if (!fnptr) {
|
||||
JS_ReportErrorASCII(cx, "couldn't find function symbol in library");
|
||||
return false;
|
||||
@ -352,10 +356,12 @@ Library::Declare(JSContext* cx, unsigned argc, Value* vp)
|
||||
|
||||
} else {
|
||||
// 'typeObj' is another data type. Look up the data symbol.
|
||||
AppendString(symbol, nameStr);
|
||||
AppendString(symbol, "\0");
|
||||
AppendString(cx, symbol, nameStr);
|
||||
AppendString(cx, symbol, "\0");
|
||||
if (!symbol)
|
||||
return false;
|
||||
|
||||
data = PR_FindSymbol(library, symbol.begin());
|
||||
data = PR_FindSymbol(library, symbol.finish().begin());
|
||||
if (!data) {
|
||||
JS_ReportErrorASCII(cx, "couldn't find symbol in library");
|
||||
return false;
|
||||
|
@ -39,15 +39,16 @@ testStructuredCloneReaderFuzz(const uint8_t* buf, size_t size) {
|
||||
const size_t kSegmentAlignment = 8;
|
||||
size_t buf_size = JS_ROUNDUP(size, kSegmentAlignment);
|
||||
|
||||
auto clonebuf = MakeUnique<JSStructuredCloneData>(0, 0, buf_size);
|
||||
if (!clonebuf || !clonebuf->Init(buf_size, buf_size)) {
|
||||
auto clonebuf = MakeUnique<JSStructuredCloneData>();
|
||||
if (!clonebuf || !clonebuf->Init(buf_size)) {
|
||||
ReportOutOfMemory(gCx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize with zeros, including padding, then copy buffer
|
||||
memset(clonebuf->Start(), '\0', buf_size);
|
||||
js_memcpy(clonebuf->Start(), buf, size);
|
||||
// Copy buffer then pad with zeroes.
|
||||
clonebuf->AppendBytes((const char*)buf, size);
|
||||
char padding[kSegmentAlignment] = {0};
|
||||
clonebuf->AppendBytes(padding, buf_size - size);
|
||||
|
||||
JS::StructuredCloneScope scope = JS::StructuredCloneScope::DifferentProcess;
|
||||
|
||||
|
@ -1933,12 +1933,21 @@ IonBuilder::inlineStrFromCharCode(CallInfo& callInfo)
|
||||
|
||||
if (getInlineReturnType() != MIRType::String)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.getArg(0)->type() != MIRType::Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MDefinition* codeUnit = callInfo.getArg(0);
|
||||
if (codeUnit->type() != MIRType::Int32) {
|
||||
// MTruncateToInt32 will always bail for objects and symbols, so don't
|
||||
// try to inline String.fromCharCode() for these two value types.
|
||||
if (codeUnit->mightBeType(MIRType::Object) || codeUnit->mightBeType(MIRType::Symbol))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
codeUnit = MTruncateToInt32::New(alloc(), codeUnit);
|
||||
current->add(codeUnit->toInstruction());
|
||||
}
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MFromCharCode* string = MFromCharCode::New(alloc(), callInfo.getArg(0));
|
||||
MFromCharCode* string = MFromCharCode::New(alloc(), codeUnit);
|
||||
current->add(string);
|
||||
current->push(string);
|
||||
return InliningStatus_Inlined;
|
||||
|
@ -1577,6 +1577,8 @@ EqualStringsHelper(JSString* str1, JSString* str2)
|
||||
MOZ_ASSERT(!str2->isAtom());
|
||||
MOZ_ASSERT(str1->length() == str2->length());
|
||||
|
||||
// ensureLinear is intentionally called with a nullptr to avoid OOM
|
||||
// reporting; if it fails, we will continue to the next stub.
|
||||
JSLinearString* str2Linear = str2->ensureLinear(nullptr);
|
||||
if (!str2Linear)
|
||||
return false;
|
||||
|
@ -152,9 +152,12 @@ class MacroAssemblerMIPS : public MacroAssemblerMIPSShared
|
||||
void ma_pop(FloatRegister f);
|
||||
void ma_push(FloatRegister f);
|
||||
|
||||
void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) {
|
||||
void ma_cmp_set(Register dst, Register lhs, ImmWord imm, Condition c) {
|
||||
ma_cmp_set(dst, lhs, Imm32(uint32_t(imm.value)), c);
|
||||
}
|
||||
void ma_cmp_set(Register dst, Register lhs, ImmPtr imm, Condition c) {
|
||||
ma_cmp_set(dst, lhs, ImmWord(uintptr_t(imm.value)), c);
|
||||
}
|
||||
void ma_cmp_set(Register dst, Register lhs, Address addr, Condition c) {
|
||||
MOZ_ASSERT(lhs != ScratchRegister);
|
||||
ma_lw(ScratchRegister, addr);
|
||||
|
@ -6079,13 +6079,6 @@ JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, cha
|
||||
return PutEscapedString(buffer, size, linearStr, quote);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_FileEscapedString(FILE* fp, JSString* str, char quote)
|
||||
{
|
||||
JSLinearString* linearStr = str->ensureLinear(nullptr);
|
||||
return linearStr && FileEscapedString(fp, linearStr, quote);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString*)
|
||||
JS_NewDependentString(JSContext* cx, HandleString str, size_t start, size_t length)
|
||||
{
|
||||
|
@ -4717,9 +4717,6 @@ JS_StringEqualsAscii(JSContext* cx, JSString* str, const char* asciiBytes, bool*
|
||||
extern JS_PUBLIC_API(size_t)
|
||||
JS_PutEscapedString(JSContext* cx, char* buffer, size_t size, JSString* str, char quote);
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_FileEscapedString(FILE* fp, JSString* str, char quote);
|
||||
|
||||
/*
|
||||
* Extracting string characters and length.
|
||||
*
|
||||
|
@ -240,6 +240,7 @@ JSString::equals(const char* s)
|
||||
{
|
||||
JSLinearString* linear = ensureLinear(nullptr);
|
||||
if (!linear) {
|
||||
// This is DEBUG-only code.
|
||||
fprintf(stderr, "OOM in JSString::equals!\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -159,16 +159,16 @@ template<typename T, typename AllocPolicy>
|
||||
struct BufferIterator {
|
||||
typedef mozilla::BufferList<AllocPolicy> BufferList;
|
||||
|
||||
explicit BufferIterator(BufferList& buffer)
|
||||
explicit BufferIterator(const BufferList& buffer)
|
||||
: mBuffer(buffer)
|
||||
, mIter(buffer.Iter())
|
||||
{
|
||||
JS_STATIC_ASSERT(8 % sizeof(T) == 0);
|
||||
}
|
||||
|
||||
BufferIterator(const BufferIterator& other)
|
||||
: mBuffer(other.mBuffer)
|
||||
, mIter(other.mIter)
|
||||
explicit BufferIterator(const JSStructuredCloneData& data)
|
||||
: mBuffer(data.bufList_)
|
||||
, mIter(data.Start())
|
||||
{
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ struct BufferIterator {
|
||||
return mIter.HasRoomFor(sizeof(T));
|
||||
}
|
||||
|
||||
BufferList& mBuffer;
|
||||
const BufferList& mBuffer;
|
||||
typename BufferList::IterImpl mIter;
|
||||
};
|
||||
|
||||
@ -294,9 +294,17 @@ SharedArrayRawBufferRefs::releaseAll()
|
||||
refs_.clear();
|
||||
}
|
||||
|
||||
// SCOutput provides an interface to write raw data -- eg uint64_ts, doubles,
|
||||
// arrays of bytes -- into a structured clone data output stream. It also knows
|
||||
// how to free any transferable data within that stream.
|
||||
//
|
||||
// Note that it contains a full JSStructuredCloneData object, which holds the
|
||||
// callbacks necessary to read/write/transfer/free the data. For the purpose of
|
||||
// this class, only the freeTransfer callback is relevant; the rest of the callbacks
|
||||
// are used by the higher-level JSStructuredCloneWriter interface.
|
||||
struct SCOutput {
|
||||
public:
|
||||
using Iter = BufferIterator<uint64_t, TempAllocPolicy>;
|
||||
using Iter = BufferIterator<uint64_t, SystemAllocPolicy>;
|
||||
|
||||
explicit SCOutput(JSContext* cx);
|
||||
|
||||
@ -313,22 +321,25 @@ struct SCOutput {
|
||||
template <class T>
|
||||
MOZ_MUST_USE bool writeArray(const T* p, size_t nbytes);
|
||||
|
||||
MOZ_MUST_USE bool extractBuffer(JSStructuredCloneData* data);
|
||||
void discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure);
|
||||
void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure,
|
||||
OwnTransferablePolicy policy)
|
||||
{
|
||||
buf.setCallbacks(callbacks, closure, policy);
|
||||
}
|
||||
void extractBuffer(JSStructuredCloneData* data) { *data = Move(buf); }
|
||||
void discardTransferables();
|
||||
|
||||
uint64_t tell() const { return buf.Size(); }
|
||||
uint64_t count() const { return buf.Size() / sizeof(uint64_t); }
|
||||
Iter iter() {
|
||||
return BufferIterator<uint64_t, TempAllocPolicy>(buf);
|
||||
}
|
||||
Iter iter() { return Iter(buf); }
|
||||
|
||||
size_t offset(Iter dest) {
|
||||
return dest - iter();
|
||||
}
|
||||
|
||||
private:
|
||||
JSContext* cx;
|
||||
mozilla::BufferList<TempAllocPolicy> buf;
|
||||
JSStructuredCloneData buf;
|
||||
};
|
||||
|
||||
class SCInput {
|
||||
@ -461,11 +472,13 @@ struct JSStructuredCloneWriter {
|
||||
const Value& tVal)
|
||||
: out(cx), scope(scope), objs(out.context()),
|
||||
counts(out.context()), entries(out.context()),
|
||||
memory(out.context()), callbacks(cb),
|
||||
closure(cbClosure), transferable(out.context(), tVal),
|
||||
memory(out.context()),
|
||||
transferable(out.context(), tVal),
|
||||
transferableObjects(out.context(), GCHashSet<JSObject*>(cx)),
|
||||
cloneDataPolicy(cloneDataPolicy)
|
||||
{}
|
||||
{
|
||||
out.setCallbacks(cb, cbClosure, OwnTransferablePolicy::NoTransferables);
|
||||
}
|
||||
|
||||
~JSStructuredCloneWriter();
|
||||
|
||||
@ -481,16 +494,8 @@ struct JSStructuredCloneWriter {
|
||||
|
||||
SCOutput& output() { return out; }
|
||||
|
||||
bool extractBuffer(JSStructuredCloneData* data) {
|
||||
bool success = out.extractBuffer(data);
|
||||
if (success) {
|
||||
// Move the SharedArrayRawBuf references here, SCOutput::extractBuffer
|
||||
// moves the serialized data.
|
||||
data->refsHeld_.takeOwnership(Move(refsHeld));
|
||||
data->setOptionalCallbacks(callbacks, closure,
|
||||
OwnTransferablePolicy::OwnsTransferablesIfAny);
|
||||
}
|
||||
return success;
|
||||
void extractBuffer(JSStructuredCloneData* newData) {
|
||||
out.extractBuffer(newData);
|
||||
}
|
||||
|
||||
JS::StructuredCloneScope cloneScope() const { return scope; }
|
||||
@ -554,21 +559,12 @@ struct JSStructuredCloneWriter {
|
||||
SystemAllocPolicy>;
|
||||
Rooted<CloneMemory> memory;
|
||||
|
||||
// The user defined callbacks that will be used for cloning.
|
||||
const JSStructuredCloneCallbacks* callbacks;
|
||||
|
||||
// Any value passed to JS_WriteStructuredClone.
|
||||
void* closure;
|
||||
|
||||
// Set of transferable objects
|
||||
RootedValue transferable;
|
||||
Rooted<GCHashSet<JSObject*>> transferableObjects;
|
||||
|
||||
const JS::CloneDataPolicy cloneDataPolicy;
|
||||
|
||||
// SharedArrayRawBuffers whose reference counts we have incremented.
|
||||
SharedArrayRawBufferRefs refsHeld;
|
||||
|
||||
friend bool JS_WriteString(JSStructuredCloneWriter* w, HandleString str);
|
||||
friend bool JS_WriteTypedArray(JSStructuredCloneWriter* w, HandleValue v);
|
||||
friend bool JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj);
|
||||
@ -626,7 +622,12 @@ WriteStructuredClone(JSContext* cx, HandleValue v, JSStructuredCloneData* bufp,
|
||||
const Value& transferable)
|
||||
{
|
||||
JSStructuredCloneWriter w(cx, scope, cloneDataPolicy, cb, cbClosure, transferable);
|
||||
return w.init() && w.write(v) && w.extractBuffer(bufp);
|
||||
if (!w.init())
|
||||
return false;
|
||||
if (!w.write(v))
|
||||
return false;
|
||||
w.extractBuffer(bufp);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -717,13 +718,12 @@ DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
|
||||
static bool
|
||||
StructuredCloneHasTransferObjects(const JSStructuredCloneData& data)
|
||||
{
|
||||
auto iter = data.Iter();
|
||||
|
||||
if (data.Size() < sizeof(uint64_t))
|
||||
return false;
|
||||
|
||||
uint64_t u;
|
||||
MOZ_ALWAYS_TRUE(data.ReadBytes(iter, reinterpret_cast<char*>(&u), sizeof(u)));
|
||||
BufferIterator<uint64_t, SystemAllocPolicy> iter(data);
|
||||
MOZ_ALWAYS_TRUE(iter.readBytes(reinterpret_cast<char*>(&u), sizeof(u)));
|
||||
uint32_t tag = uint32_t(u >> 32);
|
||||
return (tag == SCTAG_TRANSFER_MAP_HEADER);
|
||||
}
|
||||
@ -734,7 +734,7 @@ SCInput::SCInput(JSContext* cx, JSStructuredCloneData& data)
|
||||
: cx(cx), point(data)
|
||||
{
|
||||
|
||||
static_assert(JSStructuredCloneData::kSegmentAlignment % 8 == 0,
|
||||
static_assert(JSStructuredCloneData::BufferList::kSegmentAlignment % 8 == 0,
|
||||
"structured clone buffer reads should be aligned");
|
||||
MOZ_ASSERT(data.Size() % 8 == 0);
|
||||
}
|
||||
@ -906,7 +906,6 @@ SCInput::readPtr(void** p)
|
||||
|
||||
SCOutput::SCOutput(JSContext* cx)
|
||||
: cx(cx)
|
||||
, buf(0, 0, 4096, cx)
|
||||
{
|
||||
}
|
||||
|
||||
@ -914,7 +913,11 @@ bool
|
||||
SCOutput::write(uint64_t u)
|
||||
{
|
||||
uint64_t v = NativeEndian::swapToLittleEndian(u);
|
||||
return buf.WriteBytes(reinterpret_cast<char*>(&v), sizeof(u));
|
||||
if (!buf.AppendBytes(reinterpret_cast<char*>(&v), sizeof(u))) {
|
||||
ReportOutOfMemory(context());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -954,14 +957,14 @@ SCOutput::writeArray(const T* p, size_t nelems)
|
||||
|
||||
for (size_t i = 0; i < nelems; i++) {
|
||||
T value = NativeEndian::swapToLittleEndian(p[i]);
|
||||
if (!buf.WriteBytes(reinterpret_cast<char*>(&value), sizeof(value)))
|
||||
if (!buf.AppendBytes(reinterpret_cast<char*>(&value), sizeof(value)))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Zero-pad to 8 bytes boundary.
|
||||
size_t padbytes = ComputePadding(nelems, sizeof(T));
|
||||
char zeroes[sizeof(uint64_t)] = { 0 };
|
||||
if (!buf.WriteBytes(zeroes, padbytes))
|
||||
if (!buf.AppendBytes(zeroes, padbytes))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -974,13 +977,13 @@ SCOutput::writeArray<uint8_t>(const uint8_t* p, size_t nelems)
|
||||
if (nelems == 0)
|
||||
return true;
|
||||
|
||||
if (!buf.WriteBytes(reinterpret_cast<const char*>(p), nelems))
|
||||
if (!buf.AppendBytes(reinterpret_cast<const char*>(p), nelems))
|
||||
return false;
|
||||
|
||||
// zero-pad to 8 bytes boundary
|
||||
size_t padbytes = ComputePadding(nelems, 1);
|
||||
char zeroes[sizeof(uint64_t)] = { 0 };
|
||||
if (!buf.WriteBytes(zeroes, padbytes))
|
||||
if (!buf.AppendBytes(zeroes, padbytes))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@ -1014,34 +1017,22 @@ SCOutput::writePtr(const void* p)
|
||||
return write(reinterpret_cast<uint64_t>(p));
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::extractBuffer(JSStructuredCloneData* data)
|
||||
{
|
||||
bool success;
|
||||
mozilla::BufferList<SystemAllocPolicy> out =
|
||||
buf.MoveFallible<SystemAllocPolicy>(&success);
|
||||
if (!success) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
*data = JSStructuredCloneData(Move(out));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure)
|
||||
SCOutput::discardTransferables()
|
||||
{
|
||||
DiscardTransferables(buf, cb, cbClosure);
|
||||
buf.discardTransferables();
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
JSStructuredCloneData::~JSStructuredCloneData()
|
||||
|
||||
void
|
||||
JSStructuredCloneData::discardTransferables()
|
||||
{
|
||||
if (!Size())
|
||||
return;
|
||||
if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
|
||||
DiscardTransferables(*this, callbacks_, closure_);
|
||||
DiscardTransferables(bufList_, callbacks_, closure_);
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
|
||||
@ -1049,9 +1040,8 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
|
||||
JSStructuredCloneWriter::~JSStructuredCloneWriter()
|
||||
{
|
||||
// Free any transferable data left lying around in the buffer
|
||||
if (out.count()) {
|
||||
out.discardTransferables(callbacks, closure);
|
||||
}
|
||||
if (out.count())
|
||||
out.discardTransferables();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1129,11 +1119,11 @@ JSStructuredCloneWriter::parseTransferable()
|
||||
}
|
||||
|
||||
else {
|
||||
if (!callbacks || !callbacks->canTransfer)
|
||||
if (!out.buf.callbacks_ || !out.buf.callbacks_->canTransfer)
|
||||
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
|
||||
|
||||
JSAutoCompartment ac(cx, unwrappedObj);
|
||||
if (!callbacks->canTransfer(cx, unwrappedObj, closure))
|
||||
if (!out.buf.callbacks_->canTransfer(cx, unwrappedObj, out.buf.closure_))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1152,7 +1142,7 @@ JSStructuredCloneWriter::parseTransferable()
|
||||
bool
|
||||
JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId)
|
||||
{
|
||||
ReportDataCloneError(context(), callbacks, errorId);
|
||||
ReportDataCloneError(context(), out.buf.callbacks_, errorId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1285,7 +1275,7 @@ JSStructuredCloneWriter::writeSharedArrayBuffer(HandleObject obj)
|
||||
Rooted<SharedArrayBufferObject*> sharedArrayBuffer(context(), &CheckedUnwrap(obj)->as<SharedArrayBufferObject>());
|
||||
SharedArrayRawBuffer* rawbuf = sharedArrayBuffer->rawBufferObject();
|
||||
|
||||
if (!refsHeld.acquire(context(), rawbuf))
|
||||
if (!out.buf.refsHeld_.acquire(context(), rawbuf))
|
||||
return false;
|
||||
|
||||
// We must serialize the length so that the buffer object arrives in the
|
||||
@ -1611,8 +1601,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
|
||||
return traverseSavedFrame(obj);
|
||||
}
|
||||
|
||||
if (callbacks && callbacks->write)
|
||||
return callbacks->write(context(), this, obj, closure);
|
||||
if (out.buf.callbacks_ && out.buf.callbacks_->write)
|
||||
return out.buf.callbacks_->write(context(), this, obj, out.buf.closure_);
|
||||
// else fall through
|
||||
}
|
||||
|
||||
@ -1755,9 +1745,9 @@ JSStructuredCloneWriter::transferOwnership()
|
||||
extraData = nbytes;
|
||||
}
|
||||
} else {
|
||||
if (!callbacks || !callbacks->writeTransfer)
|
||||
if (!out.buf.callbacks_ || !out.buf.callbacks_->writeTransfer)
|
||||
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
|
||||
if (!callbacks->writeTransfer(cx, obj, closure, &tag, &ownership, &content, &extraData))
|
||||
if (!out.buf.callbacks_->writeTransfer(cx, obj, out.buf.closure_, &tag, &ownership, &content, &extraData))
|
||||
return false;
|
||||
MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY);
|
||||
}
|
||||
@ -2831,51 +2821,15 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks,
|
||||
void* optionalClosure)
|
||||
JSAutoStructuredCloneBuffer::clear()
|
||||
{
|
||||
if (!data_.Size())
|
||||
return;
|
||||
|
||||
const JSStructuredCloneCallbacks* callbacks =
|
||||
optionalCallbacks ? optionalCallbacks : data_.callbacks_;
|
||||
void* closure = optionalClosure ? optionalClosure : data_.closure_;
|
||||
|
||||
if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
|
||||
DiscardTransferables(data_, callbacks, closure);
|
||||
data_.discardTransferables();
|
||||
data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
|
||||
data_.refsHeld_.releaseAll();
|
||||
data_.Clear();
|
||||
version_ = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
JSAutoStructuredCloneBuffer::copy(JSContext* cx, const JSStructuredCloneData& srcData,
|
||||
uint32_t version, const JSStructuredCloneCallbacks* callbacks,
|
||||
void* closure)
|
||||
{
|
||||
// transferable objects cannot be copied
|
||||
if (StructuredCloneHasTransferObjects(srcData))
|
||||
return false;
|
||||
|
||||
clear();
|
||||
|
||||
auto iter = srcData.Iter();
|
||||
while (!iter.Done()) {
|
||||
if (!data_.WriteBytes(iter.Data(), iter.RemainingInSegment()))
|
||||
return false;
|
||||
iter.Advance(srcData, iter.RemainingInSegment());
|
||||
}
|
||||
|
||||
version_ = version;
|
||||
|
||||
if (!data_.refsHeld_.acquireAll(cx, srcData.refsHeld_))
|
||||
return false;
|
||||
|
||||
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t version,
|
||||
const JSStructuredCloneCallbacks* callbacks,
|
||||
@ -2884,7 +2838,7 @@ JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t versio
|
||||
clear();
|
||||
data_ = Move(data);
|
||||
version_ = version;
|
||||
data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
|
||||
data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2901,7 +2855,7 @@ JSAutoStructuredCloneBuffer::steal(JSStructuredCloneData* data, uint32_t* versio
|
||||
*data = Move(data_);
|
||||
|
||||
version_ = 0;
|
||||
data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
|
||||
data_.setCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -160,7 +160,6 @@ using mozilla::dom::HTMLMediaElementBinding::HAVE_METADATA;
|
||||
|
||||
#define WEBKIT_PREFIXES_ENABLED_PREF_NAME "layout.css.prefixes.webkit"
|
||||
#define TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME "layout.css.text-align-unsafe-value.enabled"
|
||||
#define FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME "layout.css.float-logical-values.enabled"
|
||||
#define INTERCHARACTER_RUBY_ENABLED_PREF_NAME "layout.css.ruby.intercharacter.enabled"
|
||||
#define CONTENT_SELECT_ENABLED_PREF_NAME "dom.select_popup_in_content.enabled"
|
||||
|
||||
@ -315,61 +314,6 @@ TextAlignUnsafeEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
|
||||
isTextAlignUnsafeEnabled ? eCSSKeyword_unsafe : eCSSKeyword_UNKNOWN;
|
||||
}
|
||||
|
||||
// When the pref "layout.css.float-logical-values.enabled" changes, this
|
||||
// function is called to let us update kFloatKTable & kClearKTable,
|
||||
// to selectively disable or restore the entries for logical values
|
||||
// (inline-start and inline-end) in those tables.
|
||||
static void
|
||||
FloatLogicalValuesEnabledPrefChangeCallback(const char* aPrefName,
|
||||
void* aClosure)
|
||||
{
|
||||
NS_ASSERTION(strcmp(aPrefName, FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME) == 0,
|
||||
"Did you misspell " FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME " ?");
|
||||
|
||||
static bool sIsInitialized;
|
||||
static int32_t sIndexOfInlineStartInFloatTable;
|
||||
static int32_t sIndexOfInlineEndInFloatTable;
|
||||
static int32_t sIndexOfInlineStartInClearTable;
|
||||
static int32_t sIndexOfInlineEndInClearTable;
|
||||
bool isFloatLogicalValuesEnabled =
|
||||
Preferences::GetBool(FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME, false);
|
||||
|
||||
if (!sIsInitialized) {
|
||||
// First run: find the position of "inline-start" in kFloatKTable.
|
||||
sIndexOfInlineStartInFloatTable =
|
||||
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_start,
|
||||
nsCSSProps::kFloatKTable);
|
||||
// First run: find the position of "inline-end" in kFloatKTable.
|
||||
sIndexOfInlineEndInFloatTable =
|
||||
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_end,
|
||||
nsCSSProps::kFloatKTable);
|
||||
// First run: find the position of "inline-start" in kClearKTable.
|
||||
sIndexOfInlineStartInClearTable =
|
||||
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_start,
|
||||
nsCSSProps::kClearKTable);
|
||||
// First run: find the position of "inline-end" in kClearKTable.
|
||||
sIndexOfInlineEndInClearTable =
|
||||
nsCSSProps::FindIndexOfKeyword(eCSSKeyword_inline_end,
|
||||
nsCSSProps::kClearKTable);
|
||||
sIsInitialized = true;
|
||||
}
|
||||
|
||||
// OK -- now, stomp on or restore the logical entries in the keyword tables,
|
||||
// depending on whether the pref is enabled vs. disabled.
|
||||
MOZ_ASSERT(sIndexOfInlineStartInFloatTable >= 0);
|
||||
nsCSSProps::kFloatKTable[sIndexOfInlineStartInFloatTable].mKeyword =
|
||||
isFloatLogicalValuesEnabled ? eCSSKeyword_inline_start : eCSSKeyword_UNKNOWN;
|
||||
MOZ_ASSERT(sIndexOfInlineEndInFloatTable >= 0);
|
||||
nsCSSProps::kFloatKTable[sIndexOfInlineEndInFloatTable].mKeyword =
|
||||
isFloatLogicalValuesEnabled ? eCSSKeyword_inline_end : eCSSKeyword_UNKNOWN;
|
||||
MOZ_ASSERT(sIndexOfInlineStartInClearTable >= 0);
|
||||
nsCSSProps::kClearKTable[sIndexOfInlineStartInClearTable].mKeyword =
|
||||
isFloatLogicalValuesEnabled ? eCSSKeyword_inline_start : eCSSKeyword_UNKNOWN;
|
||||
MOZ_ASSERT(sIndexOfInlineEndInClearTable >= 0);
|
||||
nsCSSProps::kClearKTable[sIndexOfInlineEndInClearTable].mKeyword =
|
||||
isFloatLogicalValuesEnabled ? eCSSKeyword_inline_end : eCSSKeyword_UNKNOWN;
|
||||
}
|
||||
|
||||
template<typename TestType>
|
||||
static bool
|
||||
HasMatchingAnimations(EffectSet* aEffects, TestType&& aTest)
|
||||
@ -8217,8 +8161,6 @@ static const PrefCallbacks kPrefCallbacks[] = {
|
||||
WebkitPrefixEnabledPrefChangeCallback },
|
||||
{ TEXT_ALIGN_UNSAFE_ENABLED_PREF_NAME,
|
||||
TextAlignUnsafeEnabledPrefChangeCallback },
|
||||
{ FLOAT_LOGICAL_VALUES_ENABLED_PREF_NAME,
|
||||
FloatLogicalValuesEnabledPrefChangeCallback },
|
||||
};
|
||||
|
||||
/* static */
|
||||
|
@ -110,11 +110,9 @@ public:
|
||||
*/
|
||||
void AddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const;
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
void Check() {
|
||||
mPool.Check();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
void* Allocate(uint32_t aCode, size_t aSize);
|
||||
|
@ -2781,10 +2781,26 @@ ComputeClipForMaskItem(nsDisplayListBuilder* aBuilder, nsIFrame* aMaskedFrame,
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
struct AutoCheckBuilder {
|
||||
explicit AutoCheckBuilder(nsDisplayListBuilder* aBuilder)
|
||||
: mBuilder(aBuilder)
|
||||
{
|
||||
aBuilder->Check();
|
||||
}
|
||||
|
||||
~AutoCheckBuilder()
|
||||
{
|
||||
mBuilder->Check();
|
||||
}
|
||||
|
||||
nsDisplayListBuilder* mBuilder;
|
||||
};
|
||||
|
||||
void
|
||||
nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayList* aList,
|
||||
bool* aCreatedContainerItem) {
|
||||
AutoCheckBuilder check(aBuilder);
|
||||
if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
|
||||
return;
|
||||
|
||||
@ -3069,7 +3085,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
true);
|
||||
|
||||
MarkAbsoluteFramesForDisplayList(aBuilder);
|
||||
aBuilder->Check();
|
||||
BuildDisplayList(aBuilder, set);
|
||||
aBuilder->Check();
|
||||
|
||||
// Blend modes are a real pain for retained display lists. We build a blend
|
||||
// container item if the built list contains any blend mode items within
|
||||
@ -3117,7 +3135,9 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
|
||||
MarkAbsoluteFramesForDisplayList(aBuilder);
|
||||
aBuilder->Check();
|
||||
BuildDisplayList(aBuilder, set);
|
||||
aBuilder->Check();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3515,6 +3535,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aChild,
|
||||
const nsDisplayListSet& aLists,
|
||||
uint32_t aFlags) {
|
||||
AutoCheckBuilder check(aBuilder);
|
||||
// If painting is restricted to just the background of the top level frame,
|
||||
// then we have nothing to do here.
|
||||
if (aBuilder->IsBackgroundOnly())
|
||||
@ -3577,7 +3598,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
child->MarkAbsoluteFramesForDisplayList(aBuilder);
|
||||
aBuilder->AdjustWindowDraggingRegion(child);
|
||||
aBuilder->Check();
|
||||
child->BuildDisplayList(aBuilder, aLists);
|
||||
aBuilder->Check();
|
||||
aBuilder->DisplayCaret(child, aLists.Content());
|
||||
#ifdef DEBUG
|
||||
DisplayDebugBorders(aBuilder, child, aLists);
|
||||
@ -3825,7 +3848,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
differentAGR);
|
||||
|
||||
aBuilder->AdjustWindowDraggingRegion(child);
|
||||
aBuilder->Check();
|
||||
child->BuildDisplayList(aBuilder, aLists);
|
||||
aBuilder->Check();
|
||||
aBuilder->DisplayCaret(child, aLists.Content());
|
||||
#ifdef DEBUG
|
||||
DisplayDebugBorders(aBuilder, child, aLists);
|
||||
@ -3845,7 +3870,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
|
||||
aBuilder->AdjustWindowDraggingRegion(child);
|
||||
nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
|
||||
aBuilder->Check();
|
||||
child->BuildDisplayList(aBuilder, pseudoStack);
|
||||
aBuilder->Check();
|
||||
if (aBuilder->DisplayCaret(child, pseudoStack.Content())) {
|
||||
canSkipWrapList = false;
|
||||
}
|
||||
|
@ -711,9 +711,7 @@ public:
|
||||
void RecomputeCurrentAnimatedGeometryRoot();
|
||||
|
||||
void Check() {
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
mPool.Check();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,10 +96,10 @@ fuzzy-if(OSX==1010,28,7) == orthogonal-floats-1b.html orthogonal-floats-1-ref.ht
|
||||
fuzzy-if(OSX==1010,103,802) fuzzy-if(winWidget,135,700) == orthogonal-floats-1c.html orthogonal-floats-1-ref.html
|
||||
fuzzy-if(OSX==1010,103,802) fuzzy-if(winWidget,135,700) == orthogonal-floats-1d.html orthogonal-floats-1-ref.html
|
||||
|
||||
pref(layout.css.float-logical-values.enabled,true) == logical-float-side-1.html logical-float-side-1-ref.html
|
||||
pref(layout.css.float-logical-values.enabled,true) == logical-float-side-2.html logical-float-side-2-ref.html
|
||||
pref(layout.css.float-logical-values.enabled,true) == logical-float-side-3.html logical-float-side-3-ref.html
|
||||
pref(layout.css.float-logical-values.enabled,true) == logical-float-side-4.html logical-float-side-4-ref.html
|
||||
== logical-float-side-1.html logical-float-side-1-ref.html
|
||||
== logical-float-side-2.html logical-float-side-2-ref.html
|
||||
== logical-float-side-3.html logical-float-side-3-ref.html
|
||||
== logical-float-side-4.html logical-float-side-4-ref.html
|
||||
|
||||
== float-in-rtl-slr-1a.html float-in-rtl-slr-1-ref.html
|
||||
== float-in-rtl-slr-1b.html float-in-rtl-slr-1-ref.html
|
||||
|
@ -845,7 +845,7 @@ const KTableEntry nsCSSProps::kCaptionSideKTable[] = {
|
||||
{ eCSSKeyword_UNKNOWN, -1 }
|
||||
};
|
||||
|
||||
KTableEntry nsCSSProps::kClearKTable[] = {
|
||||
const KTableEntry nsCSSProps::kClearKTable[] = {
|
||||
{ eCSSKeyword_none, StyleClear::None },
|
||||
{ eCSSKeyword_left, StyleClear::Left },
|
||||
{ eCSSKeyword_right, StyleClear::Right },
|
||||
@ -1277,7 +1277,7 @@ const KTableEntry nsCSSProps::kHyphensKTable[] = {
|
||||
{ eCSSKeyword_UNKNOWN, -1 }
|
||||
};
|
||||
|
||||
KTableEntry nsCSSProps::kFloatKTable[] = {
|
||||
const KTableEntry nsCSSProps::kFloatKTable[] = {
|
||||
{ eCSSKeyword_none, StyleFloat::None },
|
||||
{ eCSSKeyword_left, StyleFloat::Left },
|
||||
{ eCSSKeyword_right, StyleFloat::Right },
|
||||
|
@ -552,9 +552,7 @@ public:
|
||||
static const KTableEntry kBoxShadowTypeKTable[];
|
||||
static const KTableEntry kBoxSizingKTable[];
|
||||
static const KTableEntry kCaptionSideKTable[];
|
||||
// Not const because we modify its entries when the pref
|
||||
// "layout.css.float-logical-values.enabled" changes:
|
||||
static KTableEntry kClearKTable[];
|
||||
static const KTableEntry kClearKTable[];
|
||||
static const KTableEntry kColorKTable[];
|
||||
static const KTableEntry kContentKTable[];
|
||||
static const KTableEntry kControlCharacterVisibilityKTable[];
|
||||
@ -583,9 +581,7 @@ public:
|
||||
// ------------------------------------------------------------------
|
||||
static const KTableEntry kFlexDirectionKTable[];
|
||||
static const KTableEntry kFlexWrapKTable[];
|
||||
// Not const because we modify its entries when the pref
|
||||
// "layout.css.float-logical-values.enabled" changes:
|
||||
static KTableEntry kFloatKTable[];
|
||||
static const KTableEntry kFloatKTable[];
|
||||
static const KTableEntry kFloatEdgeKTable[];
|
||||
static const KTableEntry kFontDisplayKTable[];
|
||||
static const KTableEntry kFontKTable[];
|
||||
|
@ -3320,7 +3320,7 @@ var gCSSProperties = {
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "none" ],
|
||||
other_values: [ "left", "right", "both" ],
|
||||
other_values: [ "left", "right", "both", "inline-start", "inline-end" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"clip": {
|
||||
@ -3480,7 +3480,7 @@ var gCSSProperties = {
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
applies_to_first_letter: true,
|
||||
initial_values: [ "none" ],
|
||||
other_values: [ "left", "right" ],
|
||||
other_values: [ "left", "right", "inline-start", "inline-end" ],
|
||||
invalid_values: []
|
||||
},
|
||||
"font": {
|
||||
@ -8132,18 +8132,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.text-align-unsafe-value.enabled")) {
|
||||
gCSSProperties["text-align"].invalid_values.push("true left");
|
||||
}
|
||||
|
||||
if (IsCSSPropertyPrefEnabled("layout.css.float-logical-values.enabled")) {
|
||||
gCSSProperties["float"].other_values.push("inline-start");
|
||||
gCSSProperties["float"].other_values.push("inline-end");
|
||||
gCSSProperties["clear"].other_values.push("inline-start");
|
||||
gCSSProperties["clear"].other_values.push("inline-end");
|
||||
} else {
|
||||
gCSSProperties["float"].invalid_values.push("inline-start");
|
||||
gCSSProperties["float"].invalid_values.push("inline-end");
|
||||
gCSSProperties["clear"].invalid_values.push("inline-start");
|
||||
gCSSProperties["clear"].invalid_values.push("inline-end");
|
||||
}
|
||||
|
||||
gCSSProperties["display"].other_values.push("flow-root");
|
||||
|
||||
// Copy aliased properties' fields from their alias targets.
|
||||
|
@ -2878,10 +2878,6 @@ pref("layout.css.text-align-unsafe-value.enabled", false);
|
||||
// Is support for CSS text-justify property enabled?
|
||||
pref("layout.css.text-justify.enabled", true);
|
||||
|
||||
// Is support for CSS "float: inline-{start,end}" and
|
||||
// "clear: inline-{start,end}" enabled?
|
||||
pref("layout.css.float-logical-values.enabled", true);
|
||||
|
||||
// Is support for the CSS4 image-orientation property enabled?
|
||||
pref("layout.css.image-orientation.enabled", true);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -11,8 +11,11 @@ use std::io::{BufRead, BufReader, Write};
|
||||
use std::path::Path;
|
||||
|
||||
fn main() {
|
||||
// https://github.com/rust-lang/cargo/issues/3544
|
||||
let style_out_dir = env::var_os("DEP_FOR SOME REASON THE LINKS KEY IS REQUIRED \
|
||||
TO PASS DATA AROUND BETWEEN BUILD SCRIPTS_OUT_DIR").unwrap();
|
||||
let root_path = Path::new("../../../");
|
||||
let bindings_file = root_path.join("components/style/gecko/generated/bindings.rs");
|
||||
let bindings_file = Path::new(&style_out_dir).join("gecko/bindings.rs");
|
||||
let glue_file = root_path.join("ports/geckolib/glue.rs");
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
@ -70,9 +73,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/rust-lang/cargo/issues/3544
|
||||
let style_out_dir = env::var_os("DEP_FOR SOME REASON THE LINKS KEY IS REQUIRED \
|
||||
TO PASS DATA AROUND BETWEEN BUILD SCRIPTS_OUT_DIR").unwrap();
|
||||
File::create(out_dir.join("bindings.rs"))
|
||||
.unwrap()
|
||||
.write_all(format!("include!(concat!({:?}, \"/gecko/structs.rs\"));",
|
||||
|
@ -179,6 +179,15 @@ class MochitestRunner(MozbuildObject):
|
||||
|
||||
return runtestsremote.run_test_harness(parser, options)
|
||||
|
||||
def run_geckoview_junit_test(self, context, **kwargs):
|
||||
host_ret = verify_host_bin()
|
||||
if host_ret != 0:
|
||||
return host_ret
|
||||
|
||||
import runjunit
|
||||
options = Namespace(**kwargs)
|
||||
return runjunit.run_test_harness(parser, options)
|
||||
|
||||
def run_robocop_test(self, context, tests, suite=None, **kwargs):
|
||||
host_ret = verify_host_bin()
|
||||
if host_ret != 0:
|
||||
@ -241,6 +250,38 @@ def setup_argument_parser():
|
||||
return parser
|
||||
|
||||
|
||||
def setup_junit_argument_parser():
|
||||
build_obj = MozbuildObject.from_environment(cwd=here)
|
||||
|
||||
build_path = os.path.join(build_obj.topobjdir, 'build')
|
||||
if build_path not in sys.path:
|
||||
sys.path.append(build_path)
|
||||
|
||||
mochitest_dir = os.path.join(build_obj.topobjdir, '_tests', 'testing', 'mochitest')
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore')
|
||||
|
||||
# runtests.py contains MochitestDesktop, required by runjunit
|
||||
import imp
|
||||
path = os.path.join(build_obj.topobjdir, mochitest_dir, 'runtests.py')
|
||||
if not os.path.exists(path):
|
||||
path = os.path.join(here, "runtests.py")
|
||||
|
||||
with open(path, 'r') as fh:
|
||||
imp.load_module('mochitest', fh, path,
|
||||
('.py', 'r', imp.PY_SOURCE))
|
||||
|
||||
import runjunit
|
||||
|
||||
from mozrunner.devices.android_device import verify_android_device
|
||||
verify_android_device(build_obj, install=False, xre=True)
|
||||
|
||||
global parser
|
||||
parser = runjunit.JunitArgumentParser()
|
||||
return parser
|
||||
|
||||
|
||||
# condition filters
|
||||
|
||||
def is_buildapp_in(*apps):
|
||||
@ -441,6 +482,40 @@ class MachCommands(MachCommandBase):
|
||||
return overall
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class GeckoviewJunitCommands(MachCommandBase):
|
||||
|
||||
@Command('geckoview-junit', category='testing',
|
||||
conditions=[conditions.is_android],
|
||||
description='Run remote geckoview junit tests.',
|
||||
parser=setup_junit_argument_parser)
|
||||
def run_junit(self, **kwargs):
|
||||
self._ensure_state_subdir_exists('.')
|
||||
|
||||
from mozrunner.devices.android_device import (grant_runtime_permissions,
|
||||
get_adb_path,
|
||||
verify_android_device)
|
||||
# verify installation
|
||||
app = kwargs.get('app')
|
||||
device_serial = kwargs.get('deviceSerial')
|
||||
verify_android_device(self, install=True, xre=False, app=app,
|
||||
device_serial=device_serial)
|
||||
grant_runtime_permissions(self, app, device_serial=device_serial)
|
||||
|
||||
if not kwargs.get('adbPath'):
|
||||
kwargs['adbPath'] = get_adb_path(self)
|
||||
|
||||
if not kwargs.get('log'):
|
||||
from mozlog.commandline import setup_logging
|
||||
format_args = {'level': self._mach_context.settings['test']['level']}
|
||||
default_format = self._mach_context.settings['test']['format']
|
||||
kwargs['log'] = setup_logging('mach-mochitest', kwargs,
|
||||
{default_format: sys.stdout}, format_args)
|
||||
|
||||
mochitest = self._spawn(MochitestRunner)
|
||||
return mochitest.run_geckoview_junit_test(self._mach_context, **kwargs)
|
||||
|
||||
|
||||
@CommandProvider
|
||||
class RobocopCommands(MachCommandBase):
|
||||
|
||||
|
@ -56,6 +56,7 @@ TEST_HARNESS_FILES.testing.mochitest += [
|
||||
'pywebsocket_wrapper.py',
|
||||
'redirect.html',
|
||||
'rungeckoview.py',
|
||||
'runjunit.py',
|
||||
'runrobocop.py',
|
||||
'runtests.py',
|
||||
'runtestsremote.py',
|
||||
|
@ -147,9 +147,9 @@ class GeckoviewTestRunner:
|
||||
expected = 'PASS'
|
||||
(passed, message) = test()
|
||||
if passed:
|
||||
pass_count = pass_count + 1
|
||||
pass_count += 1
|
||||
else:
|
||||
fail_count = fail_count + 1
|
||||
fail_count += 1
|
||||
status = 'PASS' if passed else 'FAIL'
|
||||
|
||||
self.log.test_end(self.test_name, status, expected, message)
|
||||
@ -195,7 +195,7 @@ class GeckoviewTestRunner:
|
||||
try:
|
||||
shutil.rmtree(dump_dir)
|
||||
except Exception:
|
||||
self.log.warn("unable to remove directory: %s" % dump_dir)
|
||||
self.log.warning("unable to remove directory: %s" % dump_dir)
|
||||
return crashed
|
||||
|
||||
def cleanup(self):
|
||||
|
405
testing/mochitest/runjunit.py
Normal file
405
testing/mochitest/runjunit.py
Normal file
@ -0,0 +1,405 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
|
||||
import mozcrash
|
||||
import mozinfo
|
||||
import mozlog
|
||||
import moznetwork
|
||||
from mozdevice import ADBAndroid
|
||||
from mozprofile import Profile, Preferences, DEFAULT_PORTS
|
||||
from runtests import MochitestDesktop, update_mozinfo
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
try:
|
||||
from mozbuild.base import (
|
||||
MozbuildObject,
|
||||
MachCommandConditions as conditions,
|
||||
)
|
||||
build_obj = MozbuildObject.from_environment(cwd=here)
|
||||
except ImportError:
|
||||
build_obj = None
|
||||
conditions = None
|
||||
|
||||
|
||||
class JUnitTestRunner(MochitestDesktop):
|
||||
"""
|
||||
A test harness to run geckoview junit tests on a remote device.
|
||||
"""
|
||||
|
||||
def __init__(self, log, options):
|
||||
self.log = log
|
||||
verbose = False
|
||||
if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
|
||||
verbose = True
|
||||
self.device = ADBAndroid(adb=options.adbPath or 'adb',
|
||||
device=options.deviceSerial,
|
||||
test_root=options.remoteTestRoot,
|
||||
verbose=verbose)
|
||||
self.options = options
|
||||
self.log.debug("options=%s" % vars(options))
|
||||
update_mozinfo()
|
||||
self.remote_profile = posixpath.join(self.device.test_root, 'junit-profile')
|
||||
self.server_init()
|
||||
|
||||
self.cleanup()
|
||||
self.device.clear_logcat()
|
||||
self.build_profile()
|
||||
self.startServers(
|
||||
self.options,
|
||||
debuggerInfo=None,
|
||||
ignoreSSLTunnelExts=True)
|
||||
self.log.debug("Servers started")
|
||||
|
||||
def server_init(self):
|
||||
"""
|
||||
Additional initialization required to satisfy MochitestDesktop.startServers
|
||||
"""
|
||||
self._locations = None
|
||||
self.server = None
|
||||
self.wsserver = None
|
||||
self.websocketProcessBridge = None
|
||||
self.SERVER_STARTUP_TIMEOUT = 180 if mozinfo.info.get('debug') else 90
|
||||
if self.options.remoteWebServer is None:
|
||||
if os.name != "nt":
|
||||
self.options.remoteWebServer = moznetwork.get_ip()
|
||||
else:
|
||||
raise Exception("--remote-webserver must be specified")
|
||||
self.options.webServer = self.options.remoteWebServer
|
||||
self.options.webSocketPort = '9988'
|
||||
self.options.httpdPath = None
|
||||
self.options.keep_open = False
|
||||
self.options.pidFile = ""
|
||||
self.options.subsuite = None
|
||||
self.options.xrePath = None
|
||||
if build_obj and 'MOZ_HOST_BIN' in os.environ:
|
||||
self.options.xrePath = os.environ['MOZ_HOST_BIN']
|
||||
if not self.options.utilityPath:
|
||||
self.options.utilityPath = self.options.xrePath
|
||||
if not self.options.xrePath:
|
||||
self.options.xrePath = self.options.utilityPath
|
||||
if build_obj:
|
||||
self.options.certPath = os.path.join(build_obj.topsrcdir,
|
||||
'build', 'pgo', 'certs')
|
||||
|
||||
def build_profile(self):
|
||||
"""
|
||||
Create a local profile with test prefs and proxy definitions and
|
||||
push it to the remote device.
|
||||
"""
|
||||
preferences = [
|
||||
os.path.join(
|
||||
here,
|
||||
'profile_data',
|
||||
'prefs_general.js')]
|
||||
|
||||
prefs = {}
|
||||
for path in preferences:
|
||||
prefs.update(Preferences.read_prefs(path))
|
||||
|
||||
interpolation = {
|
||||
"server": "%s:%s" %
|
||||
(self.options.webServer, self.options.httpPort)}
|
||||
|
||||
prefs = json.loads(json.dumps(prefs) % interpolation)
|
||||
for pref in prefs:
|
||||
prefs[pref] = Preferences.cast(prefs[pref])
|
||||
|
||||
proxy = {'remote': self.options.webServer,
|
||||
'http': self.options.httpPort,
|
||||
'https': self.options.sslPort,
|
||||
'ws': self.options.sslPort
|
||||
}
|
||||
|
||||
self.profile = Profile(preferences=prefs, proxy=proxy)
|
||||
self.options.profilePath = self.profile.profile
|
||||
|
||||
if self.fillCertificateDB(self.options):
|
||||
self.log.error("Certificate integration failed")
|
||||
|
||||
self.device.mkdir(self.remote_profile, parents=True)
|
||||
self.device.push(self.profile.profile, self.remote_profile)
|
||||
self.log.debug("profile %s -> %s" %
|
||||
(str(self.profile.profile), str(self.remote_profile)))
|
||||
|
||||
def cleanup(self):
|
||||
try:
|
||||
self.stopServers()
|
||||
self.log.debug("Servers stopped")
|
||||
self.device.stop_application(self.options.app)
|
||||
self.device.rm(self.remote_profile, force=True, recursive=True)
|
||||
if hasattr(self, 'profile'):
|
||||
del self.profile
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
self.log.info("Caught and ignored an exception during cleanup")
|
||||
|
||||
def build_command_line(self, test_filters):
|
||||
"""
|
||||
Construct and return the 'am instrument' command line.
|
||||
"""
|
||||
cmd = "am instrument -w -r"
|
||||
# profile location
|
||||
cmd = cmd + " -e args '-profile %s'" % self.remote_profile
|
||||
# multi-process
|
||||
e10s = 'true' if self.options.e10s else 'false'
|
||||
cmd = cmd + " -e use_multiprocess %s" % e10s
|
||||
# test filters: limit run to specific test(s)
|
||||
for f in test_filters:
|
||||
# filter can be class-name or 'class-name#method-name' (single test)
|
||||
cmd = cmd + " -e class %s" % f
|
||||
# environment
|
||||
env = {}
|
||||
env["MOZ_CRASHREPORTER"] = "1"
|
||||
env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
|
||||
env["MOZ_CRASHREPORTER_SHUTDOWN"] = "1"
|
||||
env["XPCOM_DEBUG_BREAK"] = "stack"
|
||||
env["DISABLE_UNSAFE_CPOW_WARNINGS"] = "1"
|
||||
env["MOZ_DISABLE_NONLOCAL_CONNECTIONS"] = "1"
|
||||
env["MOZ_IN_AUTOMATION"] = "1"
|
||||
env["R_LOG_VERBOSE"] = "1"
|
||||
env["R_LOG_LEVEL"] = "6"
|
||||
env["R_LOG_DESTINATION"] = "stderr"
|
||||
for (env_count, (env_key, env_val)) in enumerate(env.iteritems()):
|
||||
cmd = cmd + " -e env%d %s=%s" % (env_count, env_key, env_val)
|
||||
# runner
|
||||
cmd = cmd + " %s/%s" % (self.options.app, self.options.runner)
|
||||
return cmd
|
||||
|
||||
def run_tests(self, test_filters=None):
|
||||
"""
|
||||
Run the tests.
|
||||
"""
|
||||
if not self.device.is_app_installed(self.options.app):
|
||||
raise Exception("%s is not installed" %
|
||||
self.options.app)
|
||||
if self.device.process_exist(self.options.app):
|
||||
raise Exception("%s already running before starting tests" %
|
||||
self.options.app)
|
||||
|
||||
self.test_started = False
|
||||
self.pass_count = 0
|
||||
self.fail_count = 0
|
||||
self.class_name = ""
|
||||
self.test_name = ""
|
||||
self.current_full_name = ""
|
||||
|
||||
def callback(line):
|
||||
# Output callback: Parse the raw junit log messages, translating into
|
||||
# treeherder-friendly test start/pass/fail messages.
|
||||
|
||||
self.log.process_output(self.options.app, str(line))
|
||||
expected = 'PASS'
|
||||
# Expect per-test info like: "INSTRUMENTATION_STATUS: class=something"
|
||||
match = re.match(r'INSTRUMENTATION_STATUS:\s*class=(.*)', line)
|
||||
if match:
|
||||
self.class_name = match.group(1)
|
||||
# Expect per-test info like: "INSTRUMENTATION_STATUS: test=something"
|
||||
match = re.match(r'INSTRUMENTATION_STATUS:\s*test=(.*)', line)
|
||||
if match:
|
||||
self.test_name = match.group(1)
|
||||
# Expect per-test info like: "INSTRUMENTATION_STATUS_CODE: 0|1|..."
|
||||
match = re.match(r'INSTRUMENTATION_STATUS_CODE:\s*([+-]?\d+)', line)
|
||||
if match:
|
||||
status = match.group(1)
|
||||
full_name = "%s.%s" % (self.class_name, self.test_name)
|
||||
if full_name == self.current_full_name:
|
||||
if status == '0':
|
||||
message = ''
|
||||
status = 'PASS'
|
||||
self.pass_count += 1
|
||||
else:
|
||||
message = 'status %s' % status
|
||||
status = 'FAIL'
|
||||
self.fail_count += 1
|
||||
self.log.test_end(full_name, status, expected, message)
|
||||
self.test_started = False
|
||||
else:
|
||||
if self.test_started:
|
||||
# next test started without reporting previous status
|
||||
self.fail_count += 1
|
||||
self.log.test_end(self.current_full_name, 'FAIL', expected,
|
||||
"missing test completion status")
|
||||
self.log.test_start(full_name)
|
||||
self.test_started = True
|
||||
self.current_full_name = full_name
|
||||
|
||||
# Ideally all test names should be reported to suite_start, but these test
|
||||
# names are not known in advance.
|
||||
self.log.suite_start(["geckoview-junit"])
|
||||
try:
|
||||
cmd = self.build_command_line(test_filters)
|
||||
self.log.info("launching %s" % cmd)
|
||||
self.device.shell(cmd, timeout=self.options.max_time, stdout_callback=callback)
|
||||
self.log.info("Passed: %d" % self.pass_count)
|
||||
self.log.info("Failed: %d" % self.fail_count)
|
||||
finally:
|
||||
self.log.suite_end()
|
||||
|
||||
if self.check_for_crashes():
|
||||
self.fail_count = 1
|
||||
|
||||
return 1 if self.fail_count else 0
|
||||
|
||||
def check_for_crashes(self):
|
||||
logcat = self.device.get_logcat()
|
||||
if logcat:
|
||||
if mozcrash.check_for_java_exception(logcat, self.current_full_name):
|
||||
return True
|
||||
symbols_path = self.options.symbolsPath
|
||||
try:
|
||||
dump_dir = tempfile.mkdtemp()
|
||||
remote_dir = posixpath.join(self.remote_profile, 'minidumps')
|
||||
if not self.device.is_dir(remote_dir):
|
||||
# If crash reporting is enabled (MOZ_CRASHREPORTER=1), the
|
||||
# minidumps directory is automatically created when the app
|
||||
# (first) starts, so its lack of presence is a hint that
|
||||
# something went wrong.
|
||||
print "Automation Error: No crash directory (%s) found on remote device" % \
|
||||
remote_dir
|
||||
return True
|
||||
self.device.pull(remote_dir, dump_dir)
|
||||
crashed = mozcrash.log_crashes(self.log, dump_dir, symbols_path,
|
||||
test=self.current_full_name)
|
||||
finally:
|
||||
try:
|
||||
shutil.rmtree(dump_dir)
|
||||
except Exception:
|
||||
self.log.warning("unable to remove directory: %s" % dump_dir)
|
||||
return crashed
|
||||
|
||||
|
||||
class JunitArgumentParser(argparse.ArgumentParser):
|
||||
"""
|
||||
An argument parser for geckoview-junit.
|
||||
"""
|
||||
def __init__(self, **kwargs):
|
||||
super(JunitArgumentParser, self).__init__(**kwargs)
|
||||
|
||||
self.add_argument("--appname",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="app",
|
||||
default="org.mozilla.geckoview.test",
|
||||
help="Test package name.")
|
||||
self.add_argument("--adbpath",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="adbPath",
|
||||
default=None,
|
||||
help="Path to adb executable.")
|
||||
self.add_argument("--deviceSerial",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="deviceSerial",
|
||||
help="adb serial number of remote device.")
|
||||
self.add_argument("--remoteTestRoot",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteTestRoot",
|
||||
help="Remote directory to use as test root "
|
||||
"(eg. /mnt/sdcard/tests or /data/local/tests).")
|
||||
self.add_argument("--disable-e10s",
|
||||
action="store_false",
|
||||
dest="e10s",
|
||||
default=True,
|
||||
help="Disable multiprocess mode in test app.")
|
||||
self.add_argument("--max-time",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="max_time",
|
||||
default="2400",
|
||||
help="Max time in seconds to wait for tests (default 2400s).")
|
||||
self.add_argument("--runner",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="runner",
|
||||
default="android.support.test.runner.AndroidJUnitRunner",
|
||||
help="Test runner name.")
|
||||
self.add_argument("--symbols-path",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="symbolsPath",
|
||||
default=None,
|
||||
help="Path to directory containing breakpad symbols, "
|
||||
"or the URL of a zip file containing symbols.")
|
||||
self.add_argument("--utility-path",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="utilityPath",
|
||||
default=None,
|
||||
help="Path to directory containing host utility programs.")
|
||||
# Additional options for server.
|
||||
self.add_argument("--certificate-path",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="certPath",
|
||||
default=None,
|
||||
help="Path to directory containing certificate store."),
|
||||
self.add_argument("--http-port",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="httpPort",
|
||||
default=DEFAULT_PORTS['http'],
|
||||
help="Port of the web server for http traffic.")
|
||||
self.add_argument("--remote-webserver",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="remoteWebServer",
|
||||
help="IP address of the webserver.")
|
||||
self.add_argument("--ssl-port",
|
||||
action="store",
|
||||
type=str,
|
||||
dest="sslPort",
|
||||
default=DEFAULT_PORTS['https'],
|
||||
help="Port of the web server for https traffic.")
|
||||
# Remaining arguments are test filters.
|
||||
self.add_argument("test_filters",
|
||||
nargs="*",
|
||||
help="Test filter(s): class and/or method names of test(s) to run.")
|
||||
|
||||
mozlog.commandline.add_logging_group(self)
|
||||
|
||||
|
||||
def run_test_harness(parser, options):
|
||||
if hasattr(options, 'log'):
|
||||
log = options.log
|
||||
else:
|
||||
log = mozlog.commandline.setup_logging("runjunit", options,
|
||||
{"tbpl": sys.stdout})
|
||||
runner = JUnitTestRunner(log, options)
|
||||
result = -1
|
||||
try:
|
||||
result = runner.run_tests(options.test_filters)
|
||||
except KeyboardInterrupt:
|
||||
log.info("runjunit.py | Received keyboard interrupt")
|
||||
result = -1
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
log.error(
|
||||
"runjunit.py | Received unexpected exception while running tests")
|
||||
result = 1
|
||||
finally:
|
||||
runner.cleanup()
|
||||
return result
|
||||
|
||||
|
||||
def main(args=sys.argv[1:]):
|
||||
parser = JunitArgumentParser()
|
||||
options = parser.parse_args()
|
||||
return run_test_harness(parser, options)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
@ -622,12 +622,10 @@ AddonManagerStartup::EncodeBlob(JS::HandleValue value, JSContext* cx, JS::Mutabl
|
||||
|
||||
nsAutoCString scData;
|
||||
|
||||
auto& data = holder.Data();
|
||||
auto iter = data.Iter();
|
||||
while (!iter.Done()) {
|
||||
scData.Append(nsDependentCSubstring(iter.Data(), iter.RemainingInSegment()));
|
||||
iter.Advance(data, iter.RemainingInSegment());
|
||||
}
|
||||
holder.Data().ForEachDataChunk([&](const char* aData, size_t aSize) {
|
||||
scData.Append(nsDependentCSubstring(aData, aSize));
|
||||
return true;
|
||||
});
|
||||
|
||||
nsCString lz4;
|
||||
MOZ_TRY_VAR(lz4, EncodeLZ4(scData, STRUCTURED_CLONE_MAGIC));
|
||||
|
@ -7,16 +7,20 @@
|
||||
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
const PREFS = {
|
||||
"pluginFlashBlockingCheckbox": "plugins.flashBlock.enabled",
|
||||
"pluginEnableProtectedModeCheckbox": "dom.ipc.plugins.flash.disable-protected-mode",
|
||||
"pluginFlashBlockingCheckbox":
|
||||
{ pref: "plugins.flashBlock.enabled", invert: false },
|
||||
"pluginEnableProtectedModeCheckbox":
|
||||
{ pref: "dom.ipc.plugins.flash.disable-protected-mode", invert: true },
|
||||
};
|
||||
|
||||
function init() {
|
||||
for (let id of Object.keys(PREFS)) {
|
||||
let checkbox = document.getElementById(id);
|
||||
checkbox.checked = Services.prefs.getBoolPref(PREFS[id]);
|
||||
var prefVal = Services.prefs.getBoolPref(PREFS[id].pref);
|
||||
checkbox.checked = PREFS[id].invert ? !prefVal : prefVal;
|
||||
checkbox.addEventListener("command", () => {
|
||||
Services.prefs.setBoolPref(PREFS[id], checkbox.checked);
|
||||
Services.prefs.setBoolPref(PREFS[id].pref,
|
||||
PREFS[id].invert ? !checkbox.checked : checkbox.checked);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
static bool OnElCapitanOrLater();
|
||||
static bool OnSierraOrLater();
|
||||
static bool OnHighSierraOrLater();
|
||||
static bool OnSierraExactly();
|
||||
|
||||
static bool IsAtLeastVersion(int32_t aMajor, int32_t aMinor, int32_t aBugFix=0);
|
||||
|
||||
@ -41,9 +42,9 @@ private:
|
||||
static int32_t mOSXVersion;
|
||||
};
|
||||
|
||||
// C-callable helper for cairo-quartz-font.c
|
||||
// C-callable helper for cairo-quartz-font.c and SkFontHost_mac.cpp
|
||||
extern "C" {
|
||||
bool Gecko_OnSierraOrLater();
|
||||
bool Gecko_OnSierraExactly();
|
||||
}
|
||||
|
||||
#endif // nsCocoaFeatures_h_
|
||||
|
@ -174,11 +174,18 @@ nsCocoaFeatures::OnHighSierraOrLater()
|
||||
return (OSXVersion() >= MAC_OS_X_VERSION_10_13_HEX);
|
||||
}
|
||||
|
||||
/* Version of OnSierraOrLater as a global function callable from C (cairo) */
|
||||
bool
|
||||
Gecko_OnSierraOrLater()
|
||||
/* static */ bool
|
||||
nsCocoaFeatures::OnSierraExactly()
|
||||
{
|
||||
return nsCocoaFeatures::OnSierraOrLater();
|
||||
return (OSXVersion() >= MAC_OS_X_VERSION_10_12_HEX) &&
|
||||
(OSXVersion() < MAC_OS_X_VERSION_10_13_HEX);
|
||||
}
|
||||
|
||||
/* Version of OnSierraExactly as global function callable from cairo & skia */
|
||||
bool
|
||||
Gecko_OnSierraExactly()
|
||||
{
|
||||
return nsCocoaFeatures::OnSierraExactly();
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -221,8 +221,13 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel)
|
||||
return true;
|
||||
}
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
|
||||
// Avoid starting the GPU process for the initial navigator:blank window.
|
||||
if (mIsEarlyBlankWindow) {
|
||||
// Call BeginPaint/EndPaint or Windows will keep sending us messages.
|
||||
::BeginPaint(mWnd, &ps);
|
||||
::EndPaint(mWnd, &ps);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -233,8 +238,6 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel)
|
||||
}
|
||||
mLastPaintBounds = mBounds;
|
||||
|
||||
PAINTSTRUCT ps;
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
if (!aDC && (eTransparencyTransparent == mTransparencyMode))
|
||||
{
|
||||
|
@ -125,14 +125,12 @@ public:
|
||||
}
|
||||
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
void Check()
|
||||
{
|
||||
for (auto arena = mHead.next; arena; arena = arena->next) {
|
||||
arena->canary.Check();
|
||||
if (mCurrent) {
|
||||
mCurrent->canary.Check();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
struct ArenaHeader
|
||||
|
Loading…
Reference in New Issue
Block a user