mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 15:25:52 +00:00
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
commit
6d17917258
@ -1,6 +1,5 @@
|
||||
[DEFAULT]
|
||||
firefox-appdir = browser
|
||||
headless = true
|
||||
head = head.js
|
||||
support-files =
|
||||
../fixtures/**
|
||||
|
@ -342,6 +342,8 @@ class FlexboxInspector {
|
||||
this.highlighters.showFlexboxHighlighter(flexbox.flexContainer.nodeFront);
|
||||
}
|
||||
|
||||
this._overlayColor = color;
|
||||
|
||||
const currentUrl = this.inspector.target.url;
|
||||
// Get the hostname, if there is no hostname, fall back on protocol
|
||||
// ex: `data:` uri, and `about:` pages
|
||||
|
@ -122,13 +122,9 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
|
||||
// In alphabetical order
|
||||
// EXT_
|
||||
case WebGLExtensionID::EXT_texture_compression_bptc:
|
||||
if (!gfxPrefs::WebGLDraftExtensionsEnabled())
|
||||
return false;
|
||||
return WebGLExtensionCompressedTextureBPTC::IsSupported(this);
|
||||
|
||||
case WebGLExtensionID::EXT_texture_compression_rgtc:
|
||||
if (!gfxPrefs::WebGLDraftExtensionsEnabled())
|
||||
return false;
|
||||
return WebGLExtensionCompressedTextureRGTC::IsSupported(this);
|
||||
|
||||
case WebGLExtensionID::EXT_texture_filter_anisotropic:
|
||||
|
@ -10,11 +10,8 @@
|
||||
<script>
|
||||
|
||||
'use strict';
|
||||
EnsureExt('EXT_texture_compression_bptc', false);
|
||||
EnsureExt('EXT_texture_compression_bptc');
|
||||
|
||||
Lastly_WithDraftExtsEnabled(() => {
|
||||
EnsureExt('EXT_texture_compression_bptc', true);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -10,11 +10,7 @@
|
||||
<script>
|
||||
|
||||
'use strict';
|
||||
EnsureExt('EXT_texture_compression_rgtc', false);
|
||||
|
||||
Lastly_WithDraftExtsEnabled(() => {
|
||||
EnsureExt('EXT_texture_compression_rgtc', true);
|
||||
});
|
||||
EnsureExt('EXT_texture_compression_rgtc');
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -41,6 +41,8 @@ var defaultExts = [
|
||||
['EXT_color_buffer_half_float' , [MACHINE_SPECIFIC, FORBID ]],
|
||||
['EXT_disjoint_timer_query' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
['EXT_sRGB' , [MACHINE_SPECIFIC, FORBID ]],
|
||||
['EXT_texture_compression_bptc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
['EXT_texture_compression_rgtc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
['WEBGL_color_buffer_float' , [MACHINE_SPECIFIC, FORBID ]],
|
||||
['WEBGL_compressed_texture_astc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
['WEBGL_compressed_texture_atc' , [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
@ -51,8 +53,6 @@ var defaultExts = [
|
||||
];
|
||||
|
||||
var draftExts = [
|
||||
['EXT_texture_compression_bptc', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
['EXT_texture_compression_rgtc', [MACHINE_SPECIFIC, MACHINE_SPECIFIC]],
|
||||
];
|
||||
|
||||
var nonImplementedExts = [
|
||||
|
@ -28,6 +28,7 @@ support-files =
|
||||
unit/test_blob_file_backed.js
|
||||
unit/test_blocked_order.js
|
||||
unit/test_clear.js
|
||||
unit/test_clone_before_key_evaluation.js
|
||||
unit/test_complex_keyPaths.js
|
||||
unit/test_constraint_error_messages.js
|
||||
unit/test_count.js
|
||||
@ -138,6 +139,7 @@ skip-if = e10s && os == 'win' && os_version == '6.1' # Bug 1342415
|
||||
[test_blocked_order.html]
|
||||
[test_bug937006.html]
|
||||
[test_clear.html]
|
||||
[test_clone_before_key_evaluation.html]
|
||||
[test_complex_keyPaths.html]
|
||||
[test_constraint_error_messages.html]
|
||||
[test_count.html]
|
||||
|
18
dom/indexedDB/test/test_clone_before_key_evaluation.html
Normal file
18
dom/indexedDB/test/test_clone_before_key_evaluation.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<title>Indexed Database Test</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
<script type="text/javascript" src="unit/test_clone_before_key_evaluation.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="runTest();"></body>
|
||||
|
||||
</html>
|
131
dom/indexedDB/test/unit/test_clone_before_key_evaluation.js
Normal file
131
dom/indexedDB/test/unit/test_clone_before_key_evaluation.js
Normal file
@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var testGenerator = testSteps();
|
||||
|
||||
function* testSteps()
|
||||
{
|
||||
const name = this.window ? window.location.pathname
|
||||
: "test_clone_before_key_evaluation.js";
|
||||
const objectStoreInfo = {
|
||||
name: "customers",
|
||||
options: { keyPath: "ssn" },
|
||||
};
|
||||
const indexInfo = {
|
||||
name: "customerIndex",
|
||||
keyPath: ["id", "email", "name"],
|
||||
options: { unique: false },
|
||||
};
|
||||
|
||||
for (let test of [1, 2]) {
|
||||
info("Opening database");
|
||||
|
||||
let request = indexedDB.open(name);
|
||||
request.onerror = errorHandler;
|
||||
request.onupgradeneeded = continueToNextStepSync;
|
||||
request.onsuccess = unexpectedSuccessHandler;
|
||||
yield undefined;
|
||||
|
||||
// upgradeneeded
|
||||
|
||||
request.onupgradeneeded = unexpectedSuccessHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
|
||||
let db = request.result;
|
||||
db.onerror = errorHandler;
|
||||
|
||||
info("Creating objectStore");
|
||||
|
||||
let objectStore = db.createObjectStore(objectStoreInfo.name,
|
||||
objectStoreInfo.options);
|
||||
|
||||
info("Creating index");
|
||||
|
||||
objectStore.createIndex(indexInfo.name,
|
||||
indexInfo.keyPath,
|
||||
indexInfo.options);
|
||||
|
||||
switch (test) {
|
||||
case 1: {
|
||||
info("Adding data with a getter");
|
||||
|
||||
let idCount = 0;
|
||||
|
||||
const customerData = {
|
||||
ssn: "444-44-4444", name: "Bill", age: 25, email: "bill@company.com",
|
||||
get id()
|
||||
{
|
||||
idCount++;
|
||||
objectStore.deleteIndex(indexInfo.name);
|
||||
return "ID_001";
|
||||
},
|
||||
};
|
||||
|
||||
objectStore.add(customerData);
|
||||
|
||||
ok(idCount == 1, "Getter was called only once");
|
||||
|
||||
ok(objectStore.indexNames.length == 0, "Index was removed");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
info("Adding data with a prototype getter");
|
||||
|
||||
let idCount = 0;
|
||||
|
||||
const customerData = {
|
||||
ssn: "555-55-5555", name: "Joe", age: 52, email: "joe@company.com",
|
||||
};
|
||||
|
||||
Object.defineProperty(Object.prototype, "id", {
|
||||
get() {
|
||||
idCount++;
|
||||
objectStore.deleteIndex(indexInfo.name);
|
||||
return "ID_002";
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
objectStore.add(customerData);
|
||||
|
||||
ok(idCount == 0, "Prototype getter was not called");
|
||||
|
||||
// Paranoid checks, just to be sure that the protype getter is called
|
||||
// in standard JS.
|
||||
|
||||
let id = customerData.id;
|
||||
|
||||
ok(id == "ID_002", "Prototype getter returned correct value");
|
||||
ok(idCount == 1, "Prototype getter was called only once");
|
||||
|
||||
delete Object.prototype.id;
|
||||
|
||||
id = customerData.id;
|
||||
|
||||
ok(id == undefined, "Prototype getter was removed");
|
||||
|
||||
ok(objectStore.indexNames.length == 0, "Index was removed");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yield undefined;
|
||||
|
||||
// success
|
||||
|
||||
db.close();
|
||||
|
||||
request = indexedDB.deleteDatabase(name);
|
||||
request.onerror = errorHandler;
|
||||
request.onsuccess = continueToNextStepSync;
|
||||
yield undefined;
|
||||
}
|
||||
|
||||
finishTest();
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
[test_autoIncrement_indexes.js]
|
||||
[test_blocked_order.js]
|
||||
[test_clear.js]
|
||||
[test_clone_before_key_evaluation.js]
|
||||
[test_complex_keyPaths.js]
|
||||
[test_count.js]
|
||||
[test_create_index.js]
|
||||
|
@ -35,6 +35,14 @@ AsyncImagePipelineManager::AsyncImagePipeline::AsyncImagePipeline()
|
||||
, mMixBlendMode(wr::MixBlendMode::Normal)
|
||||
{}
|
||||
|
||||
AsyncImagePipelineManager::PipelineUpdates::PipelineUpdates(RefPtr<wr::WebRenderPipelineInfo> aPipelineInfo,
|
||||
const uint64_t aUpdatesCount,
|
||||
const bool aRendered)
|
||||
: mPipelineInfo(aPipelineInfo)
|
||||
, mUpdatesCount(aUpdatesCount)
|
||||
, mRendered(aRendered)
|
||||
{}
|
||||
|
||||
AsyncImagePipelineManager::AsyncImagePipelineManager(already_AddRefed<wr::WebRenderAPI>&& aApi)
|
||||
: mApi(aApi)
|
||||
, mIdNamespace(mApi->GetNamespace())
|
||||
@ -553,7 +561,7 @@ AsyncImagePipelineManager::HoldExternalImage(const wr::PipelineId& aPipelineId,
|
||||
}
|
||||
|
||||
void
|
||||
AsyncImagePipelineManager::NotifyPipelinesUpdated(const wr::WrPipelineInfo& aInfo, bool aRender)
|
||||
AsyncImagePipelineManager::NotifyPipelinesUpdated(RefPtr<wr::WebRenderPipelineInfo> aInfo, bool aRender)
|
||||
{
|
||||
// This is called on the render thread, so we just stash the data into
|
||||
// UpdatesQueue and process it later on the compositor thread.
|
||||
@ -561,18 +569,7 @@ AsyncImagePipelineManager::NotifyPipelinesUpdated(const wr::WrPipelineInfo& aInf
|
||||
|
||||
// Increment the count when render happens.
|
||||
uint64_t currCount = aRender ? ++mUpdatesCount : mUpdatesCount;
|
||||
auto updates = MakeUnique<PipelineUpdates>(currCount, aRender);
|
||||
|
||||
for (uintptr_t i = 0; i < aInfo.epochs.length; i++) {
|
||||
updates->mQueue.emplace(std::make_pair(
|
||||
aInfo.epochs.data[i].pipeline_id,
|
||||
Some(aInfo.epochs.data[i].epoch)));
|
||||
}
|
||||
for (uintptr_t i = 0; i < aInfo.removed_pipelines.length; i++) {
|
||||
updates->mQueue.emplace(std::make_pair(
|
||||
aInfo.removed_pipelines.data[i],
|
||||
Nothing()));
|
||||
}
|
||||
auto updates = MakeUnique<PipelineUpdates>(aInfo, currCount, aRender);
|
||||
|
||||
{
|
||||
// Scope lock to push UpdatesQueue to mUpdatesQueues.
|
||||
@ -604,13 +601,7 @@ AsyncImagePipelineManager::ProcessPipelineUpdates()
|
||||
UniquePtr<PipelineUpdates> updates;
|
||||
|
||||
while (true) {
|
||||
// Clear updates if it is empty. It is a preparation for next PipelineUpdates handling.
|
||||
if (updates && updates->mQueue.empty()) {
|
||||
updates = nullptr;
|
||||
}
|
||||
|
||||
// Get new PipelineUpdates if necessary.
|
||||
if (!updates) {
|
||||
{
|
||||
// Scope lock to extract UpdatesQueue from mUpdatesQueues.
|
||||
MutexAutoLock lock(mUpdatesLock);
|
||||
if (mUpdatesQueues.empty()) {
|
||||
@ -628,19 +619,16 @@ AsyncImagePipelineManager::ProcessPipelineUpdates()
|
||||
}
|
||||
MOZ_ASSERT(updates);
|
||||
|
||||
if (updates->mQueue.empty()) {
|
||||
// Try next PipelineUpdates.
|
||||
continue;
|
||||
auto& info = updates->mPipelineInfo->Raw();
|
||||
|
||||
for (uintptr_t i = 0; i < info.epochs.length; i++) {
|
||||
ProcessPipelineRendered(info.epochs.data[i].pipeline_id,
|
||||
info.epochs.data[i].epoch,
|
||||
updates->mUpdatesCount);
|
||||
}
|
||||
|
||||
wr::PipelineId pipelineId = updates->mQueue.front().first;
|
||||
Maybe<wr::Epoch> epoch = updates->mQueue.front().second;
|
||||
updates->mQueue.pop();
|
||||
|
||||
if (epoch.isSome()) {
|
||||
ProcessPipelineRendered(pipelineId, *epoch, updates->mUpdatesCount);
|
||||
} else {
|
||||
ProcessPipelineRemoved(pipelineId, updates->mUpdatesCount);
|
||||
for (uintptr_t i = 0; i < info.removed_pipelines.length; i++) {
|
||||
ProcessPipelineRemoved(info.removed_pipelines.data[i],
|
||||
updates->mUpdatesCount);
|
||||
}
|
||||
}
|
||||
CheckForTextureHostsNotUsedByGPU();
|
||||
|
@ -23,6 +23,7 @@ namespace mozilla {
|
||||
namespace wr {
|
||||
class DisplayListBuilder;
|
||||
class WebRenderAPI;
|
||||
class WebRenderPipelineInfo;
|
||||
}
|
||||
|
||||
namespace layers {
|
||||
@ -56,7 +57,7 @@ public:
|
||||
// This is called from the Renderer thread to notify this class about the
|
||||
// pipelines in the most recently completed render. A copy of the update
|
||||
// information is put into mUpdatesQueue.
|
||||
void NotifyPipelinesUpdated(const wr::WrPipelineInfo& aInfo, bool aRender);
|
||||
void NotifyPipelinesUpdated(RefPtr<wr::WebRenderPipelineInfo> aInfo, bool aRender);
|
||||
|
||||
// This is run on the compositor thread to process mUpdatesQueue. We make
|
||||
// this a public entry point because we need to invoke it from other places.
|
||||
@ -247,10 +248,9 @@ private:
|
||||
// Used for checking if PipelineUpdates could be processed.
|
||||
Atomic<uint64_t> mUpdatesCount;
|
||||
struct PipelineUpdates {
|
||||
PipelineUpdates(const uint64_t aUpdatesCount, const bool aRendered)
|
||||
: mUpdatesCount(aUpdatesCount)
|
||||
, mRendered(aRendered)
|
||||
{}
|
||||
PipelineUpdates(RefPtr<wr::WebRenderPipelineInfo> aPipelineInfo,
|
||||
const uint64_t aUpdatesCount,
|
||||
const bool aRendered);
|
||||
bool NeedsToWait(const uint64_t aUpdatesCount) {
|
||||
MOZ_ASSERT(mUpdatesCount <= aUpdatesCount);
|
||||
if (mUpdatesCount == aUpdatesCount && !mRendered) {
|
||||
@ -259,14 +259,9 @@ private:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
RefPtr<wr::WebRenderPipelineInfo> mPipelineInfo;
|
||||
const uint64_t mUpdatesCount;
|
||||
const bool mRendered;
|
||||
// Queue to store rendered pipeline epoch information. This is populated from
|
||||
// the Renderer thread after a render, and is read from the compositor thread
|
||||
// to free resources (e.g. textures) that are no longer needed. Each entry
|
||||
// in the queue is a pair that holds the pipeline id and Some(x) for
|
||||
// a render of epoch x, or Nothing() for a removed pipeline.
|
||||
std::queue<std::pair<wr::PipelineId, Maybe<wr::Epoch>>> mQueue;
|
||||
};
|
||||
std::queue<UniquePtr<PipelineUpdates>> mUpdatesQueues;
|
||||
|
||||
|
@ -425,7 +425,7 @@ RenderThread::UpdateAndRender(wr::WindowId aWindowId,
|
||||
// removed the relevant renderer. And after that happens we should never reach
|
||||
// this code at all; it would bail out at the mRenderers.find check above.
|
||||
MOZ_ASSERT(pipelineMgr);
|
||||
pipelineMgr->NotifyPipelinesUpdated(info->Raw(), aRender);
|
||||
pipelineMgr->NotifyPipelinesUpdated(info, aRender);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -60,6 +60,10 @@ DecoderFactory::GetDecoderType(const char* aMimeType)
|
||||
} else if (!strcmp(aMimeType, IMAGE_BMP_MS)) {
|
||||
type = DecoderType::BMP;
|
||||
|
||||
// BMP_CLIPBOARD
|
||||
} else if (!strcmp(aMimeType, IMAGE_BMP_MS_CLIPBOARD)) {
|
||||
type = DecoderType::BMP_CLIPBOARD;
|
||||
|
||||
// ICO
|
||||
} else if (!strcmp(aMimeType, IMAGE_ICO)) {
|
||||
type = DecoderType::ICO;
|
||||
@ -103,6 +107,9 @@ DecoderFactory::GetDecoder(DecoderType aType,
|
||||
case DecoderType::BMP:
|
||||
decoder = new nsBMPDecoder(aImage);
|
||||
break;
|
||||
case DecoderType::BMP_CLIPBOARD:
|
||||
decoder = new nsBMPDecoder(aImage, /* aForClipboard */ true);
|
||||
break;
|
||||
case DecoderType::ICO:
|
||||
decoder = new nsICODecoder(aImage);
|
||||
break;
|
||||
|
@ -35,6 +35,7 @@ enum class DecoderType
|
||||
GIF,
|
||||
JPEG,
|
||||
BMP,
|
||||
BMP_CLIPBOARD,
|
||||
ICO,
|
||||
ICON,
|
||||
WEBP,
|
||||
|
@ -185,9 +185,11 @@ nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, State aState, size_t aLength)
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor for normal BMP files.
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage)
|
||||
: nsBMPDecoder(aImage, State::FILE_HEADER, FILE_HEADER_LENGTH)
|
||||
// Constructor for normal BMP files or from the clipboard.
|
||||
nsBMPDecoder::nsBMPDecoder(RasterImage* aImage, bool aForClipboard)
|
||||
: nsBMPDecoder(aImage,
|
||||
aForClipboard ? State::CLIPBOARD_HEADER : State::FILE_HEADER,
|
||||
aForClipboard ? BIHSIZE_FIELD_LENGTH : FILE_HEADER_LENGTH)
|
||||
{
|
||||
}
|
||||
|
||||
@ -455,6 +457,7 @@ nsBMPDecoder::DoDecode(SourceBufferIterator& aIterator, IResumable* aOnResume)
|
||||
[=](State aState, const char* aData, size_t aLength) {
|
||||
switch (aState) {
|
||||
case State::FILE_HEADER: return ReadFileHeader(aData, aLength);
|
||||
case State::CLIPBOARD_HEADER: return ReadClipboardHeader(aData, aLength);
|
||||
case State::INFO_HEADER_SIZE: return ReadInfoHeaderSize(aData, aLength);
|
||||
case State::INFO_HEADER_REST: return ReadInfoHeaderRest(aData, aLength);
|
||||
case State::BITFIELDS: return ReadBitfields(aData, aLength);
|
||||
@ -488,6 +491,14 @@ nsBMPDecoder::ReadFileHeader(const char* aData, size_t aLength)
|
||||
return Transition::To(State::INFO_HEADER_SIZE, BIHSIZE_FIELD_LENGTH);
|
||||
}
|
||||
|
||||
LexerTransition<nsBMPDecoder::State>
|
||||
nsBMPDecoder::ReadClipboardHeader(const char* aData, size_t aLength)
|
||||
{
|
||||
// With the clipboard, the data offset is the header length.
|
||||
mH.mDataOffset = LittleEndian::readUint32(aData);
|
||||
return ReadInfoHeaderSize(aData, aLength);
|
||||
}
|
||||
|
||||
// We read the info header in two steps: (a) read the mBIHSize field to
|
||||
// determine how long the header is; (b) read the rest of the header.
|
||||
LexerTransition<nsBMPDecoder::State>
|
||||
|
@ -157,6 +157,7 @@ private:
|
||||
|
||||
enum class State {
|
||||
FILE_HEADER,
|
||||
CLIPBOARD_HEADER,
|
||||
INFO_HEADER_SIZE,
|
||||
INFO_HEADER_REST,
|
||||
BITFIELDS,
|
||||
@ -169,8 +170,8 @@ private:
|
||||
RLE_ABSOLUTE
|
||||
};
|
||||
|
||||
// This is the constructor used for normal BMP images.
|
||||
explicit nsBMPDecoder(RasterImage* aImage);
|
||||
// This is the constructor used for normal and clipboard BMP images.
|
||||
explicit nsBMPDecoder(RasterImage* aImage, bool aForClipboard = false);
|
||||
|
||||
// This is the constructor used for BMP resources in ICO images.
|
||||
nsBMPDecoder(RasterImage* aImage, uint32_t aDataOffset);
|
||||
@ -185,6 +186,7 @@ private:
|
||||
void FinishRow();
|
||||
|
||||
LexerTransition<State> ReadFileHeader(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadClipboardHeader(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadInfoHeaderSize(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadInfoHeaderRest(const char* aData, size_t aLength);
|
||||
LexerTransition<State> ReadBitfields(const char* aData, size_t aLength);
|
||||
|
@ -68,6 +68,21 @@ enum class TraceKind
|
||||
};
|
||||
const static uintptr_t OutOfLineTraceKindMask = 0x07;
|
||||
|
||||
// Returns true if the JS::TraceKind is one the cycle collector cares about.
|
||||
// Everything used as WeakMap key should be listed here, to represent the key
|
||||
// in cycle collector's graph, otherwise the key is considered to be pointed
|
||||
// from somewhere unknown, and results in leaking the subgraph which contains
|
||||
// the key.
|
||||
// See the comments in NoteWeakMapsTracer::trace for more details.
|
||||
inline constexpr bool IsCCTraceKind(JS::TraceKind aKind)
|
||||
{
|
||||
return aKind == JS::TraceKind::Object ||
|
||||
aKind == JS::TraceKind::Script ||
|
||||
aKind == JS::TraceKind::LazyScript ||
|
||||
aKind == JS::TraceKind::Scope ||
|
||||
aKind == JS::TraceKind::RegExpShared;
|
||||
}
|
||||
|
||||
#define ASSERT_TRACE_KIND(tk) \
|
||||
static_assert((uintptr_t(tk) & OutOfLineTraceKindMask) == OutOfLineTraceKindMask, \
|
||||
"mask bits are set")
|
||||
@ -89,7 +104,7 @@ struct MapTypeToTraceKind {
|
||||
// When this header is used outside SpiderMonkey, the class definitions are not
|
||||
// available, so the following table containing all public GC types is used.
|
||||
#define JS_FOR_EACH_TRACEKIND(D) \
|
||||
/* PrettyName TypeName AddToCCKind */ \
|
||||
/* PrettyName TypeName IsCCTraceKind */ \
|
||||
D(BaseShape, js::BaseShape, true) \
|
||||
D(JitCode, js::jit::JitCode, true) \
|
||||
D(LazyScript, js::LazyScript, true) \
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "gc/WeakMap.h"
|
||||
|
||||
#include "js/TraceKind.h"
|
||||
#include "vm/JSContext.h"
|
||||
|
||||
namespace js {
|
||||
@ -28,6 +29,13 @@ template <class K, class V>
|
||||
WeakMap<K, V>::WeakMap(JSContext* cx, JSObject* memOf)
|
||||
: Base(cx->zone()), WeakMapBase(memOf, cx->zone())
|
||||
{
|
||||
using ElemType = typename K::ElementType;
|
||||
using NonPtrType = typename mozilla::RemovePointer<ElemType>::Type;
|
||||
// The object's TraceKind needs to be added to CC graph if this object is
|
||||
// used as a WeakMap key. See the comments for IsCCTraceKind for details.
|
||||
static_assert(JS::IsCCTraceKind(NonPtrType::TraceKind),
|
||||
"Object's TraceKind should be added to CC graph.");
|
||||
|
||||
zone()->gcWeakMapList().insertFront(this);
|
||||
marked = JS::IsIncrementalGCInProgress(TlsContext.get());
|
||||
}
|
||||
|
@ -208,95 +208,104 @@ for (var foldOffsets = 0; foldOffsets <= 1; foldOffsets++) {
|
||||
wasmFailValidateText('(module (memory 2 1))', /maximum length 1 is less than initial length 2/);
|
||||
|
||||
// Test bounds checks and edge cases.
|
||||
const align = 0;
|
||||
|
||||
for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
|
||||
// Accesses of 1 byte.
|
||||
let lastValidIndex = 0x10000 - 1 - offset;
|
||||
for (let align of [0,1,2,4]) {
|
||||
|
||||
testLoad('i32', '8_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '8_s', lastValidIndex + 1, offset, align);
|
||||
for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
|
||||
// Accesses of 1 byte.
|
||||
let lastValidIndex = 0x10000 - 1 - offset;
|
||||
|
||||
testLoad('i32', '8_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '8_u', lastValidIndex + 1, offset, align);
|
||||
if (align < 2) {
|
||||
testLoad('i32', '8_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '8_s', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i32', '8', lastValidIndex, offset, align, -42);
|
||||
testStoreOOB('i32', '8', lastValidIndex + 1, offset, align, -42);
|
||||
testLoad('i32', '8_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '8_u', lastValidIndex + 1, offset, align);
|
||||
|
||||
// Accesses of 2 bytes.
|
||||
lastValidIndex = 0x10000 - 2 - offset;
|
||||
testStore('i32', '8', lastValidIndex, offset, align, -42);
|
||||
testStoreOOB('i32', '8', lastValidIndex + 1, offset, align, -42);
|
||||
}
|
||||
|
||||
testLoad('i32', '16_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '16_s', lastValidIndex + 1, offset, align);
|
||||
// Accesses of 2 bytes.
|
||||
lastValidIndex = 0x10000 - 2 - offset;
|
||||
|
||||
testLoad('i32', '16_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '16_u', lastValidIndex + 1, offset, align);
|
||||
if (align < 4) {
|
||||
testLoad('i32', '16_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '16_s', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i32', '16', lastValidIndex, offset, align, -32768);
|
||||
testStoreOOB('i32', '16', lastValidIndex + 1, offset, align, -32768);
|
||||
testLoad('i32', '16_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '16_u', lastValidIndex + 1, offset, align);
|
||||
|
||||
// Accesses of 4 bytes.
|
||||
lastValidIndex = 0x10000 - 4 - offset;
|
||||
testStore('i32', '16', lastValidIndex, offset, align, -32768);
|
||||
testStoreOOB('i32', '16', lastValidIndex + 1, offset, align, -32768);
|
||||
}
|
||||
|
||||
testLoad('i32', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '', lastValidIndex + 1, offset, align);
|
||||
// Accesses of 4 bytes.
|
||||
lastValidIndex = 0x10000 - 4 - offset;
|
||||
|
||||
testLoad('f32', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('f32', '', lastValidIndex + 1, offset, align);
|
||||
testLoad('i32', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i32', '', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i32', '', lastValidIndex, offset, align, 1337);
|
||||
testStoreOOB('i32', '', lastValidIndex + 1, offset, align, 1337);
|
||||
testLoad('f32', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('f32', '', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('f32', '', lastValidIndex, offset, align, Math.fround(13.37));
|
||||
testStoreOOB('f32', '', lastValidIndex + 1, offset, align, Math.fround(13.37));
|
||||
testStore('i32', '', lastValidIndex, offset, align, 1337);
|
||||
testStoreOOB('i32', '', lastValidIndex + 1, offset, align, 1337);
|
||||
|
||||
// Accesses of 8 bytes.
|
||||
lastValidIndex = 0x10000 - 8 - offset;
|
||||
testStore('f32', '', lastValidIndex, offset, align, Math.fround(13.37));
|
||||
testStoreOOB('f32', '', lastValidIndex + 1, offset, align, Math.fround(13.37));
|
||||
|
||||
testLoad('f64', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('f64', '', lastValidIndex + 1, offset, align);
|
||||
// Accesses of 8 bytes.
|
||||
lastValidIndex = 0x10000 - 8 - offset;
|
||||
|
||||
testStore('f64', '', lastValidIndex, offset, align, 1.23456789);
|
||||
testStoreOOB('f64', '', lastValidIndex + 1, offset, align, 1.23456789);
|
||||
}
|
||||
testLoad('f64', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('f64', '', lastValidIndex + 1, offset, align);
|
||||
|
||||
// Ensure wrapping doesn't apply.
|
||||
offset = 0x7fffffff; // maximum allowed offset that doesn't always throw.
|
||||
for (let index of [0, 1, 2, 3, 0x7fffffff, 0x80000000, 0x80000001]) {
|
||||
testLoadOOB('i32', '8_s', index, offset, align);
|
||||
testLoadOOB('i32', '16_s', index, offset, align);
|
||||
testLoadOOB('i32', '', index, offset, align);
|
||||
testLoadOOB('f32', '', index, offset, align);
|
||||
testLoadOOB('f64', '', index, offset, align);
|
||||
}
|
||||
testStore('f64', '', lastValidIndex, offset, align, 1.23456789);
|
||||
testStoreOOB('f64', '', lastValidIndex + 1, offset, align, 1.23456789);
|
||||
}
|
||||
|
||||
// Ensure out of bounds when the offset is greater than the immediate range.
|
||||
index = 0;
|
||||
for (let offset of [0x80000000, 0xfffffffe, 0xffffffff]) {
|
||||
testLoadOOB('i32', '8_s', index, offset, 1);
|
||||
testLoadOOB('i32', '16_s', index, offset, 1);
|
||||
testLoadOOB('i32', '16_s', index, offset, 2);
|
||||
testLoadOOB('i32', '', index, offset, 1);
|
||||
testLoadOOB('i32', '', index, offset, 4);
|
||||
testLoadOOB('f32', '', index, offset, 1);
|
||||
testLoadOOB('f32', '', index, offset, 4);
|
||||
testLoadOOB('f64', '', index, offset, 1);
|
||||
testLoadOOB('f64', '', index, offset, 8);
|
||||
}
|
||||
// Ensure wrapping doesn't apply.
|
||||
offset = 0x7fffffff; // maximum allowed offset that doesn't always throw.
|
||||
for (let index of [0, 1, 2, 3, 0x7fffffff, 0x80000000, 0x80000001]) {
|
||||
if (align < 2) {
|
||||
testLoadOOB('i32', '8_s', index, offset, align);
|
||||
}
|
||||
if (align < 4) {
|
||||
testLoadOOB('i32', '16_s', index, offset, align);
|
||||
}
|
||||
testLoadOOB('i32', '', index, offset, align);
|
||||
testLoadOOB('f32', '', index, offset, align);
|
||||
testLoadOOB('f64', '', index, offset, align);
|
||||
}
|
||||
|
||||
wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f64"));
|
||||
wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "f64"));
|
||||
// Ensure out of bounds when the offset is greater than the immediate range.
|
||||
index = 0;
|
||||
for (let offset of [0x80000000, 0xfffffffe, 0xffffffff]) {
|
||||
testLoadOOB('i32', '8_s', index, offset, 1);
|
||||
testLoadOOB('i32', '16_s', index, offset, 1);
|
||||
testLoadOOB('i32', '16_s', index, offset, 2);
|
||||
testLoadOOB('i32', '', index, offset, 1);
|
||||
testLoadOOB('i32', '', index, offset, 4);
|
||||
testLoadOOB('f32', '', index, offset, 1);
|
||||
testLoadOOB('f32', '', index, offset, 4);
|
||||
testLoadOOB('f64', '', index, offset, 1);
|
||||
testLoadOOB('f64', '', index, offset, 8);
|
||||
}
|
||||
|
||||
wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
|
||||
wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "f32"));
|
||||
wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f64"));
|
||||
wasmFailValidateText('(module (memory 1) (func (f64.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "f64"));
|
||||
|
||||
wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
|
||||
wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "i32"));
|
||||
wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (i32.const 0))))', mismatchError("i32", "f32"));
|
||||
wasmFailValidateText('(module (memory 1) (func (f32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "f32"));
|
||||
|
||||
// Test high number of registers.
|
||||
function testRegisters() {
|
||||
assertEq(wasmEvalText(
|
||||
`(module
|
||||
wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f32.const 0))))', mismatchError("f32", "i32"));
|
||||
wasmFailValidateText('(module (memory 1) (func (i32.store offset=0 (i32.const 0) (f64.const 0))))', mismatchError("f64", "i32"));
|
||||
|
||||
// Test high number of registers.
|
||||
function testRegisters() {
|
||||
assertEq(wasmEvalText(
|
||||
`(module
|
||||
(memory 1)
|
||||
(data (i32.const 0) "\\00\\01\\02\\03\\04\\05\\06\\07\\08\\09\\0a\\0b\\0c\\0d\\0e\\0f")
|
||||
(data (i32.const 16) "\\f0\\f1\\f2\\f3\\f4\\f5\\f6\\f7\\f8\\f9\\fa\\fb\\fc\\fd\\fe\\ff")
|
||||
@ -329,76 +338,81 @@ for (var foldOffsets = 0; foldOffsets <= 1; foldOffsets++) {
|
||||
)
|
||||
)
|
||||
) (export "" 0))`
|
||||
).exports[""](1), 50464523);
|
||||
}
|
||||
).exports[""](1), 50464523);
|
||||
}
|
||||
|
||||
testRegisters();
|
||||
testRegisters();
|
||||
|
||||
testLoad('i64', '', 0, 0, 0, '0x0706050403020100');
|
||||
testLoad('i64', '', 1, 0, 0, '0x0807060504030201');
|
||||
testLoad('i64', '', 0, 1, 0, '0x0807060504030201');
|
||||
testLoad('i64', '', 1, 1, 4, '0x0908070605040302');
|
||||
testLoad('i64', '', 0, 0, 0, '0x0706050403020100');
|
||||
testLoad('i64', '', 1, 0, 0, '0x0807060504030201');
|
||||
testLoad('i64', '', 0, 1, 0, '0x0807060504030201');
|
||||
testLoad('i64', '', 1, 1, 4, '0x0908070605040302');
|
||||
|
||||
testLoad('i64', '8_s', 16, 0, 0, -0x10);
|
||||
testLoad('i64', '8_u', 16, 0, 0, 0xf0);
|
||||
testLoad('i64', '16_s', 16, 0, 0, -0xe10);
|
||||
testLoad('i64', '16_u', 16, 0, 0, 0xf1f0);
|
||||
testLoad('i64', '32_s', 16, 0, 0, 0xf3f2f1f0 | 0);
|
||||
testLoad('i64', '32_u', 16, 0, 0, '0xf3f2f1f0');
|
||||
testLoad('i64', '8_s', 16, 0, 0, -0x10);
|
||||
testLoad('i64', '8_u', 16, 0, 0, 0xf0);
|
||||
testLoad('i64', '16_s', 16, 0, 0, -0xe10);
|
||||
testLoad('i64', '16_u', 16, 0, 0, 0xf1f0);
|
||||
testLoad('i64', '32_s', 16, 0, 0, 0xf3f2f1f0 | 0);
|
||||
testLoad('i64', '32_u', 16, 0, 0, '0xf3f2f1f0');
|
||||
|
||||
testStore('i64', '', 0, 0, 0, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '', 1, 0, 0, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '', 0, 1, 0, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '', 1, 1, 4, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '8', 0, 0, 0, 0x23);
|
||||
testStore('i64', '16', 0, 0, 0, 0x23);
|
||||
testStore('i64', '32', 0, 0, 0, 0x23);
|
||||
testStore('i64', '', 0, 0, 0, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '', 1, 0, 0, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '', 0, 1, 0, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '', 1, 1, 4, '0xc0c1d3d4e6e7090a');
|
||||
testStore('i64', '8', 0, 0, 0, 0x23);
|
||||
testStore('i64', '16', 0, 0, 0, 0x23);
|
||||
testStore('i64', '32', 0, 0, 0, 0x23);
|
||||
|
||||
for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
|
||||
// Accesses of 1 byte.
|
||||
let lastValidIndex = 0x10000 - 1 - offset;
|
||||
for (let offset of [0, 1, 2, 3, 4, 8, 16, 41, 0xfff8]) {
|
||||
// Accesses of 1 byte.
|
||||
let lastValidIndex = 0x10000 - 1 - offset;
|
||||
|
||||
testLoad('i64', '8_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '8_s', lastValidIndex + 1, offset, align);
|
||||
if (align < 2) {
|
||||
testLoad('i64', '8_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '8_s', lastValidIndex + 1, offset, align);
|
||||
|
||||
testLoad('i64', '8_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '8_u', lastValidIndex + 1, offset, align);
|
||||
testLoad('i64', '8_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '8_u', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i64', '8', lastValidIndex, offset, align, -42);
|
||||
testStoreOOB('i64', '8', lastValidIndex + 1, offset, align, -42);
|
||||
testStore('i64', '8', lastValidIndex, offset, align, -42);
|
||||
testStoreOOB('i64', '8', lastValidIndex + 1, offset, align, -42);
|
||||
}
|
||||
|
||||
// Accesses of 2 bytes.
|
||||
lastValidIndex = 0x10000 - 2 - offset;
|
||||
// Accesses of 2 bytes.
|
||||
lastValidIndex = 0x10000 - 2 - offset;
|
||||
|
||||
testLoad('i64', '16_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '16_s', lastValidIndex + 1, offset, align);
|
||||
if (align < 4) {
|
||||
testLoad('i64', '16_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '16_s', lastValidIndex + 1, offset, align);
|
||||
|
||||
testLoad('i64', '16_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '16_u', lastValidIndex + 1, offset, align);
|
||||
testLoad('i64', '16_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '16_u', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i64', '16', lastValidIndex, offset, align, -32768);
|
||||
testStoreOOB('i64', '16', lastValidIndex + 1, offset, align, -32768);
|
||||
testStore('i64', '16', lastValidIndex, offset, align, -32768);
|
||||
testStoreOOB('i64', '16', lastValidIndex + 1, offset, align, -32768);
|
||||
}
|
||||
|
||||
// Accesses of 4 bytes.
|
||||
lastValidIndex = 0x10000 - 4 - offset;
|
||||
// Accesses of 4 bytes.
|
||||
lastValidIndex = 0x10000 - 4 - offset;
|
||||
|
||||
testLoad('i64', '32_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '32_s', lastValidIndex + 1, offset, align);
|
||||
testLoad('i64', '32_s', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '32_s', lastValidIndex + 1, offset, align);
|
||||
|
||||
testLoad('i64', '32_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '32_u', lastValidIndex + 1, offset, align);
|
||||
testLoad('i64', '32_u', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '32_u', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i64', '32', lastValidIndex, offset, align, 0xf1231337 | 0);
|
||||
testStoreOOB('i64', '32', lastValidIndex + 1, offset, align, 0xf1231337 | 0);
|
||||
testStore('i64', '32', lastValidIndex, offset, align, 0xf1231337 | 0);
|
||||
testStoreOOB('i64', '32', lastValidIndex + 1, offset, align, 0xf1231337 | 0);
|
||||
|
||||
// Accesses of 8 bytes.
|
||||
lastValidIndex = 0x10000 - 8 - offset;
|
||||
// Accesses of 8 bytes.
|
||||
lastValidIndex = 0x10000 - 8 - offset;
|
||||
|
||||
testLoad('i64', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '', lastValidIndex + 1, offset, align);
|
||||
testLoad('i64', '', lastValidIndex, offset, align, 0);
|
||||
testLoadOOB('i64', '', lastValidIndex + 1, offset, align);
|
||||
|
||||
testStore('i64', '', lastValidIndex, offset, align, '0x1234567887654321');
|
||||
testStoreOOB('i64', '', lastValidIndex + 1, offset, align, '0x1234567887654321');
|
||||
testStore('i64', '', lastValidIndex, offset, align, '0x1234567887654321');
|
||||
testStoreOOB('i64', '', lastValidIndex + 1, offset, align, '0x1234567887654321');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,11 @@
|
||||
new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`
|
||||
(module
|
||||
(func (param i64))
|
||||
(func (export "f")
|
||||
i64.const 2
|
||||
i64.const -9223372036854775808
|
||||
i64.mul
|
||||
call 0
|
||||
)
|
||||
)
|
||||
`))).exports.f();
|
35
js/src/jit-test/tests/wasm/regress/unaligned-store64.js
Normal file
35
js/src/jit-test/tests/wasm/regress/unaligned-store64.js
Normal file
@ -0,0 +1,35 @@
|
||||
var ins = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(
|
||||
`(module
|
||||
(memory (export "mem") 1 1)
|
||||
(func (export "store_32_1") (param $ptr i32)
|
||||
(i64.store32 align=1 (get_local $ptr) (i64.const 0xabba1337)))
|
||||
(func (export "store_32_2") (param $ptr i32)
|
||||
(i64.store32 align=2 (get_local $ptr) (i64.const 0xabba1337)))
|
||||
(func (export "store_16") (param $ptr i32)
|
||||
(i64.store16 align=1 (get_local $ptr) (i64.const 0x1337))))`))).exports;
|
||||
|
||||
var mem = new Uint8Array(ins.mem.buffer);
|
||||
|
||||
ins.store_16(1);
|
||||
assertEq(mem[1], 0x37);
|
||||
assertEq(mem[2], 0x13);
|
||||
|
||||
ins.store_32_1(11);
|
||||
assertEq(mem[11], 0x37);
|
||||
assertEq(mem[12], 0x13);
|
||||
assertEq(mem[13], 0xba);
|
||||
assertEq(mem[14], 0xab);
|
||||
|
||||
ins.store_32_2(18);
|
||||
assertEq(mem[18], 0x37);
|
||||
assertEq(mem[19], 0x13);
|
||||
assertEq(mem[20], 0xba);
|
||||
assertEq(mem[21], 0xab);
|
||||
|
||||
// This must also work on all platforms even though we're lying about the
|
||||
// alignment.
|
||||
ins.store_32_2(29);
|
||||
assertEq(mem[29], 0x37);
|
||||
assertEq(mem[30], 0x13);
|
||||
assertEq(mem[31], 0xba);
|
||||
assertEq(mem[32], 0xab);
|
@ -2175,15 +2175,15 @@ void
|
||||
CodeGeneratorARM::emitWasmUnalignedStore(T* lir)
|
||||
{
|
||||
const MWasmStore* mir = lir->mir();
|
||||
Scalar::Type accessType = mir->access().type();
|
||||
|
||||
MIRType valueType = mir->value()->type();
|
||||
Register ptr = ToRegister(lir->ptrCopy());
|
||||
Register valOrTmp = ToRegister(lir->valueHelper());
|
||||
if (accessType == Scalar::Int64) {
|
||||
|
||||
if (valueType == MIRType::Int64) {
|
||||
masm.wasmUnalignedStoreI64(mir->access(),
|
||||
ToRegister64(lir->getInt64Operand(LWasmUnalignedStoreI64::ValueIndex)),
|
||||
HeapReg, ptr, ptr, valOrTmp);
|
||||
} else if (accessType == Scalar::Float32 || accessType == Scalar::Float64) {
|
||||
} else if (valueType == MIRType::Float32 || valueType == MIRType::Double) {
|
||||
FloatRegister value = ToFloatRegister(lir->getOperand(LWasmUnalignedStore::ValueIndex));
|
||||
masm.wasmUnalignedStoreFP(mir->access(), value, HeapReg, ptr, ptr, valOrTmp);
|
||||
} else {
|
||||
|
@ -223,7 +223,7 @@ LIRGeneratorARM::lowerForMulInt64(LMulI64* ins, MMul* mir, MDefinition* lhs, MDe
|
||||
if (constant >= -1 && constant <= 2) {
|
||||
needsTemp = false;
|
||||
}
|
||||
if (int64_t(1) << shift == constant) {
|
||||
if (constant > 0 && int64_t(1) << shift == constant) {
|
||||
needsTemp = false;
|
||||
}
|
||||
}
|
||||
|
@ -6575,9 +6575,12 @@ MacroAssemblerARM::wasmUnalignedStoreImpl(const wasm::MemoryAccessDesc& access,
|
||||
// handling right.
|
||||
|
||||
if (val64 != Register64::Invalid()) {
|
||||
MOZ_ASSERT(byteSize == 8);
|
||||
emitUnalignedStore(&access, /*size=*/4, ptr, val64.high, /*offset=*/4);
|
||||
emitUnalignedStore(nullptr, /*size=*/4, ptr, val64.low);
|
||||
if (byteSize == 8) {
|
||||
emitUnalignedStore(&access, /*size=*/4, ptr, val64.high, /*offset=*/4);
|
||||
emitUnalignedStore(nullptr, /*size=*/4, ptr, val64.low);
|
||||
} else {
|
||||
emitUnalignedStore(&access, byteSize, ptr, val64.low);
|
||||
}
|
||||
} else if (!floatValue.isInvalid()) {
|
||||
if (floatValue.isDouble()) {
|
||||
MOZ_ASSERT(byteSize == 8);
|
||||
|
@ -222,7 +222,7 @@ LIRGeneratorX86::lowerForMulInt64(LMulI64* ins, MMul* mir, MDefinition* lhs, MDe
|
||||
if (constant >= -1 && constant <= 2) {
|
||||
needsTemp = false;
|
||||
}
|
||||
if (int64_t(1) << shift == constant) {
|
||||
if (constant > 0 && int64_t(1) << shift == constant) {
|
||||
needsTemp = false;
|
||||
}
|
||||
}
|
||||
|
@ -10454,6 +10454,13 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_GC
|
||||
enableWasmGc = op.getBoolOption("wasm-gc");
|
||||
# ifdef ENABLE_WASM_CRANELIFT
|
||||
if (enableWasmGc && wasmForceCranelift) {
|
||||
fprintf(stderr, "Do not combine --wasm-gc and --wasm-force-cranelift, they are "
|
||||
"incompatible.\n");
|
||||
}
|
||||
enableWasmGc = enableWasmGc && !wasmForceCranelift;
|
||||
# endif
|
||||
#endif
|
||||
enableTestWasmAwaitTier2 = op.getBoolOption("test-wasm-await-tier2");
|
||||
enableAsyncStacks = !op.getBoolOption("no-async-stacks");
|
||||
@ -10462,15 +10469,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
|
||||
enableBigInt = !op.getBoolOption("no-bigint");
|
||||
#endif
|
||||
|
||||
#if defined ENABLE_WASM_GC && defined ENABLE_WASM_CRANELIFT
|
||||
// Note, once we remove --wasm-gc this test will no longer make any sense
|
||||
// and we'll need a better solution.
|
||||
if (enableWasmGc && wasmForceCranelift) {
|
||||
fprintf(stderr, "Do not combine --wasm-gc and --wasm-force-cranelift, they are incompatible.\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
JS::ContextOptionsRef(cx).setBaseline(enableBaseline)
|
||||
.setIon(enableIon)
|
||||
.setAsmJS(enableAsmJS)
|
||||
|
@ -7149,6 +7149,10 @@ EncodeMemorySection(Encoder& e, AstModule& module)
|
||||
static bool
|
||||
EncodeGlobalSection(Encoder& e, AstModule& module)
|
||||
{
|
||||
if (!module.globals().length()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t offset;
|
||||
if (!e.startSection(SectionId::Global, &offset)) {
|
||||
return false;
|
||||
|
@ -2468,13 +2468,7 @@ nsDocumentViewer::CreateStyleSet(nsIDocument* aDocument)
|
||||
styleSet->PrependStyleSheet(SheetType::Agent, sheet);
|
||||
}
|
||||
|
||||
// This is the only place components.css / xul.css get loaded.
|
||||
if (aDocument->LoadsFullXULStyleSheetUpFront()) {
|
||||
sheet = cache->XULComponentsSheet();
|
||||
if (sheet) {
|
||||
styleSet->PrependStyleSheet(SheetType::Agent, sheet);
|
||||
}
|
||||
|
||||
sheet = cache->XULSheet();
|
||||
if (sheet) {
|
||||
styleSet->PrependStyleSheet(SheetType::Agent, sheet);
|
||||
|
@ -136,17 +136,6 @@ nsLayoutStylesheetCache::XULSheet()
|
||||
return mXULSheet;
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
nsLayoutStylesheetCache::XULComponentsSheet()
|
||||
{
|
||||
if (!mXULComponentsSheet) {
|
||||
LoadSheetURL("chrome://global/content/components.css",
|
||||
&mXULComponentsSheet, eAgentSheetFeatures, eCrash);
|
||||
}
|
||||
|
||||
return mXULComponentsSheet;
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
nsLayoutStylesheetCache::QuirkSheet()
|
||||
{
|
||||
@ -297,7 +286,6 @@ nsLayoutStylesheetCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
|
||||
MEASURE(mUserChromeSheet);
|
||||
MEASURE(mUserContentSheet);
|
||||
MEASURE(mXULSheet);
|
||||
MEASURE(mXULComponentsSheet);
|
||||
|
||||
// Measurement of the following members may be added later if DMD finds it is
|
||||
// worthwhile:
|
||||
@ -336,7 +324,6 @@ nsLayoutStylesheetCache::nsLayoutStylesheetCache()
|
||||
if (XRE_IsParentProcess()) {
|
||||
// We know we need xul.css for the UI, so load that now too:
|
||||
XULSheet();
|
||||
XULComponentsSheet();
|
||||
}
|
||||
|
||||
if (gUserContentSheetURL) {
|
||||
|
@ -51,7 +51,6 @@ class nsLayoutStylesheetCache final
|
||||
mozilla::StyleSheet* HTMLSheet();
|
||||
mozilla::StyleSheet* MinimalXULSheet();
|
||||
mozilla::StyleSheet* XULSheet();
|
||||
mozilla::StyleSheet* XULComponentsSheet();
|
||||
mozilla::StyleSheet* QuirkSheet();
|
||||
mozilla::StyleSheet* SVGSheet();
|
||||
mozilla::StyleSheet* MathMLSheet();
|
||||
@ -112,7 +111,6 @@ private:
|
||||
RefPtr<mozilla::StyleSheet> mUserChromeSheet;
|
||||
RefPtr<mozilla::StyleSheet> mUserContentSheet;
|
||||
RefPtr<mozilla::StyleSheet> mXULSheet;
|
||||
RefPtr<mozilla::StyleSheet> mXULComponentsSheet;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -108,6 +108,9 @@
|
||||
#define IMAGE_TIFF "image/tiff"
|
||||
#define IMAGE_BMP "image/bmp"
|
||||
#define IMAGE_BMP_MS "image/x-ms-bmp"
|
||||
// This is used internally to represent Windows clipboard BMPs which remove
|
||||
// part of the header.
|
||||
#define IMAGE_BMP_MS_CLIPBOARD "image/x-ms-clipboard-bmp"
|
||||
#define IMAGE_ICO "image/x-icon"
|
||||
#define IMAGE_ICO_MS "image/vnd.microsoft.icon"
|
||||
#define IMAGE_ICON_MS "image/icon"
|
||||
|
@ -6560,6 +6560,18 @@ nsHttpChannel::BeginConnect()
|
||||
if (mProxyInfo)
|
||||
proxyInfo = do_QueryInterface(mProxyInfo);
|
||||
|
||||
if (mCaps & NS_HTTP_CONNECT_ONLY) {
|
||||
if (!proxyInfo) {
|
||||
LOG(("return failure: no proxy for connect-only channel\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!proxyInfo->IsHTTP() && !proxyInfo->IsHTTPS()) {
|
||||
LOG(("return failure: non-http proxy for connect-only channel\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
mRequestHead.SetHTTPS(isHttps);
|
||||
mRequestHead.SetOrigin(scheme, host, port);
|
||||
|
||||
|
@ -20,7 +20,7 @@ public:
|
||||
, mChunkRemaining(0)
|
||||
, mReachedEOF(false)
|
||||
, mWaitEOF(false) {}
|
||||
~nsHttpChunkedDecoder() { delete mTrailers; }
|
||||
~nsHttpChunkedDecoder() = default;
|
||||
|
||||
bool ReachedEOF() { return mReachedEOF; }
|
||||
|
||||
|
@ -1906,7 +1906,8 @@ nsHttpConnection::OnSocketWritable()
|
||||
if (mTransactionCaps & NS_HTTP_CONNECT_ONLY) {
|
||||
if (!mCompletedProxyConnect && !mProxyConnectStream) {
|
||||
// A CONNECT has been requested for this connection but will never
|
||||
// be performed. Fail here to let request callbacks happen.
|
||||
// be performed. This should never happen.
|
||||
MOZ_ASSERT(false, "proxy connect will never happen");
|
||||
LOG(("return failure because proxy connect will never happen\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -2086,7 +2087,8 @@ nsHttpConnection::OnSocketReadable()
|
||||
if ((mTransactionCaps & NS_HTTP_CONNECT_ONLY) &&
|
||||
!mCompletedProxyConnect && !mProxyConnectStream) {
|
||||
// A CONNECT has been requested for this connection but will never
|
||||
// be performed. Fail here to let request callbacks happen.
|
||||
// be performed. This should never happen.
|
||||
MOZ_ASSERT(false, "proxy connect will never happen");
|
||||
LOG(("return failure because proxy connect will never happen\n"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -14,6 +14,11 @@
|
||||
// 1. OnTransportAvailable callback NOT called (checked in step 2)
|
||||
// 2. StopRequest callback called
|
||||
// 3. done
|
||||
// test_connectonly_nonhttp tests an http channel with only connect set with a
|
||||
// non-http proxy.
|
||||
// 1. OnTransportAvailable callback NOT called (checked in step 2)
|
||||
// 2. StopRequest callback called
|
||||
// 3. done
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
@ -71,6 +76,7 @@ var listener = {
|
||||
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||
if (state === STATE_COMPLETED) {
|
||||
Assert.equal(transportAvailable, false, 'transport available not called');
|
||||
Assert.equal(status, 0x80004005, 'error code matches');
|
||||
|
||||
nextTest();
|
||||
return;
|
||||
@ -294,6 +300,20 @@ function test_connectonly_noproxy() {
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function test_connectonly_nonhttp() {
|
||||
clearPrefs()
|
||||
|
||||
Services.prefs.setCharPref("network.proxy.socks", "localhost")
|
||||
Services.prefs.setIntPref("network.proxy.socks_port", socketserver_port)
|
||||
Services.prefs.setCharPref("network.proxy.no_proxies_on", "")
|
||||
Services.prefs.setIntPref("network.proxy.type", 1)
|
||||
|
||||
var chan = makeChan()
|
||||
chan.asyncOpen2(listener)
|
||||
|
||||
do_test_pending()
|
||||
}
|
||||
|
||||
function nextTest() {
|
||||
transportAvailable = false;
|
||||
|
||||
@ -308,12 +328,15 @@ function nextTest() {
|
||||
|
||||
var tests = [
|
||||
test_connectonly,
|
||||
// test_connectonly_noproxy,
|
||||
test_connectonly_noproxy,
|
||||
test_connectonly_nonhttp
|
||||
];
|
||||
|
||||
function clearPrefs() {
|
||||
Services.prefs.clearUserPref("network.proxy.ssl");
|
||||
Services.prefs.clearUserPref("network.proxy.ssl_port");
|
||||
Services.prefs.clearUserPref("network.proxy.socks");
|
||||
Services.prefs.clearUserPref("network.proxy.socks_port");
|
||||
Services.prefs.clearUserPref("network.proxy.no_proxies_on");
|
||||
Services.prefs.clearUserPref("network.proxy.type");
|
||||
}
|
||||
|
@ -648,7 +648,6 @@ linux64-sccache:
|
||||
toolchain-artifact: public/build/sccache2.tar.xz
|
||||
toolchains:
|
||||
- linux64-rust-1.28
|
||||
- linux64-binutils
|
||||
|
||||
linux64-cbindgen:
|
||||
description: "cbindgen toolchain build"
|
||||
|
@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -x -e -v
|
||||
|
||||
# 0.2.7 + a number of changes
|
||||
SCCACHE_REVISION=a3dcb66243d2f211bf2961b3bf34ff59e814daa2
|
||||
# 0.2.7 + --coverage suppport
|
||||
SCCACHE_REVISION=1ab9a33e8d328941acc23c74c949b765f975f309
|
||||
|
||||
# This script is for building sccache
|
||||
|
||||
@ -11,7 +11,6 @@ Linux)
|
||||
WORKSPACE=$HOME/workspace
|
||||
UPLOAD_DIR=$HOME/artifacts
|
||||
COMPRESS_EXT=xz
|
||||
PATH="$WORKSPACE/build/src/binutils/bin:$PATH"
|
||||
;;
|
||||
MINGW*)
|
||||
WORKSPACE=$PWD
|
||||
|
@ -1,4 +1,3 @@
|
||||
[object-position-svg-002e.html]
|
||||
expected:
|
||||
if not debug and webrender and e10s and (os == "linux") and (version == "Ubuntu 16.04") and (processor == "x86_64") and (bits == 64): PASS
|
||||
FAIL
|
||||
|
@ -1,14 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* ===== components.css ==================================================
|
||||
==
|
||||
== THESE STYLES HAVE BEEN MOVED TO "widgets.css".
|
||||
==
|
||||
== This file exists to allow debugging regressions more easily using
|
||||
== just artifact builds, and will be removed in bug 1470873.
|
||||
==
|
||||
======================================================================= */
|
||||
|
||||
|
@ -3,7 +3,6 @@ toolkit.jar:
|
||||
* content/global/license.html
|
||||
content/global/minimal-xul.css
|
||||
* content/global/xul.css
|
||||
content/global/components.css
|
||||
content/global/autocomplete.css
|
||||
content/global/aboutAbout.js
|
||||
content/global/aboutAbout.xhtml
|
||||
|
@ -60,7 +60,6 @@ UNIFIED_SOURCES += [
|
||||
'nsDataObjCollection.cpp',
|
||||
'nsDragService.cpp',
|
||||
'nsIdleServiceWin.cpp',
|
||||
'nsImageClipboard.cpp',
|
||||
'nsLookAndFeel.cpp',
|
||||
'nsNativeDragSource.cpp',
|
||||
'nsNativeDragTarget.cpp',
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsPrimitiveHelpers.h"
|
||||
#include "nsImageClipboard.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
@ -35,6 +34,8 @@
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "imgITools.h"
|
||||
|
||||
using mozilla::LogLevel;
|
||||
|
||||
@ -474,17 +475,39 @@ nsresult nsClipboard::GetNativeDataOffClipboard(IDataObject * aDataObject, UINT
|
||||
if (aMIMEImageFormat)
|
||||
{
|
||||
uint32_t allocLen = 0;
|
||||
unsigned char * clipboardData;
|
||||
const char* clipboardData;
|
||||
if (NS_SUCCEEDED(GetGlobalData(stm.hGlobal, (void **)&clipboardData, &allocLen)))
|
||||
{
|
||||
nsImageFromClipboard converter;
|
||||
nsIInputStream * inputStream;
|
||||
converter.GetEncodedImageStream(clipboardData, aMIMEImageFormat, &inputStream); // addrefs for us, don't release
|
||||
if ( inputStream ) {
|
||||
*aData = inputStream;
|
||||
*aLen = sizeof(nsIInputStream*);
|
||||
result = NS_OK;
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
|
||||
result = imgTools->DecodeImageFromBuffer(clipboardData, allocLen,
|
||||
NS_LITERAL_CSTRING(IMAGE_BMP_MS_CLIPBOARD),
|
||||
getter_AddRefs(container));
|
||||
if (NS_FAILED(result)) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsAutoCString mimeType;
|
||||
if (strcmp(aMIMEImageFormat, kJPGImageMime) == 0) {
|
||||
mimeType.Assign(IMAGE_JPEG);
|
||||
} else {
|
||||
mimeType.Assign(aMIMEImageFormat);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
result = imgTools->EncodeImage(container, mimeType, EmptyString(),
|
||||
getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(result)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!inputStream) {
|
||||
result = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
*aData = inputStream.forget().take();
|
||||
*aLen = sizeof(nsIInputStream*);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "IEnumFE.h"
|
||||
#include "nsPrimitiveHelpers.h"
|
||||
#include "nsString.h"
|
||||
#include "nsImageClipboard.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsIStringBundle.h"
|
||||
@ -35,6 +34,8 @@
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "imgITools.h"
|
||||
|
||||
#include "WinUtils.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
@ -44,6 +45,7 @@
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#define BFH_LENGTH 14
|
||||
#define DEFAULT_THREAD_TIMEOUT_MS 30000
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsDataObj::CStream, nsIStreamListener)
|
||||
@ -902,20 +904,60 @@ nsDataObj::GetDib(const nsACString& inFlavor,
|
||||
mTransferable->GetTransferData(PromiseFlatCString(inFlavor).get(), getter_AddRefs(genericDataWrapper), &len);
|
||||
nsCOMPtr<imgIContainer> image ( do_QueryInterface(genericDataWrapper) );
|
||||
if ( image ) {
|
||||
// use the |nsImageToClipboard| helper class to build up a bitmap. We now own
|
||||
// the bits, and pass them back to the OS in |aSTG|.
|
||||
nsImageToClipboard converter(image, aFormat.cfFormat == CF_DIBV5);
|
||||
HANDLE bits = nullptr;
|
||||
nsresult rv = converter.GetPicture ( &bits );
|
||||
if ( NS_SUCCEEDED(rv) && bits ) {
|
||||
aSTG.hGlobal = bits;
|
||||
aSTG.tymed = TYMED_HGLOBAL;
|
||||
result = S_OK;
|
||||
nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
|
||||
|
||||
nsAutoString options;
|
||||
if (aFormat.cfFormat == CF_DIBV5) {
|
||||
options.AppendLiteral("version=5");
|
||||
} else {
|
||||
options.AppendLiteral("version=3");
|
||||
}
|
||||
} // if we have an image
|
||||
else
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
nsresult rv = imgTools->EncodeImage(image, NS_LITERAL_CSTRING(IMAGE_BMP),
|
||||
options, getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(rv) || !inputStream) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_QueryInterface(inputStream);
|
||||
if (!encoder) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
uint32_t size = 0;
|
||||
rv = encoder->GetImageBufferUsed(&size);
|
||||
if (NS_FAILED(rv) || size <= BFH_LENGTH) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
char *src = nullptr;
|
||||
rv = encoder->GetImageBuffer(&src);
|
||||
if (NS_FAILED(rv) || !src) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// We don't want the file header.
|
||||
src += BFH_LENGTH;
|
||||
size -= BFH_LENGTH;
|
||||
|
||||
HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
|
||||
if (!glob) {
|
||||
DWORD err = ::GetLastError();
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
char *dst = (char*) ::GlobalLock(glob);
|
||||
::CopyMemory(dst, src, size);
|
||||
::GlobalUnlock(glob);
|
||||
|
||||
aSTG.hGlobal = glob;
|
||||
aSTG.tymed = TYMED_HGLOBAL;
|
||||
result = S_OK;
|
||||
} else {
|
||||
NS_WARNING ( "Definitely not an image on clipboard" );
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -1504,18 +1546,29 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
|
||||
if (!image)
|
||||
return E_FAIL;
|
||||
|
||||
// Use the clipboard helper class to build up a memory bitmap.
|
||||
nsImageToClipboard converter(image);
|
||||
HANDLE bits = nullptr;
|
||||
rv = converter.GetPicture(&bits); // Clipboard routines return a global handle we own.
|
||||
|
||||
if (NS_FAILED(rv) || !bits)
|
||||
nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = imgTools->EncodeImage(image, NS_LITERAL_CSTRING(IMAGE_BMP),
|
||||
NS_LITERAL_STRING("version=3"),
|
||||
getter_AddRefs(inputStream));
|
||||
if (NS_FAILED(rv) || !inputStream) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// We now own these bits!
|
||||
uint32_t bitmapSize = GlobalSize(bits);
|
||||
if (!bitmapSize) {
|
||||
GlobalFree(bits);
|
||||
nsCOMPtr<imgIEncoder> encoder = do_QueryInterface(inputStream);
|
||||
if (!encoder) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
uint32_t size = 0;
|
||||
rv = encoder->GetImageBufferUsed(&size);
|
||||
if (NS_FAILED(rv)) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
char *src = nullptr;
|
||||
rv = encoder->GetImageBuffer(&src);
|
||||
if (NS_FAILED(rv) || !src) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
@ -1523,7 +1576,6 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
|
||||
nsCOMPtr<nsIFile> dropFile;
|
||||
rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(dropFile));
|
||||
if (!dropFile) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
@ -1537,7 +1589,6 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
|
||||
dropFile->AppendNative(filename);
|
||||
rv = dropFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0660);
|
||||
if (NS_FAILED(rv)) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
@ -1550,33 +1601,16 @@ HRESULT nsDataObj::DropImage(FORMATETC& aFE, STGMEDIUM& aSTG)
|
||||
nsCOMPtr<nsIOutputStream> outStream;
|
||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(outStream), dropFile);
|
||||
if (NS_FAILED(rv)) {
|
||||
GlobalFree(bits);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
char * bm = (char *)GlobalLock(bits);
|
||||
|
||||
BITMAPFILEHEADER fileHdr;
|
||||
BITMAPINFOHEADER *bmpHdr = (BITMAPINFOHEADER*)bm;
|
||||
|
||||
fileHdr.bfType = ((WORD) ('M' << 8) | 'B');
|
||||
fileHdr.bfSize = GlobalSize (bits) + sizeof(fileHdr);
|
||||
fileHdr.bfReserved1 = 0;
|
||||
fileHdr.bfReserved2 = 0;
|
||||
fileHdr.bfOffBits = (DWORD) (sizeof(fileHdr) + bmpHdr->biSize);
|
||||
|
||||
uint32_t writeCount = 0;
|
||||
if (NS_FAILED(outStream->Write((const char *)&fileHdr, sizeof(fileHdr), &writeCount)) ||
|
||||
NS_FAILED(outStream->Write((const char *)bm, bitmapSize, &writeCount)))
|
||||
rv = NS_ERROR_FAILURE;
|
||||
uint32_t written = 0;
|
||||
rv = outStream->Write(src, size, &written);
|
||||
if (NS_FAILED(rv) || written != size) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
outStream->Close();
|
||||
|
||||
GlobalUnlock(bits);
|
||||
GlobalFree(bits);
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
// Pass the file name back to the drop target so that it can access the file.
|
||||
|
@ -1,496 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsImageClipboard.h"
|
||||
|
||||
#include "gfxUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/DataSurfaceHelpers.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsITransferable.h"
|
||||
#include "nsGfxCIID.h"
|
||||
#include "nsMemory.h"
|
||||
#include "imgIEncoder.h"
|
||||
#include "nsLiteralString.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#define BFH_LENGTH 14
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
/* Things To Do 11/8/00
|
||||
|
||||
Check image metrics, can we support them? Do we need to?
|
||||
Any other render format? HTML?
|
||||
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// nsImageToClipboard ctor
|
||||
//
|
||||
// Given an imgIContainer, convert it to a DIB that is ready to go on the win32 clipboard
|
||||
//
|
||||
nsImageToClipboard::nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5)
|
||||
: mImage(aInImage)
|
||||
, mWantDIBV5(aWantDIBV5)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// nsImageToClipboard dtor
|
||||
//
|
||||
// Clean up after ourselves. We know that we have created the bitmap
|
||||
// successfully if we still have a pointer to the header.
|
||||
//
|
||||
nsImageToClipboard::~nsImageToClipboard()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// GetPicture
|
||||
//
|
||||
// Call to get the actual bits that go on the clipboard. If an error
|
||||
// ocurred during conversion, |outBits| will be null.
|
||||
//
|
||||
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
|
||||
//
|
||||
nsresult
|
||||
nsImageToClipboard :: GetPicture ( HANDLE* outBits )
|
||||
{
|
||||
NS_ASSERTION ( outBits, "Bad parameter" );
|
||||
|
||||
return CreateFromImage ( mImage, outBits );
|
||||
|
||||
} // GetPicture
|
||||
|
||||
|
||||
//
|
||||
// CalcSize
|
||||
//
|
||||
// Computes # of bytes needed by a bitmap with the specified attributes.
|
||||
//
|
||||
int32_t
|
||||
nsImageToClipboard :: CalcSize ( int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes )
|
||||
{
|
||||
int32_t HeaderMem = sizeof(BITMAPINFOHEADER);
|
||||
|
||||
// add size of pallette to header size
|
||||
if (aBitsPerPixel < 16)
|
||||
HeaderMem += aColors * sizeof(RGBQUAD);
|
||||
|
||||
if (aHeight < 0)
|
||||
aHeight = -aHeight;
|
||||
|
||||
return (HeaderMem + (aHeight * aSpanBytes));
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CalcSpanLength
|
||||
//
|
||||
// Computes the span bytes for determining the overall size of the image
|
||||
//
|
||||
int32_t
|
||||
nsImageToClipboard::CalcSpanLength(uint32_t aWidth, uint32_t aBitCount)
|
||||
{
|
||||
int32_t spanBytes = (aWidth * aBitCount) >> 5;
|
||||
|
||||
if ((aWidth * aBitCount) & 0x1F)
|
||||
spanBytes++;
|
||||
spanBytes <<= 2;
|
||||
|
||||
return spanBytes;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// CreateFromImage
|
||||
//
|
||||
// Do the work to setup the bitmap header and copy the bits out of the
|
||||
// image.
|
||||
//
|
||||
nsresult
|
||||
nsImageToClipboard::CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap )
|
||||
{
|
||||
nsresult rv;
|
||||
*outBitmap = nullptr;
|
||||
|
||||
RefPtr<SourceSurface> surface =
|
||||
inImage->GetFrame(imgIContainer::FRAME_CURRENT,
|
||||
imgIContainer::FLAG_SYNC_DECODE);
|
||||
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
|
||||
|
||||
MOZ_ASSERT(surface->GetFormat() == SurfaceFormat::B8G8R8A8 ||
|
||||
surface->GetFormat() == SurfaceFormat::B8G8R8X8);
|
||||
|
||||
RefPtr<DataSourceSurface> dataSurface;
|
||||
if (surface->GetFormat() == SurfaceFormat::B8G8R8A8) {
|
||||
dataSurface = surface->GetDataSurface();
|
||||
} else {
|
||||
// XXXjwatt Bug 995923 - get rid of this copy and handle B8G8R8X8
|
||||
// directly below once bug 995807 is fixed.
|
||||
dataSurface = gfxUtils::
|
||||
CopySurfaceToDataSourceSurfaceWithFormat(surface,
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
}
|
||||
NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
|
||||
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/bmp", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t format;
|
||||
nsAutoString options;
|
||||
if (mWantDIBV5) {
|
||||
options.AppendLiteral("version=5;bpp=");
|
||||
} else {
|
||||
options.AppendLiteral("version=3;bpp=");
|
||||
}
|
||||
switch (dataSurface->GetFormat()) {
|
||||
case SurfaceFormat::B8G8R8A8:
|
||||
format = imgIEncoder::INPUT_FORMAT_HOSTARGB;
|
||||
options.AppendInt(32);
|
||||
break;
|
||||
#if 0
|
||||
// XXXjwatt Bug 995923 - fix |format| and reenable once bug 995807 is fixed.
|
||||
case SurfaceFormat::B8G8R8X8:
|
||||
format = imgIEncoder::INPUT_FORMAT_RGB;
|
||||
options.AppendInt(24);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected surface format");
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
DataSourceSurface::MappedSurface map;
|
||||
bool mappedOK = dataSurface->Map(DataSourceSurface::MapType::READ, &map);
|
||||
NS_ENSURE_TRUE(mappedOK, NS_ERROR_FAILURE);
|
||||
|
||||
rv = encoder->InitFromData(map.mData, 0,
|
||||
dataSurface->GetSize().width,
|
||||
dataSurface->GetSize().height,
|
||||
map.mStride,
|
||||
format, options);
|
||||
dataSurface->Unmap();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t size;
|
||||
encoder->GetImageBufferUsed(&size);
|
||||
NS_ENSURE_TRUE(size > BFH_LENGTH, NS_ERROR_FAILURE);
|
||||
HGLOBAL glob = ::GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT,
|
||||
size - BFH_LENGTH);
|
||||
if (!glob)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
char *dst = (char*) ::GlobalLock(glob);
|
||||
char *src;
|
||||
rv = encoder->GetImageBuffer(&src);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
::CopyMemory(dst, src + BFH_LENGTH, size - BFH_LENGTH);
|
||||
::GlobalUnlock(glob);
|
||||
|
||||
*outBitmap = (HANDLE)glob;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsImageFromClipboard :: nsImageFromClipboard ()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
nsImageFromClipboard :: ~nsImageFromClipboard ( )
|
||||
{
|
||||
}
|
||||
|
||||
//
|
||||
// GetEncodedImageStream
|
||||
//
|
||||
// Take the raw clipboard image data and convert it to aMIMEFormat in the form of a nsIInputStream
|
||||
//
|
||||
nsresult
|
||||
nsImageFromClipboard ::GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** aInputStream )
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER (aInputStream);
|
||||
NS_ENSURE_ARG_POINTER (aMIMEFormat);
|
||||
nsresult rv;
|
||||
*aInputStream = nullptr;
|
||||
|
||||
// pull the size information out of the BITMAPINFO header and
|
||||
// initialize the image
|
||||
BITMAPINFO* header = (BITMAPINFO *) aClipboardData;
|
||||
int32_t width = header->bmiHeader.biWidth;
|
||||
int32_t height = header->bmiHeader.biHeight;
|
||||
// neg. heights mean the Y axis is inverted and we don't handle that case
|
||||
NS_ENSURE_TRUE(height > 0, NS_ERROR_FAILURE);
|
||||
|
||||
unsigned char * rgbData = new unsigned char[width * height * 3 /* RGB */];
|
||||
|
||||
if (rgbData) {
|
||||
BYTE * pGlobal = (BYTE *) aClipboardData;
|
||||
// Convert the clipboard image into RGB packed pixel data
|
||||
rv = ConvertColorBitMap((unsigned char *) (pGlobal + header->bmiHeader.biSize), header, rgbData);
|
||||
// if that succeeded, encode the bitmap as aMIMEFormat data. Don't return early or we risk leaking rgbData
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoCString encoderCID(NS_LITERAL_CSTRING("@mozilla.org/image/encoder;2?type="));
|
||||
|
||||
// Map image/jpg to image/jpeg (which is how the encoder is registered).
|
||||
if (strcmp(aMIMEFormat, kJPGImageMime) == 0)
|
||||
encoderCID.AppendLiteral("image/jpeg");
|
||||
else
|
||||
encoderCID.Append(aMIMEFormat);
|
||||
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance(encoderCID.get(), &rv);
|
||||
if (NS_SUCCEEDED(rv)){
|
||||
rv = encoder->InitFromData(rgbData, 0, width, height, 3 * width /* RGB * # pixels in a row */,
|
||||
imgIEncoder::INPUT_FORMAT_RGB, EmptyString());
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
encoder.forget(aInputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] rgbData;
|
||||
}
|
||||
else
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return rv;
|
||||
} // GetImage
|
||||
|
||||
//
|
||||
// InvertRows
|
||||
//
|
||||
// Take the image data from the clipboard and invert the rows. Modifying aInitialBuffer in place.
|
||||
//
|
||||
void
|
||||
nsImageFromClipboard::InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow)
|
||||
{
|
||||
if (!aNumBytesPerRow)
|
||||
return;
|
||||
|
||||
uint32_t numRows = aSizeOfBuffer / aNumBytesPerRow;
|
||||
unsigned char * row = new unsigned char[aNumBytesPerRow];
|
||||
|
||||
uint32_t currentRow = 0;
|
||||
uint32_t lastRow = (numRows - 1) * aNumBytesPerRow;
|
||||
while (currentRow < lastRow)
|
||||
{
|
||||
// store the current row into a temporary buffer
|
||||
memcpy(row, &aInitialBuffer[currentRow], aNumBytesPerRow);
|
||||
memcpy(&aInitialBuffer[currentRow], &aInitialBuffer[lastRow], aNumBytesPerRow);
|
||||
memcpy(&aInitialBuffer[lastRow], row, aNumBytesPerRow);
|
||||
lastRow -= aNumBytesPerRow;
|
||||
currentRow += aNumBytesPerRow;
|
||||
}
|
||||
|
||||
delete[] row;
|
||||
}
|
||||
|
||||
//
|
||||
// ConvertColorBitMap
|
||||
//
|
||||
// Takes the clipboard bitmap and converts it into a RGB packed pixel values.
|
||||
//
|
||||
nsresult
|
||||
nsImageFromClipboard::ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer)
|
||||
{
|
||||
uint8_t bitCount = pBitMapInfo->bmiHeader.biBitCount;
|
||||
uint32_t imageSize = pBitMapInfo->bmiHeader.biSizeImage; // may be zero for BI_RGB bitmaps which means we need to calculate by hand
|
||||
uint32_t bytesPerPixel = bitCount / 8;
|
||||
|
||||
if (bitCount <= 4)
|
||||
bytesPerPixel = 1;
|
||||
|
||||
// rows are DWORD aligned. Calculate how many real bytes are in each row in the bitmap. This number won't
|
||||
// correspond to biWidth.
|
||||
uint32_t rowSize = (bitCount * pBitMapInfo->bmiHeader.biWidth + 7) / 8; // +7 to round up
|
||||
if (rowSize % 4)
|
||||
rowSize += (4 - (rowSize % 4)); // Pad to DWORD Boundary
|
||||
|
||||
// if our buffer includes a color map, skip over it
|
||||
if (bitCount <= 8)
|
||||
{
|
||||
int32_t bytesToSkip = (pBitMapInfo->bmiHeader.biClrUsed ? pBitMapInfo->bmiHeader.biClrUsed : (1 << bitCount) ) * sizeof(RGBQUAD);
|
||||
aInputBuffer += bytesToSkip;
|
||||
}
|
||||
|
||||
bitFields colorMasks; // only used if biCompression == BI_BITFIELDS
|
||||
|
||||
if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
// color table consists of 3 DWORDS containing the color masks...
|
||||
colorMasks.red = (*((uint32_t*)&(pBitMapInfo->bmiColors[0])));
|
||||
colorMasks.green = (*((uint32_t*)&(pBitMapInfo->bmiColors[1])));
|
||||
colorMasks.blue = (*((uint32_t*)&(pBitMapInfo->bmiColors[2])));
|
||||
CalcBitShift(&colorMasks);
|
||||
aInputBuffer += 3 * sizeof(DWORD);
|
||||
}
|
||||
else if (pBitMapInfo->bmiHeader.biCompression == BI_RGB && !imageSize) // BI_RGB can have a size of zero which means we figure it out
|
||||
{
|
||||
// XXX: note use rowSize here and not biWidth. rowSize accounts for the DWORD padding for each row
|
||||
imageSize = rowSize * pBitMapInfo->bmiHeader.biHeight;
|
||||
}
|
||||
|
||||
// The windows clipboard image format inverts the rows
|
||||
InvertRows(aInputBuffer, imageSize, rowSize);
|
||||
|
||||
if (!pBitMapInfo->bmiHeader.biCompression || pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
uint32_t index = 0;
|
||||
uint32_t writeIndex = 0;
|
||||
|
||||
unsigned char redValue, greenValue, blueValue;
|
||||
uint8_t colorTableEntry = 0;
|
||||
int8_t bit; // used for grayscale bitmaps where each bit is a pixel
|
||||
uint32_t numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth; // how many more pixels do we still need to read for the current row
|
||||
uint32_t pos = 0;
|
||||
|
||||
while (index < imageSize)
|
||||
{
|
||||
switch (bitCount)
|
||||
{
|
||||
case 1:
|
||||
for (bit = 7; bit >= 0 && numPixelsLeftInRow; bit--)
|
||||
{
|
||||
colorTableEntry = (aInputBuffer[index] >> bit) & 1;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
}
|
||||
pos += 1;
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
// each aInputBuffer[index] entry contains data for two pixels.
|
||||
// read the first pixel
|
||||
colorTableEntry = aInputBuffer[index] >> 4;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
|
||||
if (numPixelsLeftInRow) // now read the second pixel
|
||||
{
|
||||
colorTableEntry = aInputBuffer[index] & 0xF;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[colorTableEntry].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
}
|
||||
pos += 1;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbRed;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbGreen;
|
||||
aOutBuffer[writeIndex++] = pBitMapInfo->bmiColors[aInputBuffer[index]].rgbBlue;
|
||||
numPixelsLeftInRow--;
|
||||
pos += 1;
|
||||
break;
|
||||
case 16:
|
||||
{
|
||||
uint16_t num = 0;
|
||||
num = (uint8_t) aInputBuffer[index+1];
|
||||
num <<= 8;
|
||||
num |= (uint8_t) aInputBuffer[index];
|
||||
|
||||
redValue = ((uint32_t) (((float)(num & 0xf800) / 0xf800) * 0xFF0000) & 0xFF0000)>> 16;
|
||||
greenValue = ((uint32_t)(((float)(num & 0x07E0) / 0x07E0) * 0x00FF00) & 0x00FF00)>> 8;
|
||||
blueValue = ((uint32_t)(((float)(num & 0x001F) / 0x001F) * 0x0000FF) & 0x0000FF);
|
||||
|
||||
// now we have the right RGB values...
|
||||
aOutBuffer[writeIndex++] = redValue;
|
||||
aOutBuffer[writeIndex++] = greenValue;
|
||||
aOutBuffer[writeIndex++] = blueValue;
|
||||
numPixelsLeftInRow--;
|
||||
pos += 2;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
case 24:
|
||||
if (pBitMapInfo->bmiHeader.biCompression == BI_BITFIELDS)
|
||||
{
|
||||
uint32_t val = *((uint32_t*) (aInputBuffer + index) );
|
||||
aOutBuffer[writeIndex++] = (val & colorMasks.red) >> colorMasks.redRightShift << colorMasks.redLeftShift;
|
||||
aOutBuffer[writeIndex++] = (val & colorMasks.green) >> colorMasks.greenRightShift << colorMasks.greenLeftShift;
|
||||
aOutBuffer[writeIndex++] = (val & colorMasks.blue) >> colorMasks.blueRightShift << colorMasks.blueLeftShift;
|
||||
numPixelsLeftInRow--;
|
||||
pos += 4; // we read in 4 bytes of data in order to process this pixel
|
||||
}
|
||||
else
|
||||
{
|
||||
aOutBuffer[writeIndex++] = aInputBuffer[index+2];
|
||||
aOutBuffer[writeIndex++] = aInputBuffer[index+1];
|
||||
aOutBuffer[writeIndex++] = aInputBuffer[index];
|
||||
numPixelsLeftInRow--;
|
||||
pos += bytesPerPixel; // 3 bytes for 24 bit data, 4 bytes for 32 bit data (we skip over the 4th byte)...
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// This is probably the wrong place to check this...
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
index += bytesPerPixel; // increment our loop counter
|
||||
|
||||
if (!numPixelsLeftInRow)
|
||||
{
|
||||
if (rowSize != pos)
|
||||
{
|
||||
// advance index to skip over remaining padding bytes
|
||||
index += (rowSize - pos);
|
||||
}
|
||||
numPixelsLeftInRow = pBitMapInfo->bmiHeader.biWidth;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
} // while we still have bytes to process
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsImageFromClipboard::CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength)
|
||||
{
|
||||
// find the rightmost 1
|
||||
uint8_t pos;
|
||||
bool started = false;
|
||||
aBegin = aLength = 0;
|
||||
for (pos = 0; pos <= 31; pos++)
|
||||
{
|
||||
if (!started && (aMask & (1 << pos)))
|
||||
{
|
||||
aBegin = pos;
|
||||
started = true;
|
||||
}
|
||||
else if (started && !(aMask & (1 << pos)))
|
||||
{
|
||||
aLength = pos - aBegin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nsImageFromClipboard::CalcBitShift(bitFields * aColorMask)
|
||||
{
|
||||
uint8_t begin, length;
|
||||
// red
|
||||
CalcBitmask(aColorMask->red, begin, length);
|
||||
aColorMask->redRightShift = begin;
|
||||
aColorMask->redLeftShift = 8 - length;
|
||||
// green
|
||||
CalcBitmask(aColorMask->green, begin, length);
|
||||
aColorMask->greenRightShift = begin;
|
||||
aColorMask->greenLeftShift = 8 - length;
|
||||
// blue
|
||||
CalcBitmask(aColorMask->blue, begin, length);
|
||||
aColorMask->blueRightShift = begin;
|
||||
aColorMask->blueLeftShift = 8 - length;
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsImageClipboard_h
|
||||
#define nsImageClipboard_h
|
||||
|
||||
/* Things To Do 11/8/00
|
||||
|
||||
Check image metrics, can we support them? Do we need to?
|
||||
Any other render format? HTML?
|
||||
|
||||
*/
|
||||
|
||||
#include "nsError.h"
|
||||
#include <windows.h>
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "nsIInputStream.h"
|
||||
|
||||
|
||||
//
|
||||
// nsImageToClipboard
|
||||
//
|
||||
// A utility class that takes an imgIContainer and does all the bitmap magic
|
||||
// to allow us to put it on the clipboard
|
||||
//
|
||||
class nsImageToClipboard
|
||||
{
|
||||
public:
|
||||
explicit nsImageToClipboard(imgIContainer* aInImage, bool aWantDIBV5 = true);
|
||||
~nsImageToClipboard();
|
||||
|
||||
// Call to get the actual bits that go on the clipboard. If |nullptr|, the
|
||||
// setup operations have failed.
|
||||
//
|
||||
// NOTE: The caller owns the handle and must delete it with ::GlobalRelease()
|
||||
nsresult GetPicture ( HANDLE* outBits ) ;
|
||||
|
||||
private:
|
||||
|
||||
// Computes # of bytes needed by a bitmap with the specified attributes.
|
||||
int32_t CalcSize(int32_t aHeight, int32_t aColors, WORD aBitsPerPixel, int32_t aSpanBytes);
|
||||
int32_t CalcSpanLength(uint32_t aWidth, uint32_t aBitCount);
|
||||
|
||||
// Do the work
|
||||
nsresult CreateFromImage ( imgIContainer* inImage, HANDLE* outBitmap );
|
||||
|
||||
nsCOMPtr<imgIContainer> mImage; // the image we're working with
|
||||
bool mWantDIBV5;
|
||||
|
||||
}; // class nsImageToClipboard
|
||||
|
||||
|
||||
struct bitFields {
|
||||
uint32_t red;
|
||||
uint32_t green;
|
||||
uint32_t blue;
|
||||
uint8_t redLeftShift;
|
||||
uint8_t redRightShift;
|
||||
uint8_t greenLeftShift;
|
||||
uint8_t greenRightShift;
|
||||
uint8_t blueLeftShift;
|
||||
uint8_t blueRightShift;
|
||||
};
|
||||
|
||||
//
|
||||
// nsImageFromClipboard
|
||||
//
|
||||
// A utility class that takes a DIB from the win32 clipboard and does
|
||||
// all the bitmap magic to convert it to a PNG or a JPEG in the form of a nsIInputStream
|
||||
//
|
||||
class nsImageFromClipboard
|
||||
{
|
||||
public:
|
||||
nsImageFromClipboard () ;
|
||||
~nsImageFromClipboard ( ) ;
|
||||
|
||||
// Retrieve the newly created image
|
||||
nsresult GetEncodedImageStream (unsigned char * aClipboardData, const char * aMIMEFormat, nsIInputStream** outImage);
|
||||
|
||||
private:
|
||||
|
||||
void InvertRows(unsigned char * aInitialBuffer, uint32_t aSizeOfBuffer, uint32_t aNumBytesPerRow);
|
||||
nsresult ConvertColorBitMap(unsigned char * aInputBuffer, PBITMAPINFO pBitMapInfo, unsigned char * aOutBuffer);
|
||||
void CalcBitmask(uint32_t aMask, uint8_t& aBegin, uint8_t& aLength);
|
||||
void CalcBitShift(bitFields * aColorMask);
|
||||
|
||||
}; // nsImageFromClipboard
|
||||
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
#include "mozilla/RelativeLuminanceUtils.h"
|
||||
#include "mozilla/StaticPrefs.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "mozilla/gfx/Types.h" // for Color::FromABGR
|
||||
#include "nsColor.h"
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsRect.h"
|
||||
@ -44,6 +45,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
extern mozilla::LazyLogModule gWindowsLog;
|
||||
|
@ -163,7 +163,7 @@ NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing)
|
||||
return;
|
||||
}
|
||||
|
||||
if (AddToCCKind(aThing.kind())) {
|
||||
if (JS::IsCCTraceKind(aThing.kind())) {
|
||||
mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing);
|
||||
mTracedAny = true;
|
||||
} else {
|
||||
@ -198,13 +198,13 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey,
|
||||
// reason about the liveness of their keys, which in turn requires that
|
||||
// the key can be represented in the cycle collector graph. All existing
|
||||
// uses of weak maps use either objects or scripts as keys, which are okay.
|
||||
MOZ_ASSERT(AddToCCKind(aKey.kind()));
|
||||
MOZ_ASSERT(JS::IsCCTraceKind(aKey.kind()));
|
||||
|
||||
// As an emergency fallback for non-debug builds, if the key is not
|
||||
// representable in the cycle collector graph, we treat it as marked. This
|
||||
// can cause leaks, but is preferable to ignoring the binding, which could
|
||||
// cause the cycle collector to free live objects.
|
||||
if (!AddToCCKind(aKey.kind())) {
|
||||
if (!JS::IsCCTraceKind(aKey.kind())) {
|
||||
aKey = nullptr;
|
||||
}
|
||||
|
||||
@ -213,7 +213,7 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey,
|
||||
kdelegate = js::GetWeakmapKeyDelegate(&aKey.as<JSObject>());
|
||||
}
|
||||
|
||||
if (AddToCCKind(aValue.kind())) {
|
||||
if (JS::IsCCTraceKind(aValue.kind())) {
|
||||
mCb.NoteWeakMapping(aMap, aKey, kdelegate, aValue);
|
||||
} else {
|
||||
mChildTracer.mTracedAny = false;
|
||||
@ -251,7 +251,7 @@ ShouldWeakMappingEntryBeBlack(JSObject* aMap, JS::GCCellPtr aKey, JS::GCCellPtr
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AddToCCKind(aKey.kind())) {
|
||||
if (!JS::IsCCTraceKind(aKey.kind())) {
|
||||
aKey = nullptr;
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ CheckParticipatesInCycleCollection(JS::GCCellPtr aThing, const char* aName,
|
||||
return;
|
||||
}
|
||||
|
||||
if (AddToCCKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) {
|
||||
if (JS::IsCCTraceKind(aThing.kind()) && JS::GCThingIsMarkedGray(aThing)) {
|
||||
*cycleCollectionEnabled = true;
|
||||
}
|
||||
}
|
||||
@ -421,12 +421,12 @@ TraversalTracer::onChild(const JS::GCCellPtr& aThing)
|
||||
|
||||
/*
|
||||
* This function needs to be careful to avoid stack overflow. Normally, when
|
||||
* AddToCCKind is true, the recursion terminates immediately as we just add
|
||||
* IsCCTraceKind is true, the recursion terminates immediately as we just add
|
||||
* |thing| to the CC graph. So overflow is only possible when there are long
|
||||
* or cyclic chains of non-AddToCCKind GC things. Places where this can occur
|
||||
* or cyclic chains of non-IsCCTraceKind GC things. Places where this can occur
|
||||
* use special APIs to handle such chains iteratively.
|
||||
*/
|
||||
if (AddToCCKind(aThing.kind())) {
|
||||
if (JS::IsCCTraceKind(aThing.kind())) {
|
||||
if (MOZ_UNLIKELY(mCb.WantDebugInfo())) {
|
||||
char buffer[200];
|
||||
getTracingEdgeName(buffer, sizeof(buffer));
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/SegmentedVector.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/TraceKind.h"
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDataHashtable.h"
|
||||
@ -412,21 +413,6 @@ private:
|
||||
|
||||
void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer);
|
||||
|
||||
// Returns true if the JS::TraceKind is one the cycle collector cares about.
|
||||
// Everything used as WeakMap key should be listed here, to represent the key
|
||||
// in cycle collector's graph, otherwise the key is considered to be pointed
|
||||
// from somewhere unknown, and results in leaking the subgraph which contains
|
||||
// the key.
|
||||
// See the comments in NoteWeakMapsTracer::trace for more details.
|
||||
inline bool AddToCCKind(JS::TraceKind aKind)
|
||||
{
|
||||
return aKind == JS::TraceKind::Object ||
|
||||
aKind == JS::TraceKind::Script ||
|
||||
aKind == JS::TraceKind::LazyScript ||
|
||||
aKind == JS::TraceKind::Scope ||
|
||||
aKind == JS::TraceKind::RegExpShared;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_CycleCollectedJSRuntime_h
|
||||
|
@ -2062,14 +2062,14 @@ nsCycleCollector_createLogger()
|
||||
static bool
|
||||
GCThingIsGrayCCThing(JS::GCCellPtr thing)
|
||||
{
|
||||
return AddToCCKind(thing.kind()) &&
|
||||
return JS::IsCCTraceKind(thing.kind()) &&
|
||||
JS::GCThingIsMarkedGray(thing);
|
||||
}
|
||||
|
||||
static bool
|
||||
ValueIsGrayCCThing(const JS::Value& value)
|
||||
{
|
||||
return AddToCCKind(value.traceKind()) &&
|
||||
return JS::IsCCTraceKind(value.traceKind()) &&
|
||||
JS::GCThingIsMarkedGray(value.toGCCellPtr());
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ nsCycleCollectionParticipant::NoteJSChild(JS::GCCellPtr aGCThing,
|
||||
nsCycleCollectionTraversalCallback* cb =
|
||||
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aName);
|
||||
if (mozilla::AddToCCKind(aGCThing.kind())) {
|
||||
if (JS::IsCCTraceKind(aGCThing.kind())) {
|
||||
cb->NoteJSChild(aGCThing);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user