mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central
This commit is contained in:
commit
cf050969e7
@ -922,6 +922,7 @@ let PlacesToolbarHelper = {
|
||||
if (forceToolbarOverflowCheck) {
|
||||
viewElt._placesView.updateOverflowStatus();
|
||||
}
|
||||
this._shouldWrap = false;
|
||||
this._setupPlaceholder();
|
||||
},
|
||||
|
||||
|
@ -4,6 +4,9 @@
|
||||
|
||||
# Setup for build cache
|
||||
|
||||
# Avoid duplication if the file happens to be included twice.
|
||||
if test -z "$bucket"; then
|
||||
|
||||
read branch platform master <<EOF
|
||||
$(python2.7 -c 'import json; p = json.loads(open("'"$topsrcdir"'/../buildprops.json").read())["properties"]; print p["branch"], p["platform"], p["master"]' 2> /dev/null)
|
||||
EOF
|
||||
@ -62,3 +65,5 @@ else
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
fi
|
||||
|
@ -53,6 +53,7 @@ LOCAL_INCLUDES += [
|
||||
]
|
||||
|
||||
DISABLE_STL_WRAPPING = True
|
||||
NO_VISIBILITY_FLAGS = True
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['GNU_CXX']:
|
||||
|
@ -2550,8 +2550,13 @@ dnl ===============================================================
|
||||
if test "$GNU_CC"; then
|
||||
AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
|
||||
AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
|
||||
case "${OS_TARGET}" in
|
||||
Darwin|Android)
|
||||
if test -n "$gonkdir"; then
|
||||
visibility_target=Gonk
|
||||
else
|
||||
visibility_target=$OS_TARGET
|
||||
fi
|
||||
case "$visibility_target" in
|
||||
Darwin|Gonk)
|
||||
VISIBILITY_FLAGS='-fvisibility=hidden'
|
||||
;;
|
||||
*)
|
||||
|
@ -68,6 +68,7 @@ typedef enum {
|
||||
GStreamerReader::GStreamerReader(AbstractMediaDecoder* aDecoder)
|
||||
: MediaDecoderReader(aDecoder),
|
||||
mMP3FrameParser(aDecoder->GetResource()->GetLength()),
|
||||
mDataOffset(0),
|
||||
mUseParserDuration(false),
|
||||
#if GST_VERSION_MAJOR >= 1
|
||||
mAllocator(nullptr),
|
||||
@ -238,7 +239,7 @@ void GStreamerReader::PlayBinSourceSetup(GstAppSrc* aSource)
|
||||
resource->Seek(SEEK_SET, 0);
|
||||
|
||||
/* now we should have a length */
|
||||
int64_t resourceLength = resource->GetLength();
|
||||
int64_t resourceLength = GetDataLength();
|
||||
gst_app_src_set_size(mSource, resourceLength);
|
||||
if (resource->IsDataCachedToEndOfResource(0) ||
|
||||
(resourceLength != -1 && resourceLength <= SHORT_FILE_SIZE)) {
|
||||
@ -287,11 +288,28 @@ nsresult GStreamerReader::ParseMP3Headers()
|
||||
|
||||
if (mMP3FrameParser.IsMP3()) {
|
||||
mLastParserDuration = mMP3FrameParser.GetDuration();
|
||||
mDataOffset = mMP3FrameParser.GetMP3Offset();
|
||||
|
||||
// Update GStreamer's stream length in case we found any ID3 headers to
|
||||
// ignore.
|
||||
gst_app_src_set_size(mSource, GetDataLength());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int64_t
|
||||
GStreamerReader::GetDataLength()
|
||||
{
|
||||
int64_t streamLen = mDecoder->GetResource()->GetLength();
|
||||
|
||||
if (streamLen < 0) {
|
||||
return streamLen;
|
||||
}
|
||||
|
||||
return streamLen - mDataOffset;
|
||||
}
|
||||
|
||||
nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo,
|
||||
MetadataTags** aTags)
|
||||
{
|
||||
@ -800,7 +818,7 @@ nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
|
||||
|
||||
double end = (double) duration / GST_MSECOND;
|
||||
LOG(PR_LOG_DEBUG, "complete range [0, %f] for [0, %li]",
|
||||
end, resource->GetLength());
|
||||
end, GetDataLength());
|
||||
aBuffered->Add(0, end);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -829,7 +847,7 @@ nsresult GStreamerReader::GetBuffered(dom::TimeRanges* aBuffered,
|
||||
double start = (double) GST_TIME_AS_USECONDS (startTime) / GST_MSECOND;
|
||||
double end = (double) GST_TIME_AS_USECONDS (endTime) / GST_MSECOND;
|
||||
LOG(PR_LOG_DEBUG, "adding range [%f, %f] for [%li %li] size %li",
|
||||
start, end, startOffset, endOffset, resource->GetLength());
|
||||
start, end, startOffset, endOffset, GetDataLength());
|
||||
aBuffered->Add(start, end);
|
||||
}
|
||||
|
||||
@ -933,6 +951,8 @@ gboolean GStreamerReader::SeekDataCb(GstAppSrc* aSrc,
|
||||
|
||||
gboolean GStreamerReader::SeekData(GstAppSrc* aSrc, guint64 aOffset)
|
||||
{
|
||||
aOffset += mDataOffset;
|
||||
|
||||
ReentrantMonitorAutoEnter mon(mGstThreadsMonitor);
|
||||
MediaResource* resource = mDecoder->GetResource();
|
||||
int64_t resourceLength = resource->GetLength();
|
||||
@ -941,7 +961,7 @@ gboolean GStreamerReader::SeekData(GstAppSrc* aSrc, guint64 aOffset)
|
||||
/* It's possible that we didn't know the length when we initialized mSource
|
||||
* but maybe we do now
|
||||
*/
|
||||
gst_app_src_set_size(mSource, resourceLength);
|
||||
gst_app_src_set_size(mSource, GetDataLength());
|
||||
}
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
@ -178,9 +178,17 @@ private:
|
||||
// Try to find MP3 headers in this stream using our MP3 frame parser.
|
||||
nsresult ParseMP3Headers();
|
||||
|
||||
// Get the length of the stream, excluding any metadata we have ignored at the
|
||||
// start of the stream: ID3 headers, for example.
|
||||
int64_t GetDataLength();
|
||||
|
||||
// Use our own MP3 parser here, largely for consistency with other platforms.
|
||||
MP3FrameParser mMP3FrameParser;
|
||||
|
||||
// The byte position in the stream where the actual media (ignoring, for
|
||||
// example, ID3 tags) starts.
|
||||
uint64_t mDataOffset;
|
||||
|
||||
// We want to be able to decide in |ReadMetadata| whether or not we use the
|
||||
// duration from the MP3 frame parser, as this backend supports more than just
|
||||
// MP3. But |NotifyDataArrived| can update the duration and is often called
|
||||
|
@ -65,7 +65,7 @@ private:
|
||||
return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
|
||||
}
|
||||
|
||||
const nsAutoCString mType;
|
||||
const nsCString mType;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -132,6 +132,8 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static ContainerParser* CreateForMIMEType(const nsACString& aType);
|
||||
};
|
||||
|
||||
class WebMContainerParser : public ContainerParser {
|
||||
@ -156,6 +158,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/*static*/ ContainerParser*
|
||||
ContainerParser::CreateForMIMEType(const nsACString& aType)
|
||||
{
|
||||
if (aType.LowerCaseEqualsLiteral("video/webm") || aType.LowerCaseEqualsLiteral("audio/webm")) {
|
||||
return new WebMContainerParser();
|
||||
}
|
||||
|
||||
// XXX: Plug in parsers for MPEG4, etc. here.
|
||||
return new ContainerParser();
|
||||
}
|
||||
|
||||
namespace dom {
|
||||
|
||||
void
|
||||
@ -267,10 +280,7 @@ SourceBuffer::Abort(ErrorResult& aRv)
|
||||
mAppendWindowEnd = PositiveInfinity<double>();
|
||||
|
||||
MSE_DEBUG("%p Abort: Discarding decoder.", this);
|
||||
if (mDecoder) {
|
||||
mDecoder->GetResource()->Ended();
|
||||
mDecoder = nullptr;
|
||||
}
|
||||
DiscardDecoder();
|
||||
}
|
||||
|
||||
void
|
||||
@ -296,7 +306,7 @@ void
|
||||
SourceBuffer::Detach()
|
||||
{
|
||||
Ended();
|
||||
mDecoder = nullptr;
|
||||
DiscardDecoder();
|
||||
mMediaSource = nullptr;
|
||||
}
|
||||
|
||||
@ -317,15 +327,10 @@ SourceBuffer::SourceBuffer(MediaSource* aMediaSource, const nsACString& aType)
|
||||
, mTimestampOffset(0)
|
||||
, mAppendMode(SourceBufferAppendMode::Segments)
|
||||
, mUpdating(false)
|
||||
, mDecoderInit(false)
|
||||
, mDecoderInitialized(false)
|
||||
{
|
||||
MOZ_ASSERT(aMediaSource);
|
||||
if (mType.EqualsIgnoreCase("video/webm") || mType.EqualsIgnoreCase("audio/webm")) {
|
||||
mParser = new WebMContainerParser();
|
||||
} else {
|
||||
// XXX: Plug in parsers for MPEG4, etc. here.
|
||||
mParser = new ContainerParser();
|
||||
}
|
||||
mParser = ContainerParser::CreateForMIMEType(aType);
|
||||
MSE_DEBUG("%p SourceBuffer: Creating initial decoder.", this);
|
||||
InitNewDecoder();
|
||||
}
|
||||
@ -339,9 +344,7 @@ SourceBuffer::Create(MediaSource* aMediaSource, const nsACString& aType)
|
||||
|
||||
SourceBuffer::~SourceBuffer()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->GetResource()->Ended();
|
||||
}
|
||||
DiscardDecoder();
|
||||
}
|
||||
|
||||
MediaSource*
|
||||
@ -374,15 +377,27 @@ SourceBuffer::QueueAsyncSimpleEvent(const char* aName)
|
||||
bool
|
||||
SourceBuffer::InitNewDecoder()
|
||||
{
|
||||
MOZ_ASSERT(!mDecoder);
|
||||
MediaSourceDecoder* parentDecoder = mMediaSource->GetDecoder();
|
||||
nsRefPtr<SubBufferDecoder> decoder = parentDecoder->CreateSubDecoder(mType);
|
||||
if (!decoder) {
|
||||
return false;
|
||||
}
|
||||
mDecoder = decoder;
|
||||
mDecoderInitialized = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::DiscardDecoder()
|
||||
{
|
||||
if (mDecoder) {
|
||||
mDecoder->GetResource()->Ended();
|
||||
}
|
||||
mDecoder = nullptr;
|
||||
mDecoderInitialized = false;
|
||||
}
|
||||
|
||||
void
|
||||
SourceBuffer::StartUpdating()
|
||||
{
|
||||
@ -424,18 +439,28 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR
|
||||
// TODO: Test buffer full flag.
|
||||
StartUpdating();
|
||||
// TODO: Run buffer append algorithm asynchronously (would call StopUpdating()).
|
||||
if (!mDecoder || mParser->IsInitSegmentPresent(aData, aLength)) {
|
||||
if (!mDecoder || mDecoderInit) {
|
||||
MSE_DEBUG("%p AppendBuffer: New initialization segment, creating decoder.", this);
|
||||
mDecoder->GetResource()->Ended();
|
||||
if (mParser->IsInitSegmentPresent(aData, aLength)) {
|
||||
MSE_DEBUG("%p AppendBuffer: New initialization segment.", this);
|
||||
if (mDecoderInitialized) {
|
||||
// Existing decoder has been used, time for a new one.
|
||||
DiscardDecoder();
|
||||
}
|
||||
|
||||
if (!InitNewDecoder()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
|
||||
return;
|
||||
}
|
||||
// If we've got a decoder here, it's not initialized, so we can use it
|
||||
// rather than creating a new one.
|
||||
if (!mDecoder && !InitNewDecoder()) {
|
||||
aRv.Throw(NS_ERROR_FAILURE); // XXX: Review error handling.
|
||||
return;
|
||||
}
|
||||
MSE_DEBUG("%p AppendBuffer: Decoder marked as initialized.", this);
|
||||
mDecoderInit = true;
|
||||
mDecoderInitialized = true;
|
||||
} else if (!mDecoderInitialized) {
|
||||
MSE_DEBUG("%p AppendBuffer: Non-initialization segment appended during initialization.");
|
||||
Optional<MediaSourceEndOfStreamError> decodeError(MediaSourceEndOfStreamError::Decode);
|
||||
ErrorResult dummy;
|
||||
mMediaSource->EndOfStream(decodeError, dummy);
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
// XXX: For future reference: NDA call must run on the main thread.
|
||||
mDecoder->NotifyDataArrived(reinterpret_cast<const char*>(aData),
|
||||
|
@ -119,9 +119,13 @@ private:
|
||||
void DispatchSimpleEvent(const char* aName);
|
||||
void QueueAsyncSimpleEvent(const char* aName);
|
||||
|
||||
// Create a new decoder for mType, add it to mDecoders and update mCurrentDecoder.
|
||||
// Create a new decoder for mType, and store the result in mDecoder.
|
||||
// Returns true if mDecoder was set.
|
||||
bool InitNewDecoder();
|
||||
|
||||
// Set mDecoder to null and reset mDecoderInitialized.
|
||||
void DiscardDecoder();
|
||||
|
||||
// Update mUpdating and fire the appropriate events.
|
||||
void StartUpdating();
|
||||
void StopUpdating();
|
||||
@ -136,7 +140,7 @@ private:
|
||||
|
||||
nsRefPtr<MediaSource> mMediaSource;
|
||||
|
||||
const nsAutoCString mType;
|
||||
const nsCString mType;
|
||||
|
||||
nsAutoPtr<ContainerParser> mParser;
|
||||
|
||||
@ -150,7 +154,7 @@ private:
|
||||
SourceBufferAppendMode mAppendMode;
|
||||
bool mUpdating;
|
||||
|
||||
bool mDecoderInit;
|
||||
bool mDecoderInitialized;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -283,7 +283,7 @@ public:
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
const nsAutoCString mType;
|
||||
const nsCString mType;
|
||||
|
||||
// Provides synchronization between SourceBuffers and InputAdapters.
|
||||
// Protects all of the member variables below. Read() will await a
|
||||
|
27
content/media/mediasource/test/crashtests/1005366.html
Normal file
27
content/media/mediasource/test/crashtests/1005366.html
Normal file
@ -0,0 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
|
||||
/*
|
||||
user_pref("media.mediasource.enabled", true);
|
||||
*/
|
||||
|
||||
function boom()
|
||||
{
|
||||
var source = new window.MediaSource();
|
||||
var videoElement = document.createElementNS('http://www.w3.org/1999/xhtml', 'video');
|
||||
videoElement.src = URL.createObjectURL(source);
|
||||
|
||||
setTimeout(function() {
|
||||
var buf = source.addSourceBuffer("video/webm");
|
||||
buf.abort();
|
||||
buf.appendBuffer(new Float32Array(203));
|
||||
}, 0);
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
@ -0,0 +1,2 @@
|
||||
test-pref(media.mediasource.enabled,true) load 926665.html
|
||||
test-pref(media.mediasource.enabled,true) load 1005366.html
|
@ -69,4 +69,4 @@ load offline-buffer-source-ended-1.html
|
||||
skip-if(B2G) HTTP load media-element-source-seek-1.html # intermittent B2G timeouts, bug 994351
|
||||
skip-if(B2G) load oscillator-ended-1.html # intermittent B2G timeouts, bug 920338
|
||||
skip-if(B2G) load oscillator-ended-2.html # intermittent B2G timeouts, bug 920338
|
||||
test-pref(media.mediasource.enabled,true) load 926665.html
|
||||
include ../../mediasource/test/crashtests/crashtests.list
|
||||
|
@ -425,10 +425,10 @@ MediaEngineDefaultAudioSource::Start(SourceMediaStream* aStream, TrackID aID)
|
||||
#if defined(MOZ_WIDGET_GONK) && defined(DEBUG)
|
||||
// B2G emulator debug is very, very slow and has problems dealing with realtime audio inputs
|
||||
mTimer->InitWithCallback(this, MediaEngine::DEFAULT_AUDIO_TIMER_MS*10,
|
||||
nsITimer::TYPE_REPEATING_PRECISE);
|
||||
nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP);
|
||||
#else
|
||||
mTimer->InitWithCallback(this, MediaEngine::DEFAULT_AUDIO_TIMER_MS,
|
||||
nsITimer::TYPE_REPEATING_PRECISE);
|
||||
nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP);
|
||||
#endif
|
||||
mState = kStarted;
|
||||
|
||||
|
@ -23,7 +23,7 @@ HASINSTANCE_HOOK_NAME = '_hasInstance'
|
||||
NEWRESOLVE_HOOK_NAME = '_newResolve'
|
||||
ENUMERATE_HOOK_NAME = '_enumerate'
|
||||
ENUM_ENTRY_VARIABLE_NAME = 'strings'
|
||||
INSTANCE_RESERVED_SLOTS = 3
|
||||
INSTANCE_RESERVED_SLOTS = 1
|
||||
|
||||
|
||||
def memberReservedSlot(member):
|
||||
@ -353,6 +353,7 @@ JS_NULL_OBJECT_OPS
|
||||
if self.descriptor.interface.getExtendedAttribute("Global"):
|
||||
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
|
||||
traceHook = "JS_GlobalObjectTraceHook"
|
||||
reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
|
||||
if not self.descriptor.workers:
|
||||
classExtensionAndObjectOps = """\
|
||||
{
|
||||
@ -388,6 +389,7 @@ JS_NULL_OBJECT_OPS
|
||||
"""
|
||||
else:
|
||||
classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
|
||||
reservedSlots = slotCount
|
||||
if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"):
|
||||
newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME
|
||||
classFlags += " | JSCLASS_NEW_RESOLVE"
|
||||
@ -423,6 +425,10 @@ JS_NULL_OBJECT_OPS
|
||||
},
|
||||
$*{descriptor}
|
||||
};
|
||||
static_assert(${instanceReservedSlots} == DOM_INSTANCE_RESERVED_SLOTS,
|
||||
"Must have the right minimal number of reserved slots.");
|
||||
static_assert(${reservedSlots} >= ${slotCount},
|
||||
"Must have enough reserved slots.");
|
||||
""",
|
||||
name=self.descriptor.interface.identifier.name,
|
||||
flags=classFlags,
|
||||
@ -433,7 +439,10 @@ JS_NULL_OBJECT_OPS
|
||||
call=callHook,
|
||||
trace=traceHook,
|
||||
classExtensionAndObjectOps=classExtensionAndObjectOps,
|
||||
descriptor=DOMClass(self.descriptor))
|
||||
descriptor=DOMClass(self.descriptor),
|
||||
instanceReservedSlots=INSTANCE_RESERVED_SLOTS,
|
||||
reservedSlots=reservedSlots,
|
||||
slotCount=slotCount)
|
||||
|
||||
|
||||
class CGDOMProxyJSClass(CGThing):
|
||||
@ -10029,6 +10038,12 @@ class CGDescriptor(CGThing):
|
||||
not descriptor.workers):
|
||||
cgThings.append(CGConstructorEnabled(descriptor))
|
||||
|
||||
if (descriptor.interface.hasMembersInSlots() and
|
||||
descriptor.interface.hasChildInterfaces()):
|
||||
raise TypeError("We don't support members in slots on "
|
||||
"non-leaf interfaces like %s" %
|
||||
descriptor.interface.identifier.name)
|
||||
|
||||
if descriptor.concrete:
|
||||
if descriptor.proxy:
|
||||
if descriptor.interface.totalMembersInSlots != 0:
|
||||
@ -10056,10 +10071,6 @@ class CGDescriptor(CGThing):
|
||||
cgThings.append(CGDOMJSClass(descriptor))
|
||||
cgThings.append(CGGetJSClassMethod(descriptor))
|
||||
if descriptor.interface.hasMembersInSlots():
|
||||
if descriptor.interface.hasChildInterfaces():
|
||||
raise TypeError("We don't support members in slots on "
|
||||
"non-leaf interfaces like %s" %
|
||||
descriptor.interface.identifier.name)
|
||||
cgThings.append(CGUpdateMemberSlotsMethod(descriptor))
|
||||
|
||||
if descriptor.interface.getExtendedAttribute("Global"):
|
||||
|
@ -80,13 +80,18 @@ using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
// Some utilities to handle annoying overloading of "A" tag for link and named anchor
|
||||
static char hrefText[] = "href";
|
||||
static char anchorTxt[] = "anchor";
|
||||
static char namedanchorText[] = "namedanchor";
|
||||
// Some utilities to handle overloading of "A" tag for link and named anchor.
|
||||
static bool
|
||||
IsLinkTag(const nsString& s)
|
||||
{
|
||||
return s.EqualsIgnoreCase("href");
|
||||
}
|
||||
|
||||
#define IsLinkTag(s) (s.EqualsIgnoreCase(hrefText))
|
||||
#define IsNamedAnchorTag(s) (s.EqualsIgnoreCase(anchorTxt) || s.EqualsIgnoreCase(namedanchorText))
|
||||
static bool
|
||||
IsNamedAnchorTag(const nsString& s)
|
||||
{
|
||||
return s.EqualsIgnoreCase("anchor") || s.EqualsIgnoreCase("namedanchor");
|
||||
}
|
||||
|
||||
nsHTMLEditor::nsHTMLEditor()
|
||||
: nsPlaintextEditor()
|
||||
@ -648,7 +653,7 @@ nsHTMLEditor::HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent)
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
nsresult rv;
|
||||
nsresult rv = NS_OK;
|
||||
if (nsHTMLEditUtils::IsTableElement(blockParent)) {
|
||||
rv = TabInTable(nativeKeyEvent->IsShift(), &handled);
|
||||
if (handled) {
|
||||
|
@ -60,6 +60,7 @@ class FilterNode;
|
||||
struct NativeSurface {
|
||||
NativeSurfaceType mType;
|
||||
SurfaceFormat mFormat;
|
||||
gfx::IntSize mSize;
|
||||
void *mSurface;
|
||||
};
|
||||
|
||||
@ -1034,10 +1035,6 @@ public:
|
||||
|
||||
static TemporaryRef<DrawTarget> CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
|
||||
|
||||
static TemporaryRef<SourceSurface>
|
||||
CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
static TemporaryRef<DrawTarget>
|
||||
CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFormat aFormat);
|
||||
|
||||
|
@ -81,70 +81,6 @@ private:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static bool
|
||||
GetCairoSurfaceSize(cairo_surface_t* surface, IntSize& size)
|
||||
{
|
||||
switch (cairo_surface_get_type(surface))
|
||||
{
|
||||
case CAIRO_SURFACE_TYPE_IMAGE:
|
||||
{
|
||||
size.width = cairo_image_surface_get_width(surface);
|
||||
size.height = cairo_image_surface_get_height(surface);
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_XLIB_SURFACE
|
||||
case CAIRO_SURFACE_TYPE_XLIB:
|
||||
{
|
||||
size.width = cairo_xlib_surface_get_width(surface);
|
||||
size.height = cairo_xlib_surface_get_height(surface);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CAIRO_HAS_QUARTZ_SURFACE
|
||||
case CAIRO_SURFACE_TYPE_QUARTZ:
|
||||
{
|
||||
CGContextRef cgc = cairo_quartz_surface_get_cg_context(surface);
|
||||
|
||||
// It's valid to call these CGBitmapContext functions on non-bitmap
|
||||
// contexts; they'll just return 0 in that case.
|
||||
size.width = CGBitmapContextGetWidth(cgc);
|
||||
size.height = CGBitmapContextGetHeight(cgc);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef CAIRO_HAS_WIN32_SURFACE
|
||||
#ifdef MOZ2D_HAS_MOZ_CAIRO
|
||||
case CAIRO_SURFACE_TYPE_WIN32:
|
||||
case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
|
||||
{
|
||||
size.width = cairo_win32_surface_get_width(surface);
|
||||
size.height = cairo_win32_surface_get_height(surface);
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
case CAIRO_SURFACE_TYPE_WIN32:
|
||||
{
|
||||
cairo_surface_t *img = cairo_win32_surface_get_image(surface);
|
||||
|
||||
if (!img) {
|
||||
// XXX - fix me
|
||||
MOZ_ASSERT(false);
|
||||
return true;
|
||||
}
|
||||
size.width = cairo_image_surface_get_width(img);
|
||||
size.height = cairo_image_surface_get_height(img);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
SupportsSelfCopy(cairo_surface_t* surface)
|
||||
{
|
||||
@ -1131,26 +1067,14 @@ TemporaryRef<SourceSurface>
|
||||
DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
|
||||
{
|
||||
if (aSurface.mType == NativeSurfaceType::CAIRO_SURFACE) {
|
||||
IntSize size;
|
||||
cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
|
||||
if (GetCairoSurfaceSize(surf, size)) {
|
||||
RefPtr<SourceSurfaceCairo> source =
|
||||
new SourceSurfaceCairo(surf, size, aSurface.mFormat);
|
||||
return source;
|
||||
if (aSurface.mSize.width <= 0 ||
|
||||
aSurface.mSize.height <= 0) {
|
||||
gfxWarning() << "Can't create a SourceSurface without a valid size";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
DrawTargetCairo::CreateSourceSurfaceForCairoSurface(cairo_surface_t *aSurface,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
IntSize size;
|
||||
if (GetCairoSurfaceSize(aSurface, size)) {
|
||||
cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
|
||||
RefPtr<SourceSurfaceCairo> source =
|
||||
new SourceSurfaceCairo(aSurface, size, aFormat);
|
||||
new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat);
|
||||
return source;
|
||||
}
|
||||
|
||||
|
@ -169,10 +169,6 @@ public:
|
||||
|
||||
static cairo_surface_t *GetDummySurface();
|
||||
|
||||
static TemporaryRef<SourceSurface>
|
||||
CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface,
|
||||
SurfaceFormat aFormat);
|
||||
|
||||
private: // methods
|
||||
// Init cairo surface without doing a cairo_surface_reference() call.
|
||||
bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
|
||||
|
@ -637,18 +637,6 @@ Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSiz
|
||||
return retVal;
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
Factory::CreateSourceSurfaceForCairoSurface(cairo_surface_t* aSurface,
|
||||
SurfaceFormat aFormat)
|
||||
{
|
||||
RefPtr<SourceSurface> retVal;
|
||||
|
||||
#ifdef USE_CAIRO
|
||||
retVal = DrawTargetCairo::CreateSourceSurfaceForCairoSurface(aSurface, aFormat);
|
||||
#endif
|
||||
return retVal;
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
TemporaryRef<DrawTarget>
|
||||
Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize)
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
|
||||
virtual TextureSourceBasic* AsSourceBasic() MOZ_OVERRIDE { return this; }
|
||||
|
||||
virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE { return mSurface; }
|
||||
virtual gfx::SourceSurface* GetSurface(DrawTarget* aTarget) MOZ_OVERRIDE { return mSurface; }
|
||||
|
||||
SurfaceFormat GetFormat() const MOZ_OVERRIDE
|
||||
{
|
||||
@ -293,7 +293,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
Matrix maskTransform;
|
||||
if (aEffectChain.mSecondaryEffects[EffectTypes::MASK]) {
|
||||
EffectMask *effectMask = static_cast<EffectMask*>(aEffectChain.mSecondaryEffects[EffectTypes::MASK].get());
|
||||
sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface();
|
||||
sourceMask = effectMask->mMaskTexture->AsSourceBasic()->GetSurface(dest);
|
||||
MOZ_ASSERT(effectMask->mMaskTransform.Is2D(), "How did we end up with a 3D transform here?!");
|
||||
MOZ_ASSERT(!effectMask->mIs3D);
|
||||
maskTransform = effectMask->mMaskTransform.As2D();
|
||||
@ -315,7 +315,7 @@ BasicCompositor::DrawQuad(const gfx::Rect& aRect,
|
||||
TextureSourceBasic* source = texturedEffect->mTexture->AsSourceBasic();
|
||||
|
||||
DrawSurfaceWithTextureCoords(dest, aRect,
|
||||
source->GetSurface(),
|
||||
source->GetSurface(dest),
|
||||
texturedEffect->mTextureCoords,
|
||||
texturedEffect->mFilter,
|
||||
aOpacity, sourceMask, &maskTransform);
|
||||
|
@ -46,7 +46,7 @@ MacIOSurfaceTextureHostBasic::MacIOSurfaceTextureHostBasic(
|
||||
}
|
||||
|
||||
gfx::SourceSurface*
|
||||
MacIOSurfaceTextureSourceBasic::GetSurface()
|
||||
MacIOSurfaceTextureSourceBasic::GetSurface(gfx::DrawTarget* aTarget)
|
||||
{
|
||||
if (!mSourceSurface) {
|
||||
mSourceSurface = mSurface->GetAsSurface();
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
|
||||
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
|
||||
virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
|
||||
virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE;
|
||||
virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) MOZ_OVERRIDE;
|
||||
|
||||
virtual void DeallocateDeviceData() MOZ_OVERRIDE { }
|
||||
|
||||
|
@ -22,7 +22,7 @@ class TextureSourceBasic
|
||||
{
|
||||
public:
|
||||
virtual ~TextureSourceBasic() {}
|
||||
virtual gfx::SourceSurface* GetSurface() = 0;
|
||||
virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) = 0;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -32,11 +32,15 @@ X11TextureSourceBasic::GetFormat() const
|
||||
}
|
||||
|
||||
SourceSurface*
|
||||
X11TextureSourceBasic::GetSurface()
|
||||
X11TextureSourceBasic::GetSurface(DrawTarget* aTarget)
|
||||
{
|
||||
if (!mSourceSurface) {
|
||||
mSourceSurface =
|
||||
Factory::CreateSourceSurfaceForCairoSurface(mSurface->CairoSurface(), GetFormat());
|
||||
NativeSurface surf;
|
||||
surf.mFormat = GetFormat();
|
||||
surf.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
surf.mSurface = mSurface->CairoSurface();
|
||||
surf.mSize = GetSize();
|
||||
mSourceSurface = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
|
||||
}
|
||||
return mSourceSurface;
|
||||
}
|
||||
@ -62,4 +66,4 @@ X11TextureSourceBasic::ContentTypeToSurfaceFormat(gfxContentType aType)
|
||||
default:
|
||||
return SurfaceFormat::UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
|
||||
virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
|
||||
|
||||
virtual gfx::SourceSurface* GetSurface() MOZ_OVERRIDE;
|
||||
virtual gfx::SourceSurface* GetSurface(gfx::DrawTarget* aTarget) MOZ_OVERRIDE;
|
||||
|
||||
virtual void DeallocateDeviceData() MOZ_OVERRIDE { }
|
||||
|
||||
|
@ -412,6 +412,8 @@ ThebesLayerD3D10::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode)
|
||||
destinationSurface = mD2DSurface;
|
||||
}
|
||||
|
||||
aRegion.SimplifyOutwardByArea(100 * 100);
|
||||
|
||||
MOZ_ASSERT(mDrawTarget);
|
||||
nsRefPtr<gfxContext> context = new gfxContext(mDrawTarget);
|
||||
|
||||
|
@ -97,6 +97,290 @@ void nsRegion::SimplifyOutward (uint32_t aMaxRects)
|
||||
}
|
||||
}
|
||||
|
||||
// compute the covered area difference between two rows.
|
||||
// by iterating over both rows simultaneously and adding up
|
||||
// the additional increase in area caused by extending each
|
||||
// of the rectangles to the combined height of both rows
|
||||
static uint32_t ComputeMergedAreaIncrease(pixman_box32_t *topRects,
|
||||
pixman_box32_t *topRectsEnd,
|
||||
pixman_box32_t *bottomRects,
|
||||
pixman_box32_t *bottomRectsEnd)
|
||||
{
|
||||
uint32_t totalArea = 0;
|
||||
struct pt {
|
||||
int32_t x, y;
|
||||
};
|
||||
|
||||
|
||||
pt *i = (pt*)topRects;
|
||||
pt *end_i = (pt*)topRectsEnd;
|
||||
pt *j = (pt*)bottomRects;
|
||||
pt *end_j = (pt*)bottomRectsEnd;
|
||||
bool top = false;
|
||||
bool bottom = false;
|
||||
|
||||
int cur_x = i->x;
|
||||
bool top_next = top;
|
||||
bool bottom_next = bottom;
|
||||
//XXX: we could probably simplify this condition and perhaps move it into the loop below
|
||||
if (j->x < cur_x) {
|
||||
cur_x = j->x;
|
||||
j++;
|
||||
bottom_next = !bottom;
|
||||
} else if (j->x == cur_x) {
|
||||
i++;
|
||||
top_next = !top;
|
||||
bottom_next = !bottom;
|
||||
j++;
|
||||
} else {
|
||||
top_next = !top;
|
||||
i++;
|
||||
}
|
||||
|
||||
int topRectsHeight = topRects->y2 - topRects->y1;
|
||||
int bottomRectsHeight = bottomRects->y2 - bottomRects->y1;
|
||||
int inbetweenHeight = bottomRects->y1 - topRects->y2;
|
||||
int width = cur_x;
|
||||
// top and bottom are the in-status to the left of cur_x
|
||||
do {
|
||||
if (top && !bottom) {
|
||||
totalArea += (inbetweenHeight+bottomRectsHeight)*width;
|
||||
} else if (bottom && !top) {
|
||||
totalArea += (inbetweenHeight+topRectsHeight)*width;
|
||||
} else if (bottom && top) {
|
||||
totalArea += (inbetweenHeight)*width;
|
||||
}
|
||||
top = top_next;
|
||||
bottom = bottom_next;
|
||||
// find the next edge
|
||||
if (i->x < j->x) {
|
||||
top_next = !top;
|
||||
width = i->x - cur_x;
|
||||
cur_x = i->x;
|
||||
i++;
|
||||
} else if (j->x < i->x) {
|
||||
bottom_next = !bottom;
|
||||
width = j->x - cur_x;
|
||||
cur_x = j->x;
|
||||
j++;
|
||||
} else { // i->x == j->x
|
||||
top_next = !top;
|
||||
bottom_next = !bottom;
|
||||
width = i->x - cur_x;
|
||||
cur_x = i->x;
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
} while (i < end_i && j < end_j);
|
||||
|
||||
// handle any remaining rects
|
||||
while (i < end_i) {
|
||||
width = i->x - cur_x;
|
||||
cur_x = i->x;
|
||||
i++;
|
||||
if (top)
|
||||
totalArea += (inbetweenHeight+bottomRectsHeight)*width;
|
||||
top = !top;
|
||||
}
|
||||
|
||||
while (j < end_j) {
|
||||
width = j->x - cur_x;
|
||||
cur_x = j->x;
|
||||
j++;
|
||||
if (bottom)
|
||||
totalArea += (inbetweenHeight+topRectsHeight)*width;
|
||||
bottom = !bottom;
|
||||
}
|
||||
return totalArea;
|
||||
}
|
||||
|
||||
static pixman_box32_t *
|
||||
CopyRow(pixman_box32_t *dest_it, pixman_box32_t *src_start, pixman_box32_t *src_end)
|
||||
{
|
||||
// XXX: std::copy
|
||||
pixman_box32_t *src_it = src_start;
|
||||
while (src_it < src_end) {
|
||||
*dest_it++ = *src_it++;
|
||||
}
|
||||
return dest_it;
|
||||
}
|
||||
|
||||
static pixman_box32_t *
|
||||
MergeRects(pixman_box32_t *topRects, pixman_box32_t *topRectsEnd,
|
||||
pixman_box32_t *bottomRects, pixman_box32_t *bottomRectsEnd,
|
||||
pixman_box32_t *tmpRect)
|
||||
{
|
||||
struct pt {
|
||||
int32_t x, y;
|
||||
};
|
||||
|
||||
pixman_box32_t *rect;
|
||||
// merge the two spans of rects
|
||||
pt *i = (pt*)topRects;
|
||||
pt *end_i = (pt*)topRectsEnd;
|
||||
pt *j = (pt*)bottomRects;
|
||||
pt *end_j = (pt*)bottomRectsEnd;
|
||||
bool top;
|
||||
bool bottom;
|
||||
|
||||
int cur_x = i->x;
|
||||
int32_t y1 = topRects->y1;
|
||||
int32_t y2 = bottomRects->y2;
|
||||
if (j->x < cur_x) {
|
||||
top = false;
|
||||
bottom = true;
|
||||
cur_x = j->x;
|
||||
j++;
|
||||
} else if (j->x == cur_x) {
|
||||
top = true;
|
||||
bottom = true;
|
||||
i++;
|
||||
j++;
|
||||
} else {
|
||||
top = true;
|
||||
bottom = false;
|
||||
i++;
|
||||
}
|
||||
|
||||
rect = tmpRect;
|
||||
bool started = false;
|
||||
do {
|
||||
if (started && !top && !bottom) {
|
||||
rect->x2 = cur_x;
|
||||
rect->y2 = y2;
|
||||
rect++;
|
||||
started = false;
|
||||
} else if (!started) {
|
||||
rect->x1 = cur_x;
|
||||
rect->y1 = y1;
|
||||
started = true;
|
||||
}
|
||||
|
||||
if (i >= end_i || j >= end_j)
|
||||
break;
|
||||
|
||||
if (i->x < j->x) {
|
||||
top = !top;
|
||||
cur_x = i->x;
|
||||
i++;
|
||||
} else if (j->x < i->x) {
|
||||
bottom = !bottom;
|
||||
cur_x = j->x;
|
||||
j++;
|
||||
} else { // i->x == j->x
|
||||
top = !top;
|
||||
bottom = !bottom;
|
||||
cur_x = i->x;
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
} while (true);
|
||||
|
||||
// handle any remaining rects
|
||||
while (i < end_i) {
|
||||
top = !top;
|
||||
cur_x = i->x;
|
||||
i++;
|
||||
if (!top) {
|
||||
rect->x2 = cur_x;
|
||||
rect->y2 = y2;
|
||||
rect++;
|
||||
} else {
|
||||
rect->x1 = cur_x;
|
||||
rect->y1 = y1;
|
||||
}
|
||||
}
|
||||
|
||||
while (j < end_j) {
|
||||
bottom = !bottom;
|
||||
cur_x = j->x;
|
||||
j++;
|
||||
if (!bottom) {
|
||||
rect->x2 = cur_x;
|
||||
rect->y2 = y2;
|
||||
rect++;
|
||||
} else {
|
||||
rect->x1 = cur_x;
|
||||
rect->y1 = y1;
|
||||
}
|
||||
}
|
||||
return rect;
|
||||
}
|
||||
|
||||
void nsRegion::SimplifyOutwardByArea(uint32_t aThreshold)
|
||||
{
|
||||
|
||||
pixman_box32_t *boxes;
|
||||
int n;
|
||||
boxes = pixman_region32_rectangles(&mImpl, &n);
|
||||
pixman_box32_t *end = boxes + n;
|
||||
pixman_box32_t *topRectsEnd = boxes+1;
|
||||
pixman_box32_t *topRects = boxes;
|
||||
|
||||
// we need some temporary storage for merging both rows of rectangles
|
||||
nsAutoTArray<pixman_box32_t, 10> tmpStorage;
|
||||
tmpStorage.SetCapacity(n);
|
||||
pixman_box32_t *tmpRect = tmpStorage.Elements();
|
||||
|
||||
pixman_box32_t *destRect = boxes;
|
||||
pixman_box32_t *rect = tmpRect;
|
||||
// find the end of the first span of rectangles
|
||||
while (topRectsEnd < end && topRectsEnd->y1 == topRects->y1) {
|
||||
topRectsEnd++;
|
||||
}
|
||||
|
||||
// if we only have one row we are done
|
||||
if (topRectsEnd == end)
|
||||
return;
|
||||
|
||||
pixman_box32_t *bottomRects = topRectsEnd;
|
||||
pixman_box32_t *bottomRectsEnd = bottomRects+1;
|
||||
do {
|
||||
// find the end of the bottom span of rectangles
|
||||
while (bottomRectsEnd < end && bottomRectsEnd->y1 == bottomRects->y1) {
|
||||
bottomRectsEnd++;
|
||||
}
|
||||
uint32_t totalArea = ComputeMergedAreaIncrease(topRects, topRectsEnd,
|
||||
bottomRects, bottomRectsEnd);
|
||||
|
||||
if (totalArea <= aThreshold) {
|
||||
// merge the rects into tmpRect
|
||||
rect = MergeRects(topRects, topRectsEnd, bottomRects, bottomRectsEnd, tmpRect);
|
||||
|
||||
// copy the merged rects back into the destination
|
||||
topRectsEnd = CopyRow(destRect, tmpRect, rect);
|
||||
topRects = destRect;
|
||||
bottomRects = bottomRectsEnd;
|
||||
destRect = topRects;
|
||||
} else {
|
||||
// copy the unmerged rects
|
||||
destRect = CopyRow(destRect, topRects, topRectsEnd);
|
||||
|
||||
topRects = bottomRects;
|
||||
topRectsEnd = bottomRectsEnd;
|
||||
bottomRects = bottomRectsEnd;
|
||||
if (bottomRectsEnd == end) {
|
||||
// copy the last row when we are done
|
||||
topRectsEnd = CopyRow(destRect, topRects, topRectsEnd);
|
||||
}
|
||||
}
|
||||
} while (bottomRectsEnd != end);
|
||||
|
||||
|
||||
uint32_t reducedCount = topRectsEnd - pixman_region32_rectangles(&this->mImpl, &n);
|
||||
// pixman has a special representation for
|
||||
// regions of 1 rectangle. So just use the
|
||||
// bounds in that case
|
||||
if (reducedCount > 1) {
|
||||
// reach into pixman and lower the number
|
||||
// of rects stored in data.
|
||||
this->mImpl.data->numRects = reducedCount;
|
||||
} else {
|
||||
*this = GetBounds();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void nsRegion::SimplifyInward (uint32_t aMaxRects)
|
||||
{
|
||||
NS_ASSERTION(aMaxRects >= 1, "Invalid max rect count");
|
||||
|
@ -242,6 +242,13 @@ public:
|
||||
* the same as for the current region.
|
||||
*/
|
||||
void SimplifyOutward (uint32_t aMaxRects);
|
||||
/**
|
||||
* Simplify the region by adding at most aThreshold area between spans of
|
||||
* rects. The simplified region will be a superset of the original region.
|
||||
* The simplified region's bounding box will be the same as for the current
|
||||
* region.
|
||||
*/
|
||||
void SimplifyOutwardByArea(uint32_t aThreshold);
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by removing area from
|
||||
* it if necessary. The simplified region will be a subset of the
|
||||
@ -539,6 +546,10 @@ public:
|
||||
{
|
||||
mImpl.SimplifyOutward (aMaxRects);
|
||||
}
|
||||
void SimplifyOutwardByArea (uint32_t aThreshold)
|
||||
{
|
||||
mImpl.SimplifyOutwardByArea (aThreshold);
|
||||
}
|
||||
/**
|
||||
* Make sure the region has at most aMaxRects by removing area from
|
||||
* it if necessary. The simplified region will be a subset of the
|
||||
|
@ -171,3 +171,110 @@ TEST(Gfx, RegionScaleToInside) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST(Gfx, RegionSimplify) {
|
||||
{ // ensure simplify works on a single rect
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
|
||||
r.SimplifyOutwardByArea(100*100);
|
||||
|
||||
nsRegion result(nsRect(0,100,200,100));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not the same";
|
||||
}
|
||||
|
||||
{ // the rectangles will be merged
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
r.Or(r, nsRect(0,200,300,200));
|
||||
|
||||
r.SimplifyOutwardByArea(100*100);
|
||||
|
||||
nsRegion result(nsRect(0,100,300,300));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not merged";
|
||||
}
|
||||
|
||||
{ // two rectangle on the first span
|
||||
// one on the second
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
r.Or(r, nsRect(0,200,300,200));
|
||||
r.Or(r, nsRect(250,100,50,100));
|
||||
|
||||
EXPECT_TRUE(r.GetNumRects() == 3) <<
|
||||
"wrong number of rects";
|
||||
|
||||
r.SimplifyOutwardByArea(100*100);
|
||||
|
||||
nsRegion result(nsRect(0,100,300,300));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not merged";
|
||||
}
|
||||
|
||||
{ // the rectangles will be merged
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
r.Or(r, nsRect(0,200,300,200));
|
||||
r.Or(r, nsRect(250,100,50,100));
|
||||
r.Sub(r, nsRect(200,200,40,200));
|
||||
|
||||
EXPECT_TRUE(r.GetNumRects() == 4) <<
|
||||
"wrong number of rects";
|
||||
|
||||
r.SimplifyOutwardByArea(100*100);
|
||||
|
||||
nsRegion result(nsRect(0,100,300,300));
|
||||
result.Sub(result, nsRect(200,100,40,300));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not merged";
|
||||
}
|
||||
|
||||
{ // three spans of rectangles
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
r.Or(r, nsRect(0,200,300,200));
|
||||
r.Or(r, nsRect(250,100,50,50));
|
||||
r.Sub(r, nsRect(200,200,40,200));
|
||||
|
||||
r.SimplifyOutwardByArea(100*100);
|
||||
|
||||
nsRegion result(nsRect(0,100,300,300));
|
||||
result.Sub(result, nsRect(200,100,40,300));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not merged";
|
||||
}
|
||||
|
||||
{ // three spans of rectangles and an unmerged rectangle
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
r.Or(r, nsRect(0,200,300,200));
|
||||
r.Or(r, nsRect(250,100,50,50));
|
||||
r.Sub(r, nsRect(200,200,40,200));
|
||||
r.Or(r, nsRect(250,900,150,50));
|
||||
|
||||
r.SimplifyOutwardByArea(100*100);
|
||||
|
||||
nsRegion result(nsRect(0,100,300,300));
|
||||
result.Sub(result, nsRect(200,100,40,300));
|
||||
result.Or(result, nsRect(250,900,150,50));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not merged";
|
||||
}
|
||||
|
||||
{ // unmerged regions
|
||||
nsRegion r(nsRect(0,100,200,100));
|
||||
r.Or(r, nsRect(0,200,300,200));
|
||||
|
||||
r.SimplifyOutwardByArea(100);
|
||||
|
||||
nsRegion result(nsRect(0,100,200,100));
|
||||
result.Or(result, nsRect(0,200,300,200));
|
||||
|
||||
EXPECT_TRUE(r.IsEqual(result)) <<
|
||||
"regions not merged";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
#include "gfxASurface.h"
|
||||
#include "gfxContext.h"
|
||||
|
@ -39,365 +39,6 @@
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
|
||||
// rounding and truncation functions for a Freetype floating point number
|
||||
// (FT26Dot6) stored in a 32bit integer with high 26 bits for the integer
|
||||
// part and low 6 bits for the fractional part.
|
||||
#define MOZ_FT_ROUND(x) (((x) + 32) & ~63) // 63 = 2^6 - 1
|
||||
#define MOZ_FT_TRUNC(x) ((x) >> 6)
|
||||
#define CONVERT_DESIGN_UNITS_TO_PIXELS(v, s) \
|
||||
MOZ_FT_TRUNC(MOZ_FT_ROUND(FT_MulFix((v) , (s))))
|
||||
|
||||
#ifndef ANDROID // not needed on Android, we use the generic gfxFontGroup
|
||||
/**
|
||||
* gfxFT2FontGroup
|
||||
*/
|
||||
|
||||
static PRLogModuleInfo *
|
||||
GetFontLog()
|
||||
{
|
||||
static PRLogModuleInfo *sLog;
|
||||
if (!sLog)
|
||||
sLog = PR_NewLogModule("ft2fonts");
|
||||
return sLog;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxFT2FontGroup::FontCallback(const nsAString& fontName,
|
||||
const nsACString& genericName,
|
||||
bool aUseFontSet,
|
||||
void *closure)
|
||||
{
|
||||
nsTArray<nsString> *sa = static_cast<nsTArray<nsString>*>(closure);
|
||||
|
||||
if (!fontName.IsEmpty() && !sa->Contains(fontName)) {
|
||||
sa->AppendElement(fontName);
|
||||
#ifdef DEBUG_pavlov
|
||||
printf(" - %s\n", NS_ConvertUTF16toUTF8(fontName).get());
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
gfxFT2FontGroup::gfxFT2FontGroup(const nsAString& families,
|
||||
const gfxFontStyle *aStyle,
|
||||
gfxUserFontSet *aUserFontSet)
|
||||
: gfxFontGroup(families, aStyle, aUserFontSet)
|
||||
{
|
||||
#ifdef DEBUG_pavlov
|
||||
printf("Looking for %s\n", NS_ConvertUTF16toUTF8(families).get());
|
||||
#endif
|
||||
nsTArray<nsString> familyArray;
|
||||
ForEachFont(FontCallback, &familyArray);
|
||||
|
||||
if (familyArray.Length() == 0) {
|
||||
nsAutoString prefFamilies;
|
||||
gfxToolkitPlatform::GetPlatform()->GetPrefFonts(aStyle->language, prefFamilies, nullptr);
|
||||
if (!prefFamilies.IsEmpty()) {
|
||||
ForEachFont(prefFamilies, aStyle->language, FontCallback, &familyArray);
|
||||
}
|
||||
}
|
||||
if (familyArray.Length() == 0) {
|
||||
#if defined(MOZ_WIDGET_QT) /* FIXME DFB */
|
||||
printf("failde to find a font. sadface\n");
|
||||
// We want to get rid of this entirely at some point, but first we need real lists of fonts.
|
||||
QFont defaultFont;
|
||||
QFontInfo fi (defaultFont);
|
||||
familyArray.AppendElement(nsDependentString(static_cast<const char16_t *>(fi.family().utf16())));
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
FcResult result;
|
||||
FcChar8 *family = nullptr;
|
||||
FcPattern* pat = FcPatternCreate();
|
||||
FcPattern *match = FcFontMatch(nullptr, pat, &result);
|
||||
if (match)
|
||||
FcPatternGetString(match, FC_FAMILY, 0, &family);
|
||||
if (family)
|
||||
familyArray.AppendElement(NS_ConvertUTF8toUTF16((char*)family));
|
||||
#elif defined(XP_WIN)
|
||||
HGDIOBJ hGDI = ::GetStockObject(SYSTEM_FONT);
|
||||
LOGFONTW logFont;
|
||||
if (hGDI && ::GetObjectW(hGDI, sizeof(logFont), &logFont))
|
||||
familyArray.AppendElement(nsDependentString(logFont.lfFaceName));
|
||||
#elif defined(ANDROID)
|
||||
familyArray.AppendElement(NS_LITERAL_STRING("Droid Sans"));
|
||||
familyArray.AppendElement(NS_LITERAL_STRING("Roboto"));
|
||||
#else
|
||||
#error "Platform not supported"
|
||||
#endif
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < familyArray.Length(); i++) {
|
||||
nsRefPtr<gfxFT2Font> font = gfxFT2Font::GetOrMakeFont(familyArray[i], &mStyle);
|
||||
if (font) {
|
||||
mFonts.AppendElement(font);
|
||||
}
|
||||
}
|
||||
NS_ASSERTION(mFonts.Length() > 0, "We need at least one font in a fontgroup");
|
||||
}
|
||||
|
||||
gfxFT2FontGroup::~gfxFT2FontGroup()
|
||||
{
|
||||
}
|
||||
|
||||
gfxFontGroup *
|
||||
gfxFT2FontGroup::Copy(const gfxFontStyle *aStyle)
|
||||
{
|
||||
return new gfxFT2FontGroup(mFamilies, aStyle, nullptr);
|
||||
}
|
||||
|
||||
// Helper function to return the leading UTF-8 character in a char pointer
|
||||
// as 32bit number. Also sets the length of the current character (i.e. the
|
||||
// offset to the next one) in the second argument
|
||||
uint32_t getUTF8CharAndNext(const uint8_t *aString, uint8_t *aLength)
|
||||
{
|
||||
*aLength = 1;
|
||||
if (aString[0] < 0x80) { // normal 7bit ASCII char
|
||||
return aString[0];
|
||||
}
|
||||
if ((aString[0] >> 5) == 6) { // two leading ones -> two bytes
|
||||
*aLength = 2;
|
||||
return ((aString[0] & 0x1F) << 6) + (aString[1] & 0x3F);
|
||||
}
|
||||
if ((aString[0] >> 4) == 14) { // three leading ones -> three bytes
|
||||
*aLength = 3;
|
||||
return ((aString[0] & 0x0F) << 12) + ((aString[1] & 0x3F) << 6) +
|
||||
(aString[2] & 0x3F);
|
||||
}
|
||||
if ((aString[0] >> 4) == 15) { // four leading ones -> four bytes
|
||||
*aLength = 4;
|
||||
return ((aString[0] & 0x07) << 18) + ((aString[1] & 0x3F) << 12) +
|
||||
((aString[2] & 0x3F) << 6) + (aString[3] & 0x3F);
|
||||
}
|
||||
return aString[0];
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
AddFontNameToArray(const nsAString& aName,
|
||||
const nsACString& aGenericName,
|
||||
bool aUseFontSet,
|
||||
void *aClosure)
|
||||
{
|
||||
if (!aName.IsEmpty()) {
|
||||
nsTArray<nsString> *list = static_cast<nsTArray<nsString> *>(aClosure);
|
||||
|
||||
if (list->IndexOf(aName) == list->NoIndex)
|
||||
list->AppendElement(aName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
gfxFT2FontGroup::FamilyListToArrayList(const nsString& aFamilies,
|
||||
nsIAtom *aLangGroup,
|
||||
nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList)
|
||||
{
|
||||
nsAutoTArray<nsString, 15> fonts;
|
||||
ForEachFont(aFamilies, aLangGroup, AddFontNameToArray, &fonts);
|
||||
|
||||
uint32_t len = fonts.Length();
|
||||
for (uint32_t i = 0; i < len; ++i) {
|
||||
const nsString& str = fonts[i];
|
||||
nsRefPtr<gfxFontEntry> fe = (gfxToolkitPlatform::GetPlatform()->FindFontEntry(str, mStyle));
|
||||
aFontEntryList->AppendElement(fe);
|
||||
}
|
||||
}
|
||||
|
||||
void gfxFT2FontGroup::GetPrefFonts(nsIAtom *aLangGroup, nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList)
|
||||
{
|
||||
NS_ASSERTION(aLangGroup, "aLangGroup is null");
|
||||
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
|
||||
nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
|
||||
nsAutoCString key;
|
||||
aLangGroup->ToUTF8String(key);
|
||||
key.Append("-");
|
||||
key.AppendInt(GetStyle()->style);
|
||||
key.Append("-");
|
||||
key.AppendInt(GetStyle()->weight);
|
||||
if (!platform->GetPrefFontEntries(key, &fonts)) {
|
||||
nsString fontString;
|
||||
platform->GetPrefFonts(aLangGroup, fontString);
|
||||
if (fontString.IsEmpty())
|
||||
return;
|
||||
|
||||
FamilyListToArrayList(fontString, aLangGroup, &fonts);
|
||||
|
||||
platform->SetPrefFontEntries(key, fonts);
|
||||
}
|
||||
aFontEntryList.AppendElements(fonts);
|
||||
}
|
||||
|
||||
static int32_t GetCJKLangGroupIndex(const char *aLangGroup) {
|
||||
int32_t i;
|
||||
for (i = 0; i < COUNT_OF_CJK_LANG_GROUP; i++) {
|
||||
if (!PL_strcasecmp(aLangGroup, sCJKLangGroup[i]))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// this function assigns to the array passed in.
|
||||
void gfxFT2FontGroup::GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList) {
|
||||
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
|
||||
|
||||
nsAutoCString key("x-internal-cjk-");
|
||||
key.AppendInt(mStyle.style);
|
||||
key.Append("-");
|
||||
key.AppendInt(mStyle.weight);
|
||||
|
||||
if (!platform->GetPrefFontEntries(key, &aFontEntryList)) {
|
||||
NS_ENSURE_TRUE_VOID(Preferences::GetRootBranch());
|
||||
// Add the CJK pref fonts from accept languages, the order should be same order
|
||||
nsAdoptingCString list = Preferences::GetLocalizedCString("intl.accept_languages");
|
||||
if (!list.IsEmpty()) {
|
||||
const char kComma = ',';
|
||||
const char *p, *p_end;
|
||||
list.BeginReading(p);
|
||||
list.EndReading(p_end);
|
||||
while (p < p_end) {
|
||||
while (nsCRT::IsAsciiSpace(*p)) {
|
||||
if (++p == p_end)
|
||||
break;
|
||||
}
|
||||
if (p == p_end)
|
||||
break;
|
||||
const char *start = p;
|
||||
while (++p != p_end && *p != kComma)
|
||||
/* nothing */ ;
|
||||
nsAutoCString lang(Substring(start, p));
|
||||
lang.CompressWhitespace(false, true);
|
||||
int32_t index = GetCJKLangGroupIndex(lang.get());
|
||||
if (index >= 0) {
|
||||
nsCOMPtr<nsIAtom> atom = do_GetAtom(sCJKLangGroup[index]);
|
||||
GetPrefFonts(atom, aFontEntryList);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the system locale
|
||||
#ifdef XP_WIN
|
||||
switch (::GetACP()) {
|
||||
case 932: GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList); break;
|
||||
case 936: GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList); break;
|
||||
case 949: GetPrefFonts(nsGkAtoms::ko, aFontEntryList); break;
|
||||
// XXX Don't we need to append nsGkAtoms::zh_hk if the codepage is 950?
|
||||
case 950: GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList); break;
|
||||
}
|
||||
#else
|
||||
const char *ctype = setlocale(LC_CTYPE, nullptr);
|
||||
if (ctype) {
|
||||
if (!PL_strncasecmp(ctype, "ja", 2)) {
|
||||
GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList);
|
||||
} else if (!PL_strncasecmp(ctype, "zh_cn", 5)) {
|
||||
GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList);
|
||||
} else if (!PL_strncasecmp(ctype, "zh_hk", 5)) {
|
||||
GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList);
|
||||
} else if (!PL_strncasecmp(ctype, "zh_tw", 5)) {
|
||||
GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList);
|
||||
} else if (!PL_strncasecmp(ctype, "ko", 2)) {
|
||||
GetPrefFonts(nsGkAtoms::ko, aFontEntryList);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// last resort...
|
||||
GetPrefFonts(nsGkAtoms::Japanese, aFontEntryList);
|
||||
GetPrefFonts(nsGkAtoms::ko, aFontEntryList);
|
||||
GetPrefFonts(nsGkAtoms::zh_cn, aFontEntryList);
|
||||
GetPrefFonts(nsGkAtoms::zh_hk, aFontEntryList);
|
||||
GetPrefFonts(nsGkAtoms::zh_tw, aFontEntryList);
|
||||
|
||||
platform->SetPrefFontEntries(key, aFontEntryList);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<gfxFT2Font>
|
||||
gfxFT2FontGroup::WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList, uint32_t aCh)
|
||||
{
|
||||
for (uint32_t i = 0; i < aFontEntryList.Length(); i++) {
|
||||
gfxFontEntry *fe = aFontEntryList[i].get();
|
||||
if (fe->HasCharacter(aCh)) {
|
||||
nsRefPtr<gfxFT2Font> font =
|
||||
gfxFT2Font::GetOrMakeFont(static_cast<FontEntry*>(fe), &mStyle);
|
||||
return font.forget();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxFont>
|
||||
gfxFT2FontGroup::WhichPrefFontSupportsChar(uint32_t aCh)
|
||||
{
|
||||
if (aCh > 0xFFFF)
|
||||
return nullptr;
|
||||
|
||||
nsRefPtr<gfxFT2Font> selectedFont;
|
||||
|
||||
// check out the style's language
|
||||
nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
|
||||
GetPrefFonts(mStyle.language, fonts);
|
||||
selectedFont = WhichFontSupportsChar(fonts, aCh);
|
||||
|
||||
// otherwise search prefs
|
||||
if (!selectedFont) {
|
||||
uint32_t unicodeRange = FindCharUnicodeRange(aCh);
|
||||
|
||||
/* special case CJK */
|
||||
if (unicodeRange == kRangeSetCJK) {
|
||||
if (PR_LOG_TEST(GetFontLog(), PR_LOG_DEBUG)) {
|
||||
PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: CJK"));
|
||||
}
|
||||
|
||||
nsAutoTArray<nsRefPtr<gfxFontEntry>, 15> fonts;
|
||||
GetCJKPrefFonts(fonts);
|
||||
selectedFont = WhichFontSupportsChar(fonts, aCh);
|
||||
} else {
|
||||
nsIAtom *langGroup = LangGroupFromUnicodeRange(unicodeRange);
|
||||
if (langGroup) {
|
||||
PR_LOG(GetFontLog(), PR_LOG_DEBUG, (" - Trying to find fonts for: %s", nsAtomCString(langGroup).get()));
|
||||
|
||||
nsAutoTArray<nsRefPtr<gfxFontEntry>, 5> fonts;
|
||||
GetPrefFonts(langGroup, fonts);
|
||||
selectedFont = WhichFontSupportsChar(fonts, aCh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedFont) {
|
||||
nsRefPtr<gfxFont> f = static_cast<gfxFont*>(selectedFont.get());
|
||||
return f.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxFont>
|
||||
gfxFT2FontGroup::WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript)
|
||||
{
|
||||
#if defined(XP_WIN) || defined(ANDROID)
|
||||
FontEntry *fe = static_cast<FontEntry*>
|
||||
(gfxPlatformFontList::PlatformFontList()->
|
||||
SystemFindFontForChar(aCh, aRunScript, &mStyle));
|
||||
if (fe) {
|
||||
nsRefPtr<gfxFT2Font> f = gfxFT2Font::GetOrMakeFont(fe, &mStyle);
|
||||
nsRefPtr<gfxFont> font = f.get();
|
||||
return font.forget();
|
||||
}
|
||||
#else
|
||||
nsRefPtr<gfxFont> selectedFont;
|
||||
nsRefPtr<gfxFont> refFont = GetFontAt(0);
|
||||
gfxToolkitPlatform *platform = gfxToolkitPlatform::GetPlatform();
|
||||
selectedFont = platform->FindFontForChar(aCh, refFont);
|
||||
if (selectedFont)
|
||||
return selectedFont.forget();
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif // !ANDROID
|
||||
|
||||
/**
|
||||
* gfxFT2Font
|
||||
*/
|
||||
|
@ -92,43 +92,5 @@ protected:
|
||||
CharGlyphMap mCharGlyphCache;
|
||||
};
|
||||
|
||||
#ifndef ANDROID // not needed on Android, uses the standard gfxFontGroup directly
|
||||
class gfxFT2FontGroup : public gfxFontGroup {
|
||||
public: // new functions
|
||||
gfxFT2FontGroup (const nsAString& families,
|
||||
const gfxFontStyle *aStyle,
|
||||
gfxUserFontSet *aUserFontSet);
|
||||
virtual ~gfxFT2FontGroup ();
|
||||
|
||||
protected: // from gfxFontGroup
|
||||
|
||||
virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle);
|
||||
|
||||
|
||||
protected: // new functions
|
||||
|
||||
static bool FontCallback (const nsAString & fontName,
|
||||
const nsACString & genericName,
|
||||
bool aUseFontSet,
|
||||
void *closure);
|
||||
bool mEnableKerning;
|
||||
|
||||
void GetPrefFonts(nsIAtom *aLangGroup,
|
||||
nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
|
||||
void GetCJKPrefFonts(nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList);
|
||||
void FamilyListToArrayList(const nsString& aFamilies,
|
||||
nsIAtom *aLangGroup,
|
||||
nsTArray<nsRefPtr<gfxFontEntry> > *aFontEntryList);
|
||||
already_AddRefed<gfxFT2Font> WhichFontSupportsChar(const nsTArray<nsRefPtr<gfxFontEntry> >& aFontEntryList,
|
||||
uint32_t aCh);
|
||||
already_AddRefed<gfxFont> WhichPrefFontSupportsChar(uint32_t aCh);
|
||||
already_AddRefed<gfxFont>
|
||||
WhichSystemFontSupportsChar(uint32_t aCh, int32_t aRunScript);
|
||||
|
||||
nsTArray<gfxTextRange> mRanges;
|
||||
nsString mString;
|
||||
};
|
||||
#endif // !ANDROID
|
||||
|
||||
#endif /* GFX_FT2FONTS_H */
|
||||
|
||||
|
@ -739,6 +739,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
surf.mFormat = format;
|
||||
surf.mType = NativeSurfaceType::D3D10_TEXTURE;
|
||||
surf.mSurface = static_cast<gfxD2DSurface*>(aSurface)->GetTexture();
|
||||
surf.mSize = ToIntSize(aSurface->GetSize());
|
||||
mozilla::gfx::DrawTarget *dt = static_cast<mozilla::gfx::DrawTarget*>(aSurface->GetData(&kDrawTarget));
|
||||
if (dt) {
|
||||
dt->Flush();
|
||||
@ -753,6 +754,7 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa
|
||||
surf.mFormat = format;
|
||||
surf.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
surf.mSurface = aSurface->CairoSurface();
|
||||
surf.mSize = ToIntSize(aSurface->GetSize());
|
||||
srcBuffer = aTarget->CreateSourceSurfaceFromNativeSurface(surf);
|
||||
|
||||
if (srcBuffer) {
|
||||
|
@ -205,6 +205,7 @@ private:
|
||||
DECL_GFX_PREF(Once, "layout.css.touch_action.enabled", TouchActionEnabled, bool, false);
|
||||
DECL_GFX_PREF(Once, "layout.frame_rate", LayoutFrameRate, int32_t, -1);
|
||||
DECL_GFX_PREF(Live, "layout.display-list.dump", LayoutDumpDisplayList, bool, false);
|
||||
DECL_GFX_PREF(Once, "layout.paint_rects_separately", LayoutPaintRectsSeparately, bool, true);
|
||||
|
||||
DECL_GFX_PREF(Live, "nglayout.debug.widget_update_flashing", WidgetUpdateFlashing, bool, false);
|
||||
|
||||
|
@ -575,18 +575,19 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
|
||||
cairo_surface_destroy(tempXlibSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SurfaceFormat moz2DFormat =
|
||||
cairo_surface_get_content(tempXlibSurface) == CAIRO_CONTENT_COLOR ?
|
||||
SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8;
|
||||
if (method != eAlphaExtraction) {
|
||||
if (drawTarget) {
|
||||
// It doesn't matter if moz2DFormat doesn't exactly match the format
|
||||
// of tempXlibSurface, since this DrawTarget just wraps the cairo
|
||||
// drawing.
|
||||
NativeSurface native;
|
||||
native.mFormat = moz2DFormat;
|
||||
native.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
native.mSurface = tempXlibSurface;
|
||||
native.mSize = ToIntSize(size);
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
Factory::CreateSourceSurfaceForCairoSurface(tempXlibSurface,
|
||||
moz2DFormat);
|
||||
drawTarget->CreateSourceSurfaceFromNativeSurface(native);
|
||||
if (sourceSurface) {
|
||||
drawTarget->DrawSurface(sourceSurface,
|
||||
Rect(offset.x, offset.y, size.width, size.height),
|
||||
@ -622,9 +623,13 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
|
||||
|
||||
gfxASurface* paintSurface = blackImage;
|
||||
if (drawTarget) {
|
||||
NativeSurface native;
|
||||
native.mFormat = moz2DFormat;
|
||||
native.mType = NativeSurfaceType::CAIRO_SURFACE;
|
||||
native.mSurface = tempXlibSurface;
|
||||
native.mSize = ToIntSize(size);
|
||||
RefPtr<SourceSurface> sourceSurface =
|
||||
Factory::CreateSourceSurfaceForCairoSurface(paintSurface->CairoSurface(),
|
||||
moz2DFormat);
|
||||
drawTarget->CreateSourceSurfaceFromNativeSurface(native);
|
||||
if (sourceSurface) {
|
||||
drawTarget->DrawSurface(sourceSurface,
|
||||
Rect(offset.x, offset.y, size.width, size.height),
|
||||
|
@ -280,6 +280,11 @@ ProcessOrDeferMessage(HWND hwnd,
|
||||
case WM_SYNCPAINT:
|
||||
return 0;
|
||||
|
||||
// This message causes QuickTime to make re-entrant calls.
|
||||
// Simply discarding it doesn't seem to hurt anything.
|
||||
case WM_APP-1:
|
||||
return 0;
|
||||
|
||||
default: {
|
||||
if (uMsg && uMsg == mozilla::widget::sAppShellGeckoMsgId) {
|
||||
// Widget's registered native event callback
|
||||
@ -390,8 +395,10 @@ WindowIsDeferredWindow(HWND hWnd)
|
||||
|
||||
// Plugin windows that can trigger ipc calls in child:
|
||||
// 'ShockwaveFlashFullScreen' - flash fullscreen window
|
||||
// 'QTNSHIDDEN' - QuickTime
|
||||
// 'AGFullScreenWinClass' - silverlight fullscreen window
|
||||
if (className.EqualsLiteral("ShockwaveFlashFullScreen") ||
|
||||
className.EqualsLiteral("QTNSHIDDEN") ||
|
||||
className.EqualsLiteral("AGFullScreenWinClass")) {
|
||||
return true;
|
||||
}
|
||||
|
@ -421,7 +421,11 @@ struct JSClass {
|
||||
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
|
||||
// previously allowed, but is now an ES5 violation and thus unsupported.
|
||||
//
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 31)
|
||||
// JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at
|
||||
// the beginning of every global object's slots for use by the
|
||||
// application.
|
||||
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 3
|
||||
#define JSCLASS_GLOBAL_SLOT_COUNT (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 31)
|
||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
|
||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
|
||||
#define JSCLASS_GLOBAL_FLAGS \
|
||||
|
@ -2088,8 +2088,13 @@ dnl ===============================================================
|
||||
if test "$GNU_CC"; then
|
||||
AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
|
||||
AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
|
||||
case "${OS_TARGET}" in
|
||||
Darwin|Android)
|
||||
if test -n "$gonkdir"; then
|
||||
visibility_target=Gonk
|
||||
else
|
||||
visibility_target=$OS_TARGET
|
||||
fi
|
||||
case "$visibility_target" in
|
||||
Darwin|Gonk)
|
||||
VISIBILITY_FLAGS='-fvisibility=hidden'
|
||||
;;
|
||||
*)
|
||||
|
@ -38,7 +38,7 @@ class FreeOp;
|
||||
namespace gc {
|
||||
|
||||
struct Arena;
|
||||
struct ArenaList;
|
||||
class ArenaList;
|
||||
struct ArenaHeader;
|
||||
struct Chunk;
|
||||
|
||||
|
108
js/src/jsgc.cpp
108
js/src/jsgc.cpp
@ -498,20 +498,6 @@ Arena::finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert an arena into the list in appropriate position and update the cursor
|
||||
* to ensure that any arena before the cursor is full.
|
||||
*/
|
||||
void ArenaList::insert(ArenaHeader *a)
|
||||
{
|
||||
JS_ASSERT(a);
|
||||
JS_ASSERT_IF(!head, cursor == &head);
|
||||
a->next = *cursor;
|
||||
*cursor = a;
|
||||
if (!a->hasFreeThings())
|
||||
cursor = &a->next;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline bool
|
||||
FinalizeTypedArenas(FreeOp *fop,
|
||||
@ -538,7 +524,7 @@ FinalizeTypedArenas(FreeOp *fop,
|
||||
*src = aheader->next;
|
||||
bool allClear = aheader->getArena()->finalize<T>(fop, thingKind, thingSize);
|
||||
if (!allClear)
|
||||
dest.insert(aheader);
|
||||
dest.insertAtCursor(aheader);
|
||||
else if (releaseArenas)
|
||||
aheader->chunk()->releaseArena(aheader);
|
||||
else
|
||||
@ -548,13 +534,14 @@ FinalizeTypedArenas(FreeOp *fop,
|
||||
if (budget.isOverBudget())
|
||||
return false;
|
||||
}
|
||||
dest.deepCheck();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize the list. On return al->cursor points to the first non-empty arena
|
||||
* after the al->head.
|
||||
* Finalize the list. On return, |al|'s cursor points to the first non-empty
|
||||
* arena in the list (which may be null if all arenas are full).
|
||||
*/
|
||||
static bool
|
||||
FinalizeArenas(FreeOp *fop,
|
||||
@ -563,7 +550,7 @@ FinalizeArenas(FreeOp *fop,
|
||||
AllocKind thingKind,
|
||||
SliceBudget &budget)
|
||||
{
|
||||
switch(thingKind) {
|
||||
switch (thingKind) {
|
||||
case FINALIZE_OBJECT0:
|
||||
case FINALIZE_OBJECT0_BACKGROUND:
|
||||
case FINALIZE_OBJECT2:
|
||||
@ -935,7 +922,7 @@ void
|
||||
Chunk::recycleArena(ArenaHeader *aheader, ArenaList &dest, AllocKind thingKind)
|
||||
{
|
||||
aheader->getArena()->setAsFullyUnused(thingKind);
|
||||
dest.insert(aheader);
|
||||
dest.insertAtCursor(aheader);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1484,13 +1471,13 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind];
|
||||
if (*bfs != BFS_DONE) {
|
||||
/*
|
||||
* We cannot search the arena list for free things while the
|
||||
* background finalization runs and can modify head or cursor at any
|
||||
* moment. So we always allocate a new arena in that case.
|
||||
* We cannot search the arena list for free things while background
|
||||
* finalization runs and can modify it at any moment. So we always
|
||||
* allocate a new arena in that case.
|
||||
*/
|
||||
maybeLock.lock(zone->runtimeFromAnyThread());
|
||||
if (*bfs == BFS_RUN) {
|
||||
JS_ASSERT(!*al->cursor);
|
||||
JS_ASSERT(al->isCursorAtEnd());
|
||||
chunk = PickChunk(zone);
|
||||
if (!chunk) {
|
||||
/*
|
||||
@ -1509,9 +1496,7 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
if (!chunk) {
|
||||
if (ArenaHeader *aheader = *al->cursor) {
|
||||
JS_ASSERT(aheader->hasFreeThings());
|
||||
|
||||
if (ArenaHeader *aheader = al->arenaAfterCursor()) {
|
||||
/*
|
||||
* Normally, the empty arenas are returned to the chunk
|
||||
* and should not present on the list. In parallel
|
||||
@ -1519,7 +1504,8 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
* list to avoid synchronizing on the chunk.
|
||||
*/
|
||||
JS_ASSERT(!aheader->isEmpty() || InParallelSection());
|
||||
al->cursor = &aheader->next;
|
||||
|
||||
al->moveCursorPast(aheader);
|
||||
|
||||
/*
|
||||
* Move the free span stored in the arena to the free list and
|
||||
@ -1551,11 +1537,11 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
* as full as its single free span is moved to the free lits, and insert
|
||||
* it to the list as a fully allocated arena.
|
||||
*
|
||||
* We add the arena before the the head, not after the tail pointed by the
|
||||
* cursor, so after the GC the most recently added arena will be used first
|
||||
* for allocations improving cache locality.
|
||||
* We add the arena before the the head, so that after the GC the most
|
||||
* recently added arena will be used first for allocations. This improves
|
||||
* cache locality.
|
||||
*/
|
||||
JS_ASSERT(!*al->cursor);
|
||||
JS_ASSERT(al->isCursorAtEnd());
|
||||
ArenaHeader *aheader = chunk->allocateArena(zone, thingKind);
|
||||
if (!aheader)
|
||||
return nullptr;
|
||||
@ -1568,12 +1554,7 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind)
|
||||
PushArenaAllocatedDuringSweep(zone->runtimeFromMainThread(), aheader);
|
||||
}
|
||||
}
|
||||
aheader->next = al->head;
|
||||
if (!al->head) {
|
||||
JS_ASSERT(al->cursor == &al->head);
|
||||
al->cursor = &aheader->next;
|
||||
}
|
||||
al->head = aheader;
|
||||
al->insertAtStart(aheader);
|
||||
|
||||
/* See comments before allocateFromNewArena about this assert. */
|
||||
JS_ASSERT(!aheader->hasFreeThings());
|
||||
@ -1604,7 +1585,7 @@ ArenaLists::wipeDuringParallelExecution(JSRuntime *rt)
|
||||
// that'd be bad.
|
||||
for (unsigned i = 0; i < FINALIZE_LAST; i++) {
|
||||
AllocKind thingKind = AllocKind(i);
|
||||
if (!IsBackgroundFinalized(thingKind) && arenaLists[thingKind].head)
|
||||
if (!IsBackgroundFinalized(thingKind) && !arenaLists[thingKind].isEmpty())
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1617,7 +1598,7 @@ ArenaLists::wipeDuringParallelExecution(JSRuntime *rt)
|
||||
if (!IsBackgroundFinalized(thingKind))
|
||||
continue;
|
||||
|
||||
if (arenaLists[i].head) {
|
||||
if (!arenaLists[i].isEmpty()) {
|
||||
purge(thingKind);
|
||||
forceFinalizeNow(&fop, thingKind);
|
||||
}
|
||||
@ -1636,7 +1617,7 @@ ArenaLists::forceFinalizeNow(FreeOp *fop, AllocKind thingKind)
|
||||
{
|
||||
JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE);
|
||||
|
||||
ArenaHeader *arenas = arenaLists[thingKind].head;
|
||||
ArenaHeader *arenas = arenaLists[thingKind].head();
|
||||
arenaLists[thingKind].clear();
|
||||
|
||||
SliceBudget budget;
|
||||
@ -1651,7 +1632,7 @@ ArenaLists::queueForForegroundSweep(FreeOp *fop, AllocKind thingKind)
|
||||
JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE);
|
||||
JS_ASSERT(!arenaListsToSweep[thingKind]);
|
||||
|
||||
arenaListsToSweep[thingKind] = arenaLists[thingKind].head;
|
||||
arenaListsToSweep[thingKind] = arenaLists[thingKind].head();
|
||||
arenaLists[thingKind].clear();
|
||||
}
|
||||
|
||||
@ -1665,9 +1646,8 @@ ArenaLists::queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind)
|
||||
#endif
|
||||
|
||||
ArenaList *al = &arenaLists[thingKind];
|
||||
if (!al->head) {
|
||||
if (al->isEmpty()) {
|
||||
JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE);
|
||||
JS_ASSERT(al->cursor == &al->head);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1678,7 +1658,7 @@ ArenaLists::queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind)
|
||||
JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE ||
|
||||
backgroundFinalizeState[thingKind] == BFS_JUST_FINISHED);
|
||||
|
||||
arenaListsToSweep[thingKind] = al->head;
|
||||
arenaListsToSweep[thingKind] = al->head();
|
||||
al->clear();
|
||||
backgroundFinalizeState[thingKind] = BFS_RUN;
|
||||
}
|
||||
@ -1695,23 +1675,18 @@ ArenaLists::backgroundFinalize(FreeOp *fop, ArenaHeader *listHead, bool onBackgr
|
||||
FinalizeArenas(fop, &listHead, finalized, thingKind, budget);
|
||||
JS_ASSERT(!listHead);
|
||||
|
||||
/*
|
||||
* After we finish the finalization al->cursor must point to the end of
|
||||
* the head list as we emptied the list before the background finalization
|
||||
* and the allocation adds new arenas before the cursor.
|
||||
*/
|
||||
// When arenas are queued for background finalization, all
|
||||
// arenas are moved to arenaListsToSweep[], leaving the arenaLists[] empty.
|
||||
// Then, if new arenas are allocated before background finalization
|
||||
// finishes they are always added to the front of the list. Therefore,
|
||||
// at this point, |al|'s cursor will always be at the end of its list.
|
||||
ArenaLists *lists = &zone->allocator.arenas;
|
||||
ArenaList *al = &lists->arenaLists[thingKind];
|
||||
|
||||
AutoLockGC lock(fop->runtime());
|
||||
JS_ASSERT(lists->backgroundFinalizeState[thingKind] == BFS_RUN);
|
||||
JS_ASSERT(!*al->cursor);
|
||||
|
||||
if (finalized.head) {
|
||||
*al->cursor = finalized.head;
|
||||
if (finalized.cursor != &finalized.head)
|
||||
al->cursor = finalized.cursor;
|
||||
}
|
||||
al->appendToListWithCursorAtEnd(finalized);
|
||||
|
||||
/*
|
||||
* We must set the state to BFS_JUST_FINISHED if we are running on the
|
||||
@ -1722,7 +1697,7 @@ ArenaLists::backgroundFinalize(FreeOp *fop, ArenaHeader *listHead, bool onBackgr
|
||||
* allocating new arenas from the chunks we can set the state to BFS_DONE if
|
||||
* we have released all finalized arenas back to their chunks.
|
||||
*/
|
||||
if (onBackgroundThread && finalized.head)
|
||||
if (onBackgroundThread && !finalized.isEmpty())
|
||||
lists->backgroundFinalizeState[thingKind] = BFS_JUST_FINISHED;
|
||||
else
|
||||
lists->backgroundFinalizeState[thingKind] = BFS_DONE;
|
||||
@ -5335,11 +5310,12 @@ ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
|
||||
#endif
|
||||
ArenaList *fromList = &fromArenaLists->arenaLists[thingKind];
|
||||
ArenaList *toList = &arenaLists[thingKind];
|
||||
while (fromList->head != nullptr) {
|
||||
// Remove entry from |fromList|
|
||||
ArenaHeader *fromHeader = fromList->head;
|
||||
fromList->head = fromHeader->next;
|
||||
fromHeader->next = nullptr;
|
||||
fromList->deepCheck();
|
||||
toList->deepCheck();
|
||||
ArenaHeader *next;
|
||||
for (ArenaHeader *fromHeader = fromList->head(); fromHeader; fromHeader = next) {
|
||||
// Copy fromHeader->next before releasing/reinserting.
|
||||
next = fromHeader->next;
|
||||
|
||||
// During parallel execution, we sometimes keep empty arenas
|
||||
// on the lists rather than sending them back to the chunk.
|
||||
@ -5348,9 +5324,10 @@ ArenaLists::adoptArenas(JSRuntime *rt, ArenaLists *fromArenaLists)
|
||||
if (fromHeader->isEmpty())
|
||||
fromHeader->chunk()->releaseArena(fromHeader);
|
||||
else
|
||||
toList->insert(fromHeader);
|
||||
toList->insertAtCursor(fromHeader);
|
||||
}
|
||||
fromList->cursor = &fromList->head;
|
||||
fromList->clear();
|
||||
toList->deepCheck();
|
||||
}
|
||||
}
|
||||
|
||||
@ -5359,10 +5336,7 @@ ArenaLists::containsArena(JSRuntime *rt, ArenaHeader *needle)
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
size_t allocKind = needle->getAllocKind();
|
||||
for (ArenaHeader *aheader = arenaLists[allocKind].head;
|
||||
aheader != nullptr;
|
||||
aheader = aheader->next)
|
||||
{
|
||||
for (ArenaHeader *aheader = arenaLists[allocKind].head(); aheader; aheader = aheader->next) {
|
||||
if (aheader == needle)
|
||||
return true;
|
||||
}
|
||||
|
188
js/src/jsgc.h
188
js/src/jsgc.h
@ -365,30 +365,165 @@ GetGCKindSlots(AllocKind thingKind, const Class *clasp)
|
||||
}
|
||||
|
||||
/*
|
||||
* ArenaList::head points to the start of the list. Normally cursor points
|
||||
* to the first arena in the list with some free things and all arenas
|
||||
* before cursor are fully allocated. However, as the arena currently being
|
||||
* allocated from is considered full while its list of free spans is moved
|
||||
* into the freeList, during the GC or cell enumeration, when an
|
||||
* unallocated freeList is moved back to the arena, we can see an arena
|
||||
* with some free cells before the cursor. The cursor is an indirect
|
||||
* pointer to allow for efficient list insertion at the cursor point and
|
||||
* other list manipulations.
|
||||
* Arena lists have a head and a cursor. The cursor conceptually lies on arena
|
||||
* boundaries, i.e. before the first arena, between two arenas, or after the
|
||||
* last arena.
|
||||
*
|
||||
* Normally the arena following the cursor is the first arena in the list with
|
||||
* some free things and all arenas before the cursor are fully allocated. (And
|
||||
* if the cursor is at the end of the list, then all the arenas are full.)
|
||||
*
|
||||
* However, the arena currently being allocated from is considered full while
|
||||
* its list of free spans is moved into the freeList. Therefore, during GC or
|
||||
* cell enumeration, when an unallocated freeList is moved back to the arena,
|
||||
* we can see an arena with some free cells before the cursor.
|
||||
*
|
||||
* Arenas following the cursor should not be full.
|
||||
*/
|
||||
struct ArenaList {
|
||||
ArenaHeader *head;
|
||||
ArenaHeader **cursor;
|
||||
class ArenaList {
|
||||
// The cursor is implemented via an indirect pointer, |cursorp_|, to allow
|
||||
// for efficient list insertion at the cursor point and other list
|
||||
// manipulations.
|
||||
//
|
||||
// - If the list is empty: |head| is null, |cursorp_| points to |head|, and
|
||||
// therefore |*cursorp_| is null.
|
||||
//
|
||||
// - If the list is not empty: |head| is non-null, and...
|
||||
//
|
||||
// - If the cursor is at the start of the list: |cursorp_| points to
|
||||
// |head|, and therefore |*cursorp_| points to the first arena.
|
||||
//
|
||||
// - If cursor is at the end of the list: |cursorp_| points to the |next|
|
||||
// field of the last arena, and therefore |*cursorp_| is null.
|
||||
//
|
||||
// - If the cursor is at neither the start nor the end of the list:
|
||||
// |cursorp_| points to the |next| field of the arena preceding the
|
||||
// cursor, and therefore |*cursorp_| points to the arena following the
|
||||
// cursor.
|
||||
//
|
||||
// |cursorp_| is never null.
|
||||
//
|
||||
ArenaHeader *head_;
|
||||
ArenaHeader **cursorp_;
|
||||
|
||||
public:
|
||||
ArenaList() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear() {
|
||||
head = nullptr;
|
||||
cursor = &head;
|
||||
// This does checking just of |head_| and |cursorp_|.
|
||||
void check() const {
|
||||
#ifdef DEBUG
|
||||
// If the list is empty, it must have this form.
|
||||
JS_ASSERT_IF(!head_, cursorp_ == &head_);
|
||||
|
||||
// If there's an arena following the cursor, it must not be full.
|
||||
ArenaHeader *cursor = *cursorp_;
|
||||
JS_ASSERT_IF(cursor, cursor->hasFreeThings());
|
||||
#endif
|
||||
}
|
||||
|
||||
void insert(ArenaHeader *arena);
|
||||
// This does checking involving all the arenas in the list.
|
||||
void deepCheck() const {
|
||||
#ifdef DEBUG
|
||||
check();
|
||||
// All full arenas must precede all non-full arenas.
|
||||
//
|
||||
// XXX: this is currently commented out because it fails moderately
|
||||
// often. I'm not sure if this is because (a) it's not true that all
|
||||
// full arenas must precede all non-full arenas, or (b) we have some
|
||||
// defective list-handling code.
|
||||
//
|
||||
// bool havePassedFullArenas = false;
|
||||
// for (ArenaHeader *aheader = head_; aheader; aheader = aheader->next) {
|
||||
// if (havePassedFullArenas) {
|
||||
// JS_ASSERT(aheader->hasFreeThings());
|
||||
// } else if (aheader->hasFreeThings()) {
|
||||
// havePassedFullArenas = true;
|
||||
// }
|
||||
// }
|
||||
#endif
|
||||
}
|
||||
|
||||
void clear() {
|
||||
head_ = nullptr;
|
||||
cursorp_ = &head_;
|
||||
check();
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
check();
|
||||
return !head_;
|
||||
}
|
||||
|
||||
// This returns nullptr if the list is empty.
|
||||
ArenaHeader *head() const {
|
||||
check();
|
||||
return head_;
|
||||
}
|
||||
|
||||
bool isCursorAtEnd() const {
|
||||
check();
|
||||
return !*cursorp_;
|
||||
}
|
||||
|
||||
// This can return nullptr.
|
||||
ArenaHeader *arenaAfterCursor() const {
|
||||
check();
|
||||
return *cursorp_;
|
||||
}
|
||||
|
||||
// This moves the cursor past |aheader|. |aheader| must be an arena within
|
||||
// this list.
|
||||
void moveCursorPast(ArenaHeader *aheader) {
|
||||
cursorp_ = &aheader->next;
|
||||
check();
|
||||
}
|
||||
|
||||
// This does two things.
|
||||
// - Inserts |a| at the cursor.
|
||||
// - Leaves the cursor sitting just before |a|, if |a| is not full, or just
|
||||
// after |a|, if |a| is full.
|
||||
//
|
||||
void insertAtCursor(ArenaHeader *a) {
|
||||
check();
|
||||
a->next = *cursorp_;
|
||||
*cursorp_ = a;
|
||||
// At this point, the cursor is sitting before |a|. Move it after |a|
|
||||
// if necessary.
|
||||
if (!a->hasFreeThings())
|
||||
cursorp_ = &a->next;
|
||||
check();
|
||||
}
|
||||
|
||||
// This inserts |a| at the start of the list, and doesn't change the
|
||||
// cursor.
|
||||
void insertAtStart(ArenaHeader *a) {
|
||||
check();
|
||||
a->next = head_;
|
||||
if (isEmpty())
|
||||
cursorp_ = &a->next; // The cursor remains null.
|
||||
head_ = a;
|
||||
check();
|
||||
}
|
||||
|
||||
// Appends |list|. |this|'s cursor must be at the end.
|
||||
void appendToListWithCursorAtEnd(ArenaList &other) {
|
||||
JS_ASSERT(isCursorAtEnd());
|
||||
deepCheck();
|
||||
other.deepCheck();
|
||||
if (!other.isEmpty()) {
|
||||
// Because |this|'s cursor is at the end, |cursorp_| points to the
|
||||
// list-ending null. So this assignment appends |other| to |this|.
|
||||
*cursorp_ = other.head_;
|
||||
|
||||
// If |other|'s cursor isn't at the start of the list, then update
|
||||
// |this|'s cursor accordingly.
|
||||
if (other.cursorp_ != &other.head_)
|
||||
cursorp_ = other.cursorp_;
|
||||
}
|
||||
deepCheck();
|
||||
}
|
||||
};
|
||||
|
||||
class ArenaLists
|
||||
@ -408,7 +543,7 @@ class ArenaLists
|
||||
|
||||
/*
|
||||
* The background finalization adds the finalized arenas to the list at
|
||||
* the *cursor position. backgroundFinalizeState controls the interaction
|
||||
* the cursor position. backgroundFinalizeState controls the interaction
|
||||
* between the GC lock and the access to the list from the allocation
|
||||
* thread.
|
||||
*
|
||||
@ -420,7 +555,7 @@ class ArenaLists
|
||||
* lock. The former indicates that the finalization still runs. The latter
|
||||
* signals that finalization just added to the list finalized arenas. In
|
||||
* that case the lock effectively serves as a read barrier to ensure that
|
||||
* the allocation thread see all the writes done during finalization.
|
||||
* the allocation thread sees all the writes done during finalization.
|
||||
*/
|
||||
enum BackgroundFinalizeState {
|
||||
BFS_DONE,
|
||||
@ -455,9 +590,10 @@ class ArenaLists
|
||||
* the background finalization is disabled.
|
||||
*/
|
||||
JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE);
|
||||
ArenaHeader **headp = &arenaLists[i].head;
|
||||
while (ArenaHeader *aheader = *headp) {
|
||||
*headp = aheader->next;
|
||||
ArenaHeader *next;
|
||||
for (ArenaHeader *aheader = arenaLists[i].head(); aheader; aheader = next) {
|
||||
// Copy aheader->next before releasing.
|
||||
next = aheader->next;
|
||||
aheader->chunk()->releaseArena(aheader);
|
||||
}
|
||||
}
|
||||
@ -473,7 +609,7 @@ class ArenaLists
|
||||
}
|
||||
|
||||
ArenaHeader *getFirstArena(AllocKind thingKind) const {
|
||||
return arenaLists[thingKind].head;
|
||||
return arenaLists[thingKind].head();
|
||||
}
|
||||
|
||||
ArenaHeader *getFirstArenaToSweep(AllocKind thingKind) const {
|
||||
@ -488,22 +624,18 @@ class ArenaLists
|
||||
*/
|
||||
if (backgroundFinalizeState[i] != BFS_DONE)
|
||||
return false;
|
||||
if (arenaLists[i].head)
|
||||
if (!arenaLists[i].isEmpty())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool arenasAreFull(AllocKind thingKind) const {
|
||||
return !*arenaLists[thingKind].cursor;
|
||||
}
|
||||
|
||||
void unmarkAll() {
|
||||
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
|
||||
/* The background finalization must have stopped at this point. */
|
||||
JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE ||
|
||||
backgroundFinalizeState[i] == BFS_JUST_FINISHED);
|
||||
for (ArenaHeader *aheader = arenaLists[i].head; aheader; aheader = aheader->next) {
|
||||
for (ArenaHeader *aheader = arenaLists[i].head(); aheader; aheader = aheader->next) {
|
||||
uintptr_t *word = aheader->chunk()->bitmap.arenaBits(aheader);
|
||||
memset(word, 0, ArenaBitmapWords * sizeof(uintptr_t));
|
||||
}
|
||||
|
@ -1802,26 +1802,28 @@ ScriptedDirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject prox
|
||||
cx->names().getOwnPropertyNames);
|
||||
}
|
||||
|
||||
// Proxy.[[Delete]](P, Throw)
|
||||
// ES6 (5 April 2014) Proxy.[[Delete]](P)
|
||||
bool
|
||||
ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
|
||||
{
|
||||
// step 1
|
||||
// step 2
|
||||
RootedObject handler(cx, GetDirectProxyHandlerObject(proxy));
|
||||
|
||||
// step 2
|
||||
// TODO: step 3: Implement revocation semantics
|
||||
|
||||
// step 4
|
||||
RootedObject target(cx, proxy->as<ProxyObject>().target());
|
||||
|
||||
// step 3
|
||||
// step 5
|
||||
RootedValue trap(cx);
|
||||
if (!JSObject::getProperty(cx, handler, handler, cx->names().deleteProperty, &trap))
|
||||
return false;
|
||||
|
||||
// step 4
|
||||
// step 7
|
||||
if (trap.isUndefined())
|
||||
return DirectProxyHandler::delete_(cx, proxy, id, bp);
|
||||
|
||||
// step 5
|
||||
// step 8
|
||||
RootedValue value(cx);
|
||||
if (!IdToExposableValue(cx, id, &value))
|
||||
return false;
|
||||
@ -1833,24 +1835,26 @@ ScriptedDirectProxyHandler::delete_(JSContext *cx, HandleObject proxy, HandleId
|
||||
if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
|
||||
return false;
|
||||
|
||||
// step 6-7
|
||||
// step 9
|
||||
if (ToBoolean(trapResult)) {
|
||||
// step 12
|
||||
Rooted<PropertyDescriptor> desc(cx);
|
||||
if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
|
||||
return false;
|
||||
|
||||
// step 14-15
|
||||
if (desc.object() && desc.isPermanent()) {
|
||||
RootedValue v(cx, IdToValue(id));
|
||||
js_ReportValueError(cx, JSMSG_CANT_DELETE, JSDVG_IGNORE_STACK, v, js::NullPtr());
|
||||
return false;
|
||||
}
|
||||
|
||||
// step 16
|
||||
*bp = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// step 8
|
||||
// FIXME: API does not include a Throw parameter
|
||||
// step 11
|
||||
*bp = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ class TypedObjectModuleObject;
|
||||
class GlobalObject : public JSObject
|
||||
{
|
||||
/* Count of slots set aside for application use. */
|
||||
static const unsigned APPLICATION_SLOTS = 3;
|
||||
static const unsigned APPLICATION_SLOTS = JSCLASS_GLOBAL_APPLICATION_SLOTS;
|
||||
|
||||
/*
|
||||
* Count of slots to store built-in constructors, prototypes, and initial
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "gfxPrefs.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -3705,14 +3705,7 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
|
||||
*/
|
||||
static bool ShouldDrawRectsSeparately(gfxContext* aContext, DrawRegionClip aClip)
|
||||
{
|
||||
static bool sPaintRectsSeparately;
|
||||
static bool sPaintRectsSeparatelyPrefCached = false;
|
||||
if (!sPaintRectsSeparatelyPrefCached) {
|
||||
mozilla::Preferences::AddBoolVarCache(&sPaintRectsSeparately, "layout.paint_rects_separately", false);
|
||||
sPaintRectsSeparatelyPrefCached = true;
|
||||
}
|
||||
|
||||
if (!sPaintRectsSeparately ||
|
||||
if (!gfxPrefs::LayoutPaintRectsSeparately() ||
|
||||
aContext->IsCairo() ||
|
||||
aClip == DrawRegionClip::CLIP_NONE) {
|
||||
return false;
|
||||
|
@ -73,7 +73,6 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
nsRect& aBounds,
|
||||
float aAppUnitsPerPixel,
|
||||
InfallibleTArray<TransformFunction>& aFunctions)
|
||||
{
|
||||
if (aList->mValue.GetUnit() == eCSSUnit_None) {
|
||||
@ -158,7 +157,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
{
|
||||
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerPixel);
|
||||
aBounds.Width());
|
||||
aFunctions.AppendElement(Translation(x, 0, 0));
|
||||
break;
|
||||
}
|
||||
@ -166,7 +165,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
{
|
||||
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerPixel);
|
||||
aBounds.Height());
|
||||
aFunctions.AppendElement(Translation(0, y, 0));
|
||||
break;
|
||||
}
|
||||
@ -174,7 +173,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
{
|
||||
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||
0, aAppUnitsPerPixel);
|
||||
0);
|
||||
aFunctions.AppendElement(Translation(0, 0, z));
|
||||
break;
|
||||
}
|
||||
@ -182,13 +181,13 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
{
|
||||
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerPixel);
|
||||
aBounds.Width());
|
||||
// translate(x) is shorthand for translate(x, 0)
|
||||
double y = 0;
|
||||
if (array->Count() == 3) {
|
||||
y = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerPixel);
|
||||
aBounds.Height());
|
||||
}
|
||||
aFunctions.AppendElement(Translation(x, y, 0));
|
||||
break;
|
||||
@ -197,13 +196,13 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
{
|
||||
double x = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerPixel);
|
||||
aBounds.Width());
|
||||
double y = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerPixel);
|
||||
aBounds.Height());
|
||||
double z = nsStyleTransformMatrix::ProcessTranslatePart(
|
||||
array->Item(3), aContext, aPresContext, canStoreInRuleTree,
|
||||
0, aAppUnitsPerPixel);
|
||||
0);
|
||||
|
||||
aFunctions.AppendElement(Translation(x, y, z));
|
||||
break;
|
||||
@ -282,8 +281,7 @@ static void AddTransformFunctions(nsCSSValueList* aList,
|
||||
aContext,
|
||||
aPresContext,
|
||||
canStoreInRuleTree,
|
||||
aBounds,
|
||||
aAppUnitsPerPixel);
|
||||
aBounds);
|
||||
gfx::Matrix4x4 transform;
|
||||
gfx::ToMatrix4x4(matrix, transform);
|
||||
aFunctions.AppendElement(TransformMatrix(transform));
|
||||
@ -322,8 +320,6 @@ AddAnimationForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
|
||||
nsStyleContext* styleContext = aFrame->StyleContext();
|
||||
nsPresContext* presContext = aFrame->PresContext();
|
||||
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame);
|
||||
// all data passed directly to the compositor should be in css pixels
|
||||
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
|
||||
|
||||
mozilla::layers::Animation* animation =
|
||||
aPending ?
|
||||
@ -354,11 +350,11 @@ AddAnimationForProperty(nsIFrame* aFrame, nsCSSProperty aProperty,
|
||||
animSegment->endState() = InfallibleTArray<TransformFunction>();
|
||||
|
||||
nsCSSValueSharedList* list = segment->mFromValue.GetCSSValueSharedListValue();
|
||||
AddTransformFunctions(list->mHead, styleContext, presContext, bounds, scale,
|
||||
AddTransformFunctions(list->mHead, styleContext, presContext, bounds,
|
||||
animSegment->startState().get_ArrayOfTransformFunction());
|
||||
|
||||
list = segment->mToValue.GetCSSValueSharedListValue();
|
||||
AddTransformFunctions(list->mHead, styleContext, presContext, bounds, scale,
|
||||
AddTransformFunctions(list->mHead, styleContext, presContext, bounds,
|
||||
animSegment->endState().get_ArrayOfTransformFunction());
|
||||
} else if (aProperty == eCSSProperty_opacity) {
|
||||
animSegment->startState() = segment->mFromValue.GetFloatValue();
|
||||
|
@ -41,8 +41,7 @@ ProcessTranslatePart(const nsCSSValue& aValue,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nscoord aSize,
|
||||
float aAppUnitsPerMatrixUnit)
|
||||
nscoord aSize)
|
||||
{
|
||||
nscoord offset = 0;
|
||||
float percent = 0.0f;
|
||||
@ -60,8 +59,7 @@ ProcessTranslatePart(const nsCSSValue& aValue,
|
||||
// Raw numbers are treated as being pixels.
|
||||
//
|
||||
// Don't convert to aValue to AppUnits here to avoid precision issues.
|
||||
return aValue.GetFloatValue() *
|
||||
(float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit);
|
||||
return aValue.GetFloatValue();
|
||||
} else if (aValue.IsCalcUnit()) {
|
||||
nsRuleNode::ComputedCalc result =
|
||||
nsRuleNode::SpecifiedCalcToComputedCalc(aValue, aContext, aPresContext,
|
||||
@ -73,8 +71,8 @@ ProcessTranslatePart(const nsCSSValue& aValue,
|
||||
aCanStoreInRuleTree);
|
||||
}
|
||||
|
||||
return (percent * NSAppUnitsToFloatPixels(aSize, aAppUnitsPerMatrixUnit)) +
|
||||
NSAppUnitsToFloatPixels(offset, aAppUnitsPerMatrixUnit);
|
||||
return (percent * NSAppUnitsToFloatPixels(aSize, nsPresContext::AppUnitsPerCSSPixel())) +
|
||||
NSAppUnitsToFloatPixels(offset, nsPresContext::AppUnitsPerCSSPixel());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,7 +88,7 @@ ProcessMatrix(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 7, "Invalid array!");
|
||||
|
||||
@ -109,10 +107,10 @@ ProcessMatrix(gfx3DMatrix& aMatrix,
|
||||
*/
|
||||
result.x0 = ProcessTranslatePart(aData->Item(5),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Width());
|
||||
result.y0 = ProcessTranslatePart(aData->Item(6),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Height());
|
||||
|
||||
aMatrix.PreMultiply(result);
|
||||
}
|
||||
@ -123,7 +121,7 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 17, "Invalid array!");
|
||||
|
||||
@ -145,13 +143,13 @@ ProcessMatrix3D(gfx3DMatrix& aMatrix,
|
||||
|
||||
temp._41 = ProcessTranslatePart(aData->Item(13),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Width());
|
||||
temp._42 = ProcessTranslatePart(aData->Item(14),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Height());
|
||||
temp._43 = ProcessTranslatePart(aData->Item(15),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Height());
|
||||
|
||||
aMatrix.PreMultiply(temp);
|
||||
}
|
||||
@ -163,7 +161,7 @@ ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
|
||||
|
||||
@ -172,13 +170,13 @@ ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
||||
matrix1 = nsStyleTransformMatrix::ReadTransforms(aData->Item(1).GetListValue(),
|
||||
aContext, aPresContext,
|
||||
aCanStoreInRuleTree,
|
||||
aBounds, aAppUnitsPerMatrixUnit);
|
||||
aBounds, nsPresContext::AppUnitsPerCSSPixel());
|
||||
}
|
||||
if (aData->Item(2).GetUnit() == eCSSUnit_List) {
|
||||
matrix2 = ReadTransforms(aData->Item(2).GetListValue(),
|
||||
aContext, aPresContext,
|
||||
aCanStoreInRuleTree,
|
||||
aBounds, aAppUnitsPerMatrixUnit);
|
||||
aBounds, nsPresContext::AppUnitsPerCSSPixel());
|
||||
}
|
||||
double progress = aData->Item(3).GetPercentValue();
|
||||
|
||||
@ -192,7 +190,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
@ -200,7 +198,7 @@ ProcessTranslateX(gfx3DMatrix& aMatrix,
|
||||
|
||||
temp.x = ProcessTranslatePart(aData->Item(1),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Width());
|
||||
aMatrix.Translate(temp);
|
||||
}
|
||||
|
||||
@ -211,7 +209,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
@ -219,7 +217,7 @@ ProcessTranslateY(gfx3DMatrix& aMatrix,
|
||||
|
||||
temp.y = ProcessTranslatePart(aData->Item(1),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Height());
|
||||
aMatrix.Translate(temp);
|
||||
}
|
||||
|
||||
@ -227,17 +225,15 @@ static void
|
||||
ProcessTranslateZ(gfx3DMatrix& aMatrix,
|
||||
const nsCSSValue::Array* aData,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
float aAppUnitsPerMatrixUnit)
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
gfxPoint3D temp;
|
||||
|
||||
temp.z = ProcessTranslatePart(aData->Item(1),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
0, aAppUnitsPerMatrixUnit);
|
||||
temp.z = ProcessTranslatePart(aData->Item(1), aContext,
|
||||
aPresContext, aCanStoreInRuleTree, 0);
|
||||
aMatrix.Translate(temp);
|
||||
}
|
||||
|
||||
@ -248,7 +244,7 @@ ProcessTranslate(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
|
||||
|
||||
@ -256,13 +252,13 @@ ProcessTranslate(gfx3DMatrix& aMatrix,
|
||||
|
||||
temp.x = ProcessTranslatePart(aData->Item(1),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Width());
|
||||
|
||||
/* If we read in a Y component, set it appropriately */
|
||||
if (aData->Count() == 3) {
|
||||
temp.y = ProcessTranslatePart(aData->Item(2),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Height());
|
||||
}
|
||||
aMatrix.Translate(temp);
|
||||
}
|
||||
@ -273,7 +269,7 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 4, "Invalid array!");
|
||||
|
||||
@ -281,15 +277,15 @@ ProcessTranslate3D(gfx3DMatrix& aMatrix,
|
||||
|
||||
temp.x = ProcessTranslatePart(aData->Item(1),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Width(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Width());
|
||||
|
||||
temp.y = ProcessTranslatePart(aData->Item(2),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
aBounds.Height(), aAppUnitsPerMatrixUnit);
|
||||
aBounds.Height());
|
||||
|
||||
temp.z = ProcessTranslatePart(aData->Item(3),
|
||||
aContext, aPresContext, aCanStoreInRuleTree,
|
||||
0, aAppUnitsPerMatrixUnit);
|
||||
0);
|
||||
|
||||
aMatrix.Translate(temp);
|
||||
}
|
||||
@ -480,14 +476,13 @@ ProcessPerspective(gfx3DMatrix& aMatrix,
|
||||
const nsCSSValue::Array* aData,
|
||||
nsStyleContext *aContext,
|
||||
nsPresContext *aPresContext,
|
||||
bool &aCanStoreInRuleTree,
|
||||
float aAppUnitsPerMatrixUnit)
|
||||
bool &aCanStoreInRuleTree)
|
||||
{
|
||||
NS_PRECONDITION(aData->Count() == 2, "Invalid array!");
|
||||
|
||||
float depth = ProcessTranslatePart(aData->Item(1), aContext,
|
||||
aPresContext, aCanStoreInRuleTree,
|
||||
0, aAppUnitsPerMatrixUnit);
|
||||
0);
|
||||
aMatrix.Perspective(depth);
|
||||
}
|
||||
|
||||
@ -502,8 +497,7 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds,
|
||||
float aAppUnitsPerMatrixUnit)
|
||||
nsRect& aBounds)
|
||||
{
|
||||
NS_PRECONDITION(aData, "Why did you want to get data from a null array?");
|
||||
// It's OK if aContext and aPresContext are null if the caller already
|
||||
@ -515,23 +509,23 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||
switch (TransformFunctionOf(aData)) {
|
||||
case eCSSKeyword_translatex:
|
||||
ProcessTranslateX(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_translatey:
|
||||
ProcessTranslateY(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_translatez:
|
||||
ProcessTranslateZ(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree);
|
||||
break;
|
||||
case eCSSKeyword_translate:
|
||||
ProcessTranslate(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_translate3d:
|
||||
ProcessTranslate3D(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_scalex:
|
||||
ProcessScaleX(aMatrix, aData);
|
||||
@ -572,19 +566,19 @@ MatrixForTransformFunction(gfx3DMatrix& aMatrix,
|
||||
break;
|
||||
case eCSSKeyword_matrix:
|
||||
ProcessMatrix(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_matrix3d:
|
||||
ProcessMatrix3D(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_interpolatematrix:
|
||||
ProcessInterpolateMatrix(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aBounds, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree, aBounds);
|
||||
break;
|
||||
case eCSSKeyword_perspective:
|
||||
ProcessPerspective(aMatrix, aData, aContext, aPresContext,
|
||||
aCanStoreInRuleTree, aAppUnitsPerMatrixUnit);
|
||||
aCanStoreInRuleTree);
|
||||
break;
|
||||
default:
|
||||
NS_NOTREACHED("Unknown transform function!");
|
||||
@ -621,9 +615,12 @@ ReadTransforms(const nsCSSValueList* aList,
|
||||
|
||||
/* Read in a single transform matrix. */
|
||||
MatrixForTransformFunction(result, currElem.GetArrayValue(), aContext,
|
||||
aPresContext, aCanStoreInRuleTree,
|
||||
aBounds, aAppUnitsPerMatrixUnit);
|
||||
aPresContext, aCanStoreInRuleTree, aBounds);
|
||||
}
|
||||
|
||||
float scale = float(nsPresContext::AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
|
||||
result.Scale(1/scale, 1/scale, 1/scale);
|
||||
result.ScalePost(scale, scale, scale);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -32,8 +32,7 @@ namespace nsStyleTransformMatrix {
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nscoord aSize,
|
||||
float aAppUnitsPerMatrixUnit);
|
||||
nscoord aSize);
|
||||
|
||||
void
|
||||
ProcessInterpolateMatrix(gfx3DMatrix& aMatrix,
|
||||
@ -41,7 +40,7 @@ namespace nsStyleTransformMatrix {
|
||||
nsStyleContext* aContext,
|
||||
nsPresContext* aPresContext,
|
||||
bool& aCanStoreInRuleTree,
|
||||
nsRect& aBounds, float aAppUnitsPerMatrixUnit);
|
||||
nsRect& aBounds);
|
||||
|
||||
/**
|
||||
* Given an nsCSSValueList containing -moz-transform functions,
|
||||
|
@ -2369,18 +2369,16 @@ bool AudioDeviceLinuxALSA::RecThreadProcess()
|
||||
|
||||
|
||||
bool AudioDeviceLinuxALSA::KeyPressed() const{
|
||||
|
||||
#ifdef USE_X11
|
||||
char szKey[32];
|
||||
unsigned int i = 0;
|
||||
char state = 0;
|
||||
|
||||
#ifdef USE_X11
|
||||
if (!_XDisplay)
|
||||
return false;
|
||||
|
||||
// Check key map status
|
||||
XQueryKeymap(_XDisplay, szKey);
|
||||
#endif
|
||||
|
||||
// A bit change in keymap means a key is pressed
|
||||
for (i = 0; i < sizeof(szKey); i++)
|
||||
@ -2389,5 +2387,8 @@ bool AudioDeviceLinuxALSA::KeyPressed() const{
|
||||
// Save old state
|
||||
memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
|
||||
return (state != 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
@ -3114,18 +3114,16 @@ bool AudioDeviceLinuxPulse::RecThreadProcess()
|
||||
}
|
||||
|
||||
bool AudioDeviceLinuxPulse::KeyPressed() const{
|
||||
|
||||
#ifdef USE_X11
|
||||
char szKey[32];
|
||||
unsigned int i = 0;
|
||||
char state = 0;
|
||||
|
||||
#ifdef USE_X11
|
||||
if (!_XDisplay)
|
||||
return false;
|
||||
|
||||
// Check key map status
|
||||
XQueryKeymap(_XDisplay, szKey);
|
||||
#endif
|
||||
|
||||
// A bit change in keymap means a key is pressed
|
||||
for (i = 0; i < sizeof(szKey); i++)
|
||||
@ -3134,5 +3132,8 @@ bool AudioDeviceLinuxPulse::KeyPressed() const{
|
||||
// Save old state
|
||||
memcpy((char*)_oldKeyState, (char*)szKey, sizeof(_oldKeyState));
|
||||
return (state != 0);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,4 @@ ac_add_options --with-branding=mobile/android/branding/nightly
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
||||
# Use ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"
|
||||
|
@ -15,7 +15,4 @@ ac_add_options --with-branding=mobile/android/branding/nightly
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
||||
# Use ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"
|
||||
|
@ -14,7 +14,4 @@ ac_add_options --with-branding=mobile/android/branding/nightly
|
||||
# Treat warnings as errors in directories with FAIL_ON_WARNINGS.
|
||||
ac_add_options --enable-warnings-as-errors
|
||||
|
||||
# Use ccache
|
||||
. "$topsrcdir/build/mozconfig.cache"
|
||||
|
||||
. "$topsrcdir/mobile/android/config/mozconfigs/common.override"
|
||||
|
@ -147,6 +147,9 @@ static DllBlockInfo sWindowsDllBlocklist[] = {
|
||||
// Topcrash with V-bates, bug 1002748
|
||||
{ "libinject.dll", UNVERSIONED },
|
||||
|
||||
// Crashes with RoboForm2Go written against old SDK, bug 988311
|
||||
{ "rf-firefox-22.dll", ALL_VERSIONS },
|
||||
|
||||
{ nullptr, 0 }
|
||||
};
|
||||
|
||||
|
@ -90,8 +90,12 @@ TEST_F(pkixder_input_tests, InputInitWithNullPointerOrZeroLength)
|
||||
ASSERT_EQ(Failure, input.Init(nullptr, 100));
|
||||
ASSERT_EQ(SEC_ERROR_BAD_DER, PR_GetError());
|
||||
|
||||
// Is this a bug?
|
||||
// Though it seems odd to initialize with zero-length and non-null ptr, this
|
||||
// is working as intended. The Input class was intended to protect against
|
||||
// buffer overflows, and there's no risk with the current behavior. See bug
|
||||
// 1000354.
|
||||
ASSERT_EQ(Success, input.Init((const uint8_t*) "hello", 0));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitWithLargeData)
|
||||
|
@ -5026,23 +5026,12 @@ static int32_t RoundUp(double aDouble)
|
||||
NPCocoaEventScrollWheel,
|
||||
&cocoaEvent);
|
||||
|
||||
#ifdef __LP64__
|
||||
// Only dispatch this event if we're not currently tracking a scroll event as
|
||||
// swipe.
|
||||
if (!mCancelSwipeAnimation || *mCancelSwipeAnimation == YES) {
|
||||
#endif // #ifdef __LP64__
|
||||
mGeckoChild->DispatchWindowEvent(wheelEvent);
|
||||
if (!mGeckoChild) {
|
||||
return;
|
||||
}
|
||||
#ifdef __LP64__
|
||||
} else {
|
||||
// Manually set these members here since we didn't dispatch the event.
|
||||
wheelEvent.overflowDeltaX = wheelEvent.deltaX;
|
||||
wheelEvent.overflowDeltaY = wheelEvent.deltaY;
|
||||
wheelEvent.mViewPortIsOverscrolled = true;
|
||||
mGeckoChild->DispatchWindowEvent(wheelEvent);
|
||||
if (!mGeckoChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef __LP64__
|
||||
// overflowDeltaX and overflowDeltaY tell us when the user has tried to
|
||||
// scroll past the edge of a page (in those cases it's non-zero).
|
||||
if ((wheelEvent.deltaMode == nsIDOMWheelEvent::DOM_DELTA_PIXEL) &&
|
||||
|
@ -216,6 +216,8 @@ inline void PadDriverDecimal(char *aString)
|
||||
inline bool
|
||||
ParseDriverVersion(const nsAString& aVersion, uint64_t *aNumericVersion)
|
||||
{
|
||||
*aNumericVersion = 0;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
int a, b, c, d;
|
||||
char aStr[8], bStr[8], cStr[8], dStr[8];
|
||||
@ -238,12 +240,15 @@ ParseDriverVersion(const nsAString& aVersion, uint64_t *aNumericVersion)
|
||||
if (d < 0 || d > 0xffff) return false;
|
||||
|
||||
*aNumericVersion = GFX_DRIVER_VERSION(a, b, c, d);
|
||||
return true;
|
||||
#elif defined(ANDROID)
|
||||
// Can't use aVersion.ToInteger() because that's not compiled into our code
|
||||
// unless we have XPCOM_GLUE_AVOID_NSPR disabled.
|
||||
*aNumericVersion = atoi(NS_LossyConvertUTF16toASCII(aVersion).get());
|
||||
#endif
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -595,8 +595,10 @@ GfxInfoBase::FindBlocklistedDeviceInList(const nsTArray<GfxDriverInfo>& info,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN) || defined(ANDROID)
|
||||
uint64_t driverVersion;
|
||||
ParseDriverVersion(adapterDriverVersionString, &driverVersion);
|
||||
#endif
|
||||
|
||||
uint32_t i = 0;
|
||||
for (; i < info.Length(); i++) {
|
||||
@ -747,9 +749,6 @@ GfxInfoBase::GetFeatureStatusImpl(int32_t aFeature,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint64_t driverVersion;
|
||||
ParseDriverVersion(adapterDriverVersionString, &driverVersion);
|
||||
|
||||
// Check if the device is blocked from the downloaded blocklist. If not, check
|
||||
// the static list after that. This order is used so that we can later escape
|
||||
// out of static blocks (i.e. if we were wrong or something was patched, we
|
||||
|
@ -194,7 +194,8 @@ struct XPTInterfaceDirectoryEntry {
|
||||
extern XPT_PUBLIC_API(PRBool)
|
||||
XPT_FillInterfaceDirectoryEntry(XPTArena *arena,
|
||||
XPTInterfaceDirectoryEntry *ide,
|
||||
nsID *iid, char *name, char *name_space,
|
||||
nsID *iid, const char *name,
|
||||
const char *name_space,
|
||||
XPTInterfaceDescriptor *descriptor);
|
||||
|
||||
extern XPT_PUBLIC_API(void)
|
||||
@ -250,7 +251,7 @@ struct XPTInterfaceDescriptor {
|
||||
|
||||
extern XPT_PUBLIC_API(PRBool)
|
||||
XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block,
|
||||
uint16_t num_interfaces, char *name,
|
||||
uint16_t num_interfaces, const char *name,
|
||||
uint16_t *indexp);
|
||||
|
||||
extern XPT_PUBLIC_API(XPTInterfaceDescriptor *)
|
||||
@ -283,10 +284,10 @@ struct XPTString {
|
||||
};
|
||||
|
||||
extern XPT_PUBLIC_API(XPTString *)
|
||||
XPT_NewString(XPTArena *arena, uint16_t length, char *bytes);
|
||||
XPT_NewString(XPTArena *arena, uint16_t length, const char *bytes);
|
||||
|
||||
extern XPT_PUBLIC_API(XPTString *)
|
||||
XPT_NewStringZ(XPTArena *arena, char *bytes);
|
||||
XPT_NewStringZ(XPTArena *arena, const char *bytes);
|
||||
|
||||
/*
|
||||
* A TypeDescriptor is a variable-size record used to identify the type of a
|
||||
@ -477,9 +478,9 @@ struct XPTMethodDescriptor {
|
||||
#define XPT_MD_WANTS_CONTEXT(flags) (flags & XPT_MD_CONTEXT)
|
||||
|
||||
extern XPT_PUBLIC_API(PRBool)
|
||||
XPT_FillMethodDescriptor(XPTArena *arena,
|
||||
XPTMethodDescriptor *meth, uint8_t flags, char *name,
|
||||
uint8_t num_args);
|
||||
XPT_FillMethodDescriptor(XPTArena *arena,
|
||||
XPTMethodDescriptor *meth, uint8_t flags,
|
||||
const char *name, uint8_t num_args);
|
||||
|
||||
/*
|
||||
* Annotation records are variable-size records used to store secondary
|
||||
|
@ -283,7 +283,8 @@ XPT_DoHeader(XPTArena *arena, XPTCursor *cursor, XPTHeader **headerp)
|
||||
XPT_PUBLIC_API(PRBool)
|
||||
XPT_FillInterfaceDirectoryEntry(XPTArena *arena,
|
||||
XPTInterfaceDirectoryEntry *ide,
|
||||
nsID *iid, char *name, char *name_space,
|
||||
nsID *iid, const char *name,
|
||||
const char *name_space,
|
||||
XPTInterfaceDescriptor *descriptor)
|
||||
{
|
||||
XPT_COPY_IID(ide->iid, *iid);
|
||||
@ -694,8 +695,8 @@ DoConstDescriptor(XPTArena *arena, XPTCursor *cursor, XPTConstDescriptor *cd,
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(PRBool)
|
||||
XPT_FillMethodDescriptor(XPTArena *arena, XPTMethodDescriptor *meth,
|
||||
uint8_t flags, char *name, uint8_t num_args)
|
||||
XPT_FillMethodDescriptor(XPTArena *arena, XPTMethodDescriptor *meth,
|
||||
uint8_t flags, const char *name, uint8_t num_args)
|
||||
{
|
||||
meth->flags = flags & XPT_MD_FLAGMASK;
|
||||
meth->name = XPT_STRDUP(arena, name);
|
||||
@ -874,11 +875,11 @@ DoAnnotation(XPTArena *arena, XPTCursor *cursor, XPTAnnotation **annp)
|
||||
|
||||
PRBool
|
||||
XPT_GetInterfaceIndexByName(XPTInterfaceDirectoryEntry *ide_block,
|
||||
uint16_t num_interfaces, char *name,
|
||||
uint16_t *indexp)
|
||||
uint16_t num_interfaces, const char *name,
|
||||
uint16_t *indexp)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for (i=1; i<=num_interfaces; i++) {
|
||||
fprintf(stderr, "%s == %s ?\n", ide_block[i].name, name);
|
||||
if (strcmp(ide_block[i].name, name) == 0) {
|
||||
|
@ -305,7 +305,7 @@ XPT_SeekTo(XPTCursor *cursor, uint32_t offset)
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(XPTString *)
|
||||
XPT_NewString(XPTArena *arena, uint16_t length, char *bytes)
|
||||
XPT_NewString(XPTArena *arena, uint16_t length, const char *bytes)
|
||||
{
|
||||
XPTString *str = XPT_NEW(arena, XPTString);
|
||||
if (!str)
|
||||
@ -324,7 +324,7 @@ XPT_NewString(XPTArena *arena, uint16_t length, char *bytes)
|
||||
}
|
||||
|
||||
XPT_PUBLIC_API(XPTString *)
|
||||
XPT_NewStringZ(XPTArena *arena, char *bytes)
|
||||
XPT_NewStringZ(XPTArena *arena, const char *bytes)
|
||||
{
|
||||
uint32_t length = strlen(bytes);
|
||||
if (length > 0xffff)
|
||||
|
@ -26,15 +26,17 @@
|
||||
#define TRY(msg, cond) TRY_(msg, cond, 0)
|
||||
#define TRY_Q(msg, cond) TRY_(msg, cond, 1);
|
||||
|
||||
XPTString in_str = { 4, "bazz" };
|
||||
static char bazz[] = "bazz";
|
||||
XPTString in_str = { 4, bazz };
|
||||
|
||||
static char foobar[] = "foobar";
|
||||
struct TestData {
|
||||
uint32_t bit32;
|
||||
uint16_t bit16;
|
||||
uint8_t bit8[2];
|
||||
char *cstr;
|
||||
XPTString *str;
|
||||
} input = { 0xdeadbeef, 0xcafe, {0xba, 0xbe}, "foobar", &in_str},
|
||||
} input = { 0xdeadbeef, 0xcafe, {0xba, 0xbe}, foobar, &in_str},
|
||||
output = {0, 0, {0, 0}, NULL, NULL };
|
||||
|
||||
void
|
||||
|
Loading…
Reference in New Issue
Block a user