Merge mozilla-central and inbound

This commit is contained in:
Ed Morley 2014-01-10 15:25:50 +00:00
commit eb55035528
156 changed files with 4795 additions and 2907 deletions

View File

@ -16,10 +16,13 @@ function triggerSave(aWindow, aCallback) {
var fileName;
let testBrowser = aWindow.gBrowser.selectedBrowser;
// This page sets a cookie if and only if a cookie does not exist yet
testBrowser.loadURI("http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html");
let testURI = "http://mochi.test:8888/browser/browser/base/content/test/general/bug792517-2.html";
testBrowser.loadURI(testURI);
testBrowser.addEventListener("pageshow", function pageShown(event) {
if (event.target.location == "about:blank")
if (event.target.location != testURI) {
testBrowser.loadURI(testURI);
return;
}
testBrowser.removeEventListener("pageshow", pageShown, false);
executeSoon(function () {

View File

@ -848,7 +848,7 @@ class Automation(object):
xrePath = None, certPath = None,
debuggerInfo = None, symbolsPath = None,
timeout = -1, maxTime = None, onLaunch = None,
webapprtChrome = False):
webapprtChrome = False, hide_subtests=None):
"""
Run the app, log the duration it took to execute, return the status code.
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.

View File

@ -124,9 +124,6 @@ libs:: $(CPP_UNIT_TEST_BINS) $(call mkdir_deps,$(DIST)/cppunittests)
$(NSINSTALL) $(CPP_UNIT_TEST_BINS) $(DIST)/cppunittests
endif
check::
@$(PYTHON) $(topsrcdir)/testing/runcppunittests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS))
cppunittests-remote: DM_TRANS?=adb
cppunittests-remote:
@if [ '${TEST_DEVICE}' != '' -o '$(DM_TRANS)' = 'adb' ]; then \

View File

@ -8818,6 +8818,10 @@ void
nsDocument::ScrollToRef()
{
if (mScrolledToRefAlready) {
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
shell->ScrollToAnchor();
}
return;
}

View File

@ -1899,7 +1899,11 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
mProgressTimerIsActive = false;
mProgressNotifier->Cancel();
}
MaybeDispatchProgressEvents(true);
if (mUploadTransferred < mUploadTotal) {
mUploadTransferred = mUploadTotal;
mProgressSinceLastProgressEvent = true;
MaybeDispatchProgressEvents(true);
}
mUploadComplete = true;
DispatchProgressEvent(mUpload, NS_LITERAL_STRING(LOAD_STR),
true, mUploadTotal, mUploadTotal);
@ -3410,9 +3414,6 @@ nsXMLHttpRequest::MaybeDispatchProgressEvents(bool aFinalProgress)
// We're uploading if our state is XML_HTTP_REQUEST_OPENED or
// XML_HTTP_REQUEST_SENT
if ((XML_HTTP_REQUEST_OPENED | XML_HTTP_REQUEST_SENT) & mState) {
if (aFinalProgress) {
mUploadTotal = mUploadTransferred;
}
if (mUpload && !mUploadComplete) {
DispatchProgressEvent(mUpload, NS_LITERAL_STRING(PROGRESS_STR),
mUploadLengthComputable, mUploadTransferred,

View File

@ -23,6 +23,7 @@ var xhr = null;
var upload = null;
var currentEvents = null;
var expectedResponseText = null;
var uploadTotal = 0;
function logEvent(evt) {
var i = 0;
@ -32,6 +33,13 @@ function logEvent(evt) {
!(evt.target instanceof currentEvents[i].target))) {
++i;
}
if (evt.target instanceof XMLHttpRequestUpload) {
if (evt.type == "loadstart") {
uploadTotal = evt.total
} else {
is(evt.total, uploadTotal, "event(" + evt.type + ").total should not change during upload.");
}
}
ok(i != currentEvents.length, "Extra or wrong event?");
is(evt.type, currentEvents[i].type, "Wrong event!")
ok(evt.target instanceof currentEvents[i].target,

View File

@ -1790,23 +1790,6 @@ bool CanvasRenderingContext2D::DrawCustomFocusRing(mozilla::dom::Element& aEleme
nsCOMPtr<nsIDOMElement> focusedElement;
fm->GetFocusedElement(getter_AddRefs(focusedElement));
if (SameCOMIdentity(aElement.AsDOMNode(), focusedElement)) {
// get the bounds of the current path
mgfx::Rect bounds;
bounds = mPath->GetBounds(mTarget->GetTransform());
// and set them as the accessible area
nsRect rect(canvas->ClientLeft() + bounds.x, canvas->ClientTop() + bounds.y,
bounds.width, bounds.height);
rect.x *= AppUnitsPerCSSPixel();
rect.y *= AppUnitsPerCSSPixel();
rect.width *= AppUnitsPerCSSPixel();
rect.height *= AppUnitsPerCSSPixel();
nsIFrame* frame = aElement.GetPrimaryFrame();
if(frame) {
frame->SetRect(rect);
}
return true;
}
}

View File

@ -156,6 +156,11 @@ WebGLContext::WebGLContext()
mStencilWriteMaskFront = 0xffffffff;
mStencilWriteMaskBack = 0xffffffff;
mViewportX = 0;
mViewportY = 0;
mViewportWidth = 0;
mViewportHeight = 0;
mScissorTestEnabled = 0;
mDitherEnabled = 1;
mRasterizerDiscardEnabled = 0; // OpenGL ES 3.0 spec p244
@ -193,6 +198,7 @@ WebGLContext::WebGLContext()
mAlreadyGeneratedWarnings = 0;
mAlreadyWarnedAboutFakeVertexAttrib0 = false;
mAlreadyWarnedAboutViewportLargerThanDest = false;
mMaxWarnings = Preferences::GetInt("webgl.max-warnings-per-context", 32);
if (mMaxWarnings < -1)
{
@ -573,6 +579,8 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
mWidth = width;
mHeight = height;
mViewportWidth = width;
mViewportHeight = height;
mResetLayer = true;
mOptionsFrozen = true;

View File

@ -1136,6 +1136,12 @@ protected:
GLint mStencilClearValue;
GLfloat mDepthClearValue;
GLint mViewportX;
GLint mViewportY;
GLsizei mViewportWidth;
GLsizei mViewportHeight;
bool mAlreadyWarnedAboutViewportLargerThanDest;
nsCOMPtr<nsITimer> mContextRestorer;
bool mAllowRestore;
bool mContextLossTimerRunning;

View File

@ -53,7 +53,7 @@ using namespace mozilla::gfx;
static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2);
inline const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject()
: static_cast<const WebGLRectangleObject*>(this);
}
@ -3067,6 +3067,11 @@ WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
MakeContextCurrent();
gl->fViewport(x, y, width, height);
mViewportX = x;
mViewportY = y;
mViewportWidth = width;
mViewportHeight = height;
}
void

View File

@ -490,9 +490,11 @@ uint32_t WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
case LOCAL_GL_LUMINANCE_ALPHA:
return 2 * multiplier;
case LOCAL_GL_RGB:
case LOCAL_GL_RGB32F:
case LOCAL_GL_SRGB_EXT:
return 3 * multiplier;
case LOCAL_GL_RGBA:
case LOCAL_GL_RGBA32F:
case LOCAL_GL_SRGB_ALPHA_EXT:
return 4 * multiplier;
case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
@ -519,7 +521,7 @@ uint32_t WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
return 16;
}
MOZ_ASSERT(false);
MOZ_ASSERT(false, "Unhandled format+type combo.");
return 0;
}

View File

@ -733,6 +733,20 @@ void WebGLContext::Draw_cleanup()
}
}
}
// Let's check the viewport
const WebGLRectangleObject* rect = FramebufferRectangleObject();
if (rect) {
if (mViewportWidth > rect->Width() ||
mViewportHeight > rect->Height())
{
if (!mAlreadyWarnedAboutViewportLargerThanDest) {
GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
"(This warning will only be given once)");
mAlreadyWarnedAboutViewportLargerThanDest = true;
}
}
}
}
/*

View File

@ -3677,12 +3677,12 @@ void HTMLMediaElement::FireTimeUpdate(bool aPeriodic)
mDecoder->SetFragmentEndTime(mFragmentEnd);
}
// Update visible text tracks.
// Update the cues displaying on the video.
// Here mTextTrackManager can be null if the cycle collector has unlinked
// us before our parent. In that case UnbindFromTree will call us
// when our parent is unlinked.
if (mTextTrackManager) {
mTextTrackManager->Update(time);
mTextTrackManager->UpdateCueDisplay();
}
}

View File

@ -8,6 +8,14 @@
#include "mozilla/dom/TextTrackManager.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "mozilla/dom/HTMLTrackElement.h"
#include "mozilla/dom/TextTrack.h"
#include "mozilla/dom/TextTrackCue.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsComponentManagerUtils.h"
#include "nsVideoFrame.h"
#include "nsIFrame.h"
#include "nsTArrayHelpers.h"
#include "nsIWebVTTParserWrapper.h"
namespace mozilla {
namespace dom {
@ -17,6 +25,8 @@ NS_IMPL_CYCLE_COLLECTION_3(TextTrackManager, mTextTracks,
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(TextTrackManager, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(TextTrackManager, Release)
StaticRefPtr<nsIWebVTTParserWrapper> TextTrackManager::sParserWrapper;
TextTrackManager::TextTrackManager(HTMLMediaElement *aMediaElement)
: mMediaElement(aMediaElement)
{
@ -25,6 +35,13 @@ TextTrackManager::TextTrackManager(HTMLMediaElement *aMediaElement)
mTextTracks = new TextTrackList(mMediaElement->OwnerDoc()->GetParentObject());
mPendingTextTracks =
new TextTrackList(mMediaElement->OwnerDoc()->GetParentObject());
if (!sParserWrapper) {
nsCOMPtr<nsIWebVTTParserWrapper> parserWrapper =
do_CreateInstance(NS_WEBVTTPARSERWRAPPER_CONTRACTID);
sParserWrapper = parserWrapper;
ClearOnShutdown(&sParserWrapper);
}
}
TextTrackManager::~TextTrackManager()
@ -86,9 +103,42 @@ TextTrackManager::DidSeek()
}
void
TextTrackManager::Update(double aTime)
TextTrackManager::UpdateCueDisplay()
{
mTextTracks->Update(aTime);
nsIFrame* frame = mMediaElement->GetPrimaryFrame();
if (!frame) {
return;
}
nsVideoFrame* videoFrame = do_QueryFrame(frame);
if (!videoFrame) {
return;
}
nsCOMPtr<nsIContent> overlay = videoFrame->GetCaptionOverlay();
if (!overlay) {
return;
}
nsTArray<nsRefPtr<TextTrackCue> > activeCues;
mTextTracks->GetAllActiveCues(activeCues);
if (activeCues.Length() > 0) {
nsCOMPtr<nsIWritableVariant> jsCues =
do_CreateInstance("@mozilla.org/variant;1");
jsCues->SetAsArray(nsIDataType::VTYPE_INTERFACE,
&NS_GET_IID(nsIDOMEventTarget),
activeCues.Length(),
static_cast<void*>(activeCues.Elements()));
nsPIDOMWindow* window = mMediaElement->OwnerDoc()->GetWindow();
if (window) {
sParserWrapper->ProcessCues(window, jsCues, overlay);
}
} else if (overlay->nsINode::Length() > 0) {
nsContentUtils::SetNodeTextContent(overlay, EmptyString(), true);
}
}
void

View File

@ -11,11 +11,16 @@
#include "mozilla/dom/TextTrack.h"
#include "mozilla/dom/TextTrackList.h"
#include "mozilla/dom/TextTrackCueList.h"
#include "mozilla/StaticPtr.h"
class nsIWebVTTParserWrapper;
namespace mozilla {
namespace dom {
class HTMLMediaElement;
class TextTrack;
class TextTrackCue;
class TextTrackManager
{
@ -37,9 +42,35 @@ public:
void AddCue(TextTrackCue& aCue);
void AddCues(TextTrack* aTextTrack);
// Update the display of cues on the video as per the current play back time
// of aTime.
void Update(double aTime);
/**
* Overview of WebVTT cuetext and anonymous content setup.
*
* WebVTT nodes are the parsed version of WebVTT cuetext. WebVTT cuetext is
* the portion of a WebVTT cue that specifies what the caption will actually
* show up as on screen.
*
* WebVTT cuetext can contain markup that loosely relates to HTML markup. It
* can contain tags like <b>, <u>, <i>, <c>, <v>, <ruby>, <rt>, <lang>,
* including timestamp tags.
*
* When the caption is ready to be displayed the WebVTT nodes are converted
* over to anonymous DOM content. <i>, <u>, <b>, <ruby>, and <rt> all become
* HTMLElements of their corresponding HTML markup tags. <c> and <v> are
* converted to <span> tags. Timestamp tags are converted to XML processing
* instructions. Additionally, all cuetext tags support specifying of classes.
* This takes the form of <foo.class.subclass>. These classes are then parsed
* and set as the anonymous content's class attribute.
*
* Rules on constructing DOM objects from WebVTT nodes can be found here
* http://dev.w3.org/html5/webvtt/#webvtt-cue-text-dom-construction-rules.
* Current rules are taken from revision on April 15, 2013.
*/
/**
* Converts the TextTrackCue's cuetext into a tree of DOM objects and attaches
* it to a div on it's owning TrackElement's MediaElement's caption overlay.
*/
void UpdateCueDisplay();
void PopulatePendingList();
@ -55,6 +86,8 @@ private:
nsRefPtr<TextTrackList> mPendingTextTracks;
// List of newly introduced Text Track cues.
nsRefPtr<TextTrackCueList> mNewCues;
static StaticRefPtr<nsIWebVTTParserWrapper> sParserWrapper;
};
} // namespace dom

View File

@ -72,14 +72,6 @@ TextTrack::SetDefaultSettings()
mReadyState = HTMLTrackElement::NONE;
}
void
TextTrack::Update(double aTime)
{
if (mCueList) {
mCueList->Update(aTime);
}
}
JSObject*
TextTrack::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
@ -142,11 +134,11 @@ TextTrack::RemoveRegion(const TextTrackRegion& aRegion, ErrorResult& aRv)
mRegionList->RemoveTextTrackRegion(aRegion);
}
TextTrackCueList*
TextTrack::GetActiveCues()
void
TextTrack::UpdateActiveCueList()
{
if (mMode == TextTrackMode::Disabled || !mMediaElement) {
return nullptr;
return;
}
// If we are dirty, i.e. an event happened that may cause the sorted mCueList
@ -176,9 +168,21 @@ TextTrack::GetActiveCues()
mActiveCueList->AddCue(*(*mCueList)[mCuePos]);
}
}
}
TextTrackCueList*
TextTrack::GetActiveCues() {
UpdateActiveCueList();
return mActiveCueList;
}
void
TextTrack::GetActiveCueArray(nsTArray<nsRefPtr<TextTrackCue> >& aCues)
{
UpdateActiveCueList();
mActiveCueList->GetArray(aCues);
}
uint16_t
TextTrack::ReadyState() const
{

View File

@ -83,6 +83,7 @@ public:
}
TextTrackCueList* GetActiveCues();
void GetActiveCueArray(nsTArray<nsRefPtr<TextTrackCue> >& aCues);
TextTrackRegionList* GetRegions() const
{
@ -98,9 +99,6 @@ public:
void AddRegion(TextTrackRegion& aRegion);
void RemoveRegion(const TextTrackRegion& aRegion, ErrorResult& aRv);
// Time is in seconds.
void Update(double aTime);
void AddCue(TextTrackCue& aCue);
void RemoveCue(TextTrackCue& aCue, ErrorResult& aRv);
void CueChanged(TextTrackCue& aCue);
@ -109,6 +107,8 @@ public:
IMPL_EVENT_HANDLER(cuechange)
private:
void UpdateActiveCueList();
nsCOMPtr<nsISupports> mParent;
nsRefPtr<HTMLMediaElement> mMediaElement;

View File

@ -5,8 +5,6 @@
#include "mozilla/dom/HTMLTrackElement.h"
#include "mozilla/dom/TextTrackCue.h"
#include "nsIFrame.h"
#include "nsVideoFrame.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/ClearOnShutdown.h"
@ -36,6 +34,7 @@ void
TextTrackCue::SetDefaultCueSettings()
{
mPosition = 50;
mPositionAlign = AlignSetting::Middle;
mSize = 100;
mPauseOnExit = false;
mSnapToLines = true;
@ -100,57 +99,6 @@ TextTrackCue::StashDocument(nsISupports* aGlobal)
return NS_OK;
}
void
TextTrackCue::CreateCueOverlay()
{
mDocument->CreateElem(NS_LITERAL_STRING("div"), nullptr,
kNameSpaceID_XHTML,
getter_AddRefs(mDisplayState));
nsGenericHTMLElement* cueDiv =
static_cast<nsGenericHTMLElement*>(mDisplayState.get());
cueDiv->SetClassName(NS_LITERAL_STRING("caption-text"));
}
void
TextTrackCue::RenderCue()
{
nsRefPtr<DocumentFragment> frag = GetCueAsHTML();
if (!frag || !mTrackElement) {
return;
}
if (!mDisplayState) {
CreateCueOverlay();
}
HTMLMediaElement* parent = mTrackElement->mMediaParent;
if (!parent) {
return;
}
nsIFrame* frame = parent->GetPrimaryFrame();
if (!frame) {
return;
}
nsVideoFrame* videoFrame = do_QueryFrame(frame);
if (!videoFrame) {
return;
}
nsIContent* overlay = videoFrame->GetCaptionOverlay();
if (!overlay) {
return;
}
ErrorResult rv;
nsContentUtils::SetNodeTextContent(overlay, EmptyString(), true);
nsContentUtils::SetNodeTextContent(mDisplayState, EmptyString(), true);
mDisplayState->AppendChild(*frag, rv);
overlay->AppendChild(*mDisplayState, rv);
}
already_AddRefed<DocumentFragment>
TextTrackCue::GetCueAsHTML()
{

View File

@ -14,6 +14,7 @@
#include "nsIWebVTTParserWrapper.h"
#include "mozilla/StaticPtr.h"
#include "nsIDocument.h"
#include "mozilla/dom/HTMLDivElement.h"
namespace mozilla {
namespace dom {
@ -220,6 +221,26 @@ public:
CueChanged();
}
AlignSetting PositionAlign() const
{
return mPositionAlign;
}
void SetPositionAlign(AlignSetting aPositionAlign, ErrorResult& aRv)
{
if (mPositionAlign == aPositionAlign)
return;
if (aPositionAlign == AlignSetting::Left ||
aPositionAlign == AlignSetting::Right) {
return aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
}
mReset = true;
mPositionAlign = aPositionAlign;
CueChanged();
}
int32_t Size() const
{
return mSize;
@ -276,6 +297,21 @@ public:
IMPL_EVENT_HANDLER(enter)
IMPL_EVENT_HANDLER(exit)
HTMLDivElement* GetDisplayState()
{
return static_cast<HTMLDivElement*>(mDisplayState.get());
}
void SetDisplayState(HTMLDivElement* aDisplayState)
{
mDisplayState = aDisplayState;
}
bool HasBeenReset()
{
return mReset;
}
// Helper functions for implementation.
bool
operator==(const TextTrackCue& rhs) const
@ -288,36 +324,6 @@ public:
return mId;
}
/**
* Overview of WebVTT cuetext and anonymous content setup.
*
* WebVTT nodes are the parsed version of WebVTT cuetext. WebVTT cuetext is
* the portion of a WebVTT cue that specifies what the caption will actually
* show up as on screen.
*
* WebVTT cuetext can contain markup that loosely relates to HTML markup. It
* can contain tags like <b>, <u>, <i>, <c>, <v>, <ruby>, <rt>, <lang>,
* including timestamp tags.
*
* When the caption is ready to be displayed the WebVTT nodes are converted
* over to anonymous DOM content. <i>, <u>, <b>, <ruby>, and <rt> all become
* HTMLElements of their corresponding HTML markup tags. <c> and <v> are
* converted to <span> tags. Timestamp tags are converted to XML processing
* instructions. Additionally, all cuetext tags support specifying of classes.
* This takes the form of <foo.class.subclass>. These classes are then parsed
* and set as the anonymous content's class attribute.
*
* Rules on constructing DOM objects from WebVTT nodes can be found here
* http://dev.w3.org/html5/webvtt/#webvtt-cue-text-dom-construction-rules.
* Current rules are taken from revision on April 15, 2013.
*/
/**
* Converts the TextTrackCue's cuetext into a tree of DOM objects and attaches
* it to a div on it's owning TrackElement's MediaElement's caption overlay.
*/
void RenderCue();
/**
* Produces a tree of anonymous content based on the tree of the processed
* cue text.
@ -332,7 +338,6 @@ public:
private:
void CueChanged();
void SetDefaultCueSettings();
void CreateCueOverlay();
nsresult StashDocument(nsISupports* aGlobal);
nsRefPtr<nsIDocument> mDocument;
@ -344,6 +349,7 @@ private:
nsRefPtr<HTMLTrackElement> mTrackElement;
nsString mId;
int32_t mPosition;
AlignSetting mPositionAlign;
int32_t mSize;
bool mPauseOnExit;
bool mSnapToLines;
@ -355,7 +361,7 @@ private:
// Holds the computed DOM elements that represent the parsed cue text.
// http://www.whatwg.org/specs/web-apps/current-work/#text-track-cue-display-state
nsCOMPtr<nsIContent> mDisplayState;
nsRefPtr<nsGenericHTMLElement> mDisplayState;
// Tells whether or not we need to recompute mDisplayState. This is set
// anytime a property that relates to the display of the TextTrackCue is
// changed.

View File

@ -38,17 +38,6 @@ TextTrackCueList::TextTrackCueList(nsISupports* aParent) : mParent(aParent)
SetIsDOMBinding();
}
void
TextTrackCueList::Update(double aTime)
{
const uint32_t length = mList.Length();
for (uint32_t i = 0; i < length; i++) {
if (aTime > mList[i]->StartTime() && aTime < mList[i]->EndTime()) {
mList[i]->RenderCue();
}
}
}
JSObject*
TextTrackCueList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
@ -116,5 +105,12 @@ TextTrackCueList::RemoveAll()
mList.Clear();
}
void
TextTrackCueList::GetArray(nsTArray<nsRefPtr<TextTrackCue> >& aCues)
{
aCues = nsTArray<nsRefPtr<TextTrackCue> >(mList);
}
} // namespace dom
} // namespace mozilla

View File

@ -41,9 +41,6 @@ public:
return mList.Length();
}
// Time is in seconds.
void Update(double aTime);
TextTrackCue* IndexedGetter(uint32_t aIndex, bool& aFound);
TextTrackCue* operator[](uint32_t aIndex);
TextTrackCue* GetCueById(const nsAString& aId);
@ -56,6 +53,7 @@ public:
void RemoveCue(TextTrackCue& aCue, ErrorResult& aRv);
void RemoveCueAt(uint32_t aIndex);
void RemoveAll();
void GetArray(nsTArray<nsRefPtr<TextTrackCue> >& aCues);
private:
nsCOMPtr<nsISupports> mParent;

View File

@ -7,6 +7,7 @@
#include "mozilla/dom/TextTrackListBinding.h"
#include "mozilla/dom/TrackEvent.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/TextTrackCue.h"
namespace mozilla {
namespace dom {
@ -27,11 +28,14 @@ TextTrackList::TextTrackList(nsISupports* aGlobal) : mGlobal(aGlobal)
}
void
TextTrackList::Update(double aTime)
TextTrackList::GetAllActiveCues(nsTArray<nsRefPtr<TextTrackCue> >& aCues)
{
uint32_t length = Length(), i;
for (i = 0; i < length; i++) {
mTextTracks[i]->Update(aTime);
nsTArray< nsRefPtr<TextTrackCue> > cues;
for (uint32_t i = 0; i < Length(); i++) {
if (mTextTracks[i]->Mode() != TextTrackMode::Disabled) {
mTextTracks[i]->GetActiveCueArray(cues);
aCues.AppendElements(cues);
}
}
}

View File

@ -38,8 +38,8 @@ public:
return mTextTracks.Length();
}
// Time is in seconds.
void Update(double aTime);
// Get all the current active cues.
void GetAllActiveCues(nsTArray<nsRefPtr<TextTrackCue> >& aCues);
TextTrack* IndexedGetter(uint32_t aIndex, bool& aFound);

View File

@ -239,6 +239,7 @@ support-files =
[test_video_to_canvas.html]
[test_audiowrite.html]
[test_mediarecorder_creation.html]
[test_mediarecorder_creation_fail.html]
[test_mediarecorder_avoid_recursion.html]
[test_mediarecorder_record_timeslice.html]
[test_mediarecorder_record_audiocontext.html]

View File

@ -0,0 +1,74 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test MediaRecorder Record with media.ogg.enabled = false</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
function startTest() {
var element = document.createElement('audio');
element.src = 'detodos.opus';
element.stream = element.mozCaptureStream();
// the expect sequence should be
// 1. onerror
// 2. ondataavailable
// 3. onstop
var callbackStep = 0;
var mediaRecorder = new MediaRecorder(element.stream);
mediaRecorder.onerror = function (e) {
is(callbackStep, 0, 'should fired onstop callback');
is(e.name, 'GenericError', 'error name should be GenericError');
is(mediaRecorder.mimeType, '', 'mimetype should be empty');
is(mediaRecorder.state, 'recording', 'state is recording');
info('onerror callback fired');
SpecialPowers.setBoolPref('media.ogg.enabled', true);
callbackStep = 1;
};
mediaRecorder.onwarning = function () {
ok(false, 'Unexpected onwarning callback fired');
};
mediaRecorder.onstop = function () {
info('onstop callback fired');
is(mediaRecorder.state, 'inactive', 'state should be inactive');
is(callbackStep, 2, 'should fired onstop callback');
SimpleTest.finish();
};
// This handler fires every 250ms to generate a blob.
mediaRecorder.ondataavailable = function (evt) {
info('ondataavailable callback fired');
is(callbackStep, 1, 'should fired ondataavailable callback');
is(evt.data.size, 0, 'data size should be zero');
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.data.type, '', 'encoder start fail, blob miemType should be empty');
callbackStep = 2;
};
// Start recording once canplaythrough fires
element.oncanplaythrough = function() {
SpecialPowers.setBoolPref("media.ogg.enabled", false);
mediaRecorder.start(250);
is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
is(mediaRecorder.stream, element.stream,
'Media recorder stream = element stream at the start of recording');
};
element.play();
}
startTest();
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -104,6 +104,32 @@ SpecialPowers.pushPrefEnv({"set": [["media.webvtt.enabled", true]]},
cue.lineAlign = "end";
is(cue.lineAlign, "end", "Cue's line align should be end.");
// Check that cue position align works properly
is(cue.positionAlign, "middle", "Cue's default position alignment should be middle.");
var exceptionHappened = false;
try {
cue.positionAlign = "left";
} catch(e) {
exceptionHappened = true;
is(e.name, "SyntaxError", "Should have thrown SyntaxError.");
}
ok(exceptionHappened, "Exception should have happened.");
exceptionHappened = false;
try {
cue.positionAlign = "right";
} catch(e) {
exceptionHappened = true;
is(e.name, "SyntaxError", "Should have thrown SyntaxError.");
}
ok(exceptionHappened, "Exception should have happened.");
cue.positionAlign = "start";
is(cue.positionAlign, "start", "Cue's position align should be start.");
cue.positionAlign = "end";
is(cue.positionAlign, "end", "Cue's position align should be end.");
// Check that we can create and add new VTTCues
var vttCue = new VTTCue(3.999, 4, "foo");
trackElement.track.addCue(vttCue);

View File

@ -23,7 +23,8 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
NS_IMPL_ADDREF_INHERITED(OscillatorNode, AudioNode)
NS_IMPL_RELEASE_INHERITED(OscillatorNode, AudioNode)
static const float sLeak = 0.995f;
static const float sLeakTriangle = 0.995f;
static const float sLeak = 0.999f;
class DCBlocker
{
@ -320,7 +321,7 @@ public:
UpdateParametersIfNeeded(ticks, i);
// Integration to get us a square. It turns out we can have a
// pure integrator here.
mSquare += BipolarBLIT();
mSquare = mSquare * sLeak + BipolarBLIT();
aOutput[i] = mSquare;
// maybe we want to apply a gain, the wg has not decided yet
aOutput[i] *= 1.5;
@ -337,7 +338,7 @@ public:
dcoffset = mFinalFrequency / mSource->SampleRate();
// Integrate and offset so we get mAmplitudeAtZero sawtooth. We have a
// very low frequency component somewhere here, but I'm not sure where.
mSaw += UnipolarBLIT() - dcoffset;
mSaw = mSaw * sLeak + (UnipolarBLIT() - dcoffset);
// reverse the saw so we are spec compliant
aOutput[i] = -mSaw * 1.5;
@ -356,7 +357,7 @@ public:
// C6 = k0 / period
// (period is samplingrate / frequency, k0 = (PI/2)/(2*PI)) = 0.25
float C6 = 0.25 / (mSource->SampleRate() / mFinalFrequency);
mTriangle = mTriangle * sLeak + mSquare + C6;
mTriangle = mTriangle * sLeakTriangle + mSquare + C6;
// DC Block, and scale back to [-1.0; 1.0]
aOutput[i] = mDCBlocker.Process(mTriangle) / (mSignalPeriod/2) * 1.5;

View File

@ -50,6 +50,11 @@ WebVTTParserWrapper.prototype =
return WebVTTParser.convertCueToDOMTree(window, cue.text);
},
processCues: function(window, cues, overlay)
{
WebVTTParser.processCues(window, cues, null, overlay);
},
classDescription: "Wrapper for the JS WebVTTParser (vtt.js)",
classID: Components.ID(WEBVTTPARSERWRAPPER_CID),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebVTTParserWrapper]),

View File

@ -7,6 +7,7 @@
interface nsIDOMHTMLElement;
interface nsIWebVTTListener;
interface nsIDOMWindow;
interface nsIVariant;
/**
* Interface for a wrapper of a JS WebVTT parser (vtt.js).
@ -61,6 +62,24 @@ interface nsIWebVTTParserWrapper : nsISupports
*/
nsIDOMHTMLElement convertCueToDOMTree(in nsIDOMWindow window,
in nsISupports cue);
/**
* Compute the display state of the VTTCues in cues along with any VTTRegions
* that they might be in. First, it computes the positioning and styling of
* the cues and regions passed and converts them into a DOM tree rooted at
* a containing HTMLDivElement. It then adjusts those computed divs for
* overlap avoidance using the dimensions of 'overlay'. Finally, it adds the
* computed divs to the VTTCues display state property for use later.
*
* @param window A window object with which it will create the DOM tree
* and containing div element.
* @param cues An array of VTTCues who need there display state to be
* computed.
* @param overlay The HTMLElement that the cues will be displayed within.
*/
void processCues(in nsIDOMWindow window, in nsIVariant cues,
in nsISupports overlay);
};
%{C++

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,19 @@
#include <sys/stat.h>
#include <errno.h>
#define USE_DEBUG 0
#undef LOG
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OpenFileFinder", ## args)
#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "OpenFileFinder", ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
#if USE_DEBUG
#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
#else
#define DBG(args...)
#endif
namespace mozilla {
namespace system {

View File

@ -9,19 +9,6 @@
#include <dirent.h>
#define USE_DEBUG 0
#undef LOG
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OpenFileFinder", ## args)
#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "OpenFileFinder", ## args)
#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args)
#if USE_DEBUG
#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args)
#else
#define DBG(args...)
#endif
namespace mozilla {
namespace system {

View File

@ -42,6 +42,8 @@ interface VTTCue : EventTarget {
[SetterThrows]
attribute long position;
[SetterThrows]
attribute AlignSetting positionAlign;
[SetterThrows]
attribute long size;
attribute AlignSetting align;
attribute DOMString text;
@ -51,3 +53,11 @@ interface VTTCue : EventTarget {
attribute EventHandler onexit;
};
// Mozilla extensions.
partial interface VTTCue {
[ChromeOnly]
attribute HTMLDivElement? displayState;
[ChromeOnly]
readonly attribute boolean hasBeenReset;
};

View File

@ -13,6 +13,8 @@
#include "mozilla/gfx/2D.h"
#include "gfx2DGlue.h"
using namespace mozilla::gfx;
namespace mozilla {
namespace gl {
@ -204,14 +206,14 @@ GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType,
}
}
static void SwapRAndBComponents(gfxImageSurface* surf)
static void SwapRAndBComponents(DataSourceSurface* surf)
{
uint8_t *row = surf->Data();
uint8_t *row = surf->GetData();
size_t rowBytes = surf->Width()*4;
size_t rowBytes = surf->GetSize().width*4;
size_t rowHole = surf->Stride() - rowBytes;
size_t rows = surf->Height();
size_t rows = surf->GetSize().height;
while (rows) {
@ -282,19 +284,19 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
if (gl->DebugMode()) {
NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
}
gfx::SurfaceFormat readFormatGFX;
SurfaceFormat readFormatGFX;
switch (readFormat) {
case LOCAL_GL_RGBA:
case LOCAL_GL_BGRA: {
readFormatGFX = hasAlpha ? gfx::FORMAT_B8G8R8A8
: gfx::FORMAT_B8G8R8X8;
readFormatGFX = hasAlpha ? FORMAT_B8G8R8A8
: FORMAT_B8G8R8X8;
break;
}
case LOCAL_GL_RGB: {
MOZ_ASSERT(readPixelSize == 2);
MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV);
readFormatGFX = gfx::FORMAT_R5G6B5;
readFormatGFX = FORMAT_R5G6B5;
break;
}
default: {
@ -358,7 +360,12 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
// So we just copied in RGBA in big endian, or le: 0xAABBGGRR.
// We want 0xAARRGGBB, so swap R and B:
dest->Flush();
SwapRAndBComponents(readSurf);
RefPtr<DataSourceSurface> readDSurf =
Factory::CreateWrappingDataSourceSurface(readSurf->Data(),
readSurf->Stride(),
ToIntSize(readSurf->GetSize()),
ImageFormatToSurfaceFormat(readSurf->Format()));
SwapRAndBComponents(readDSurf);
dest->MarkDirty();
gfxContext ctx(dest);
@ -397,33 +404,50 @@ ReadPixelsIntoImageSurface(GLContext* gl, gfxImageSurface* dest) {
#endif
}
static already_AddRefed<gfxImageSurface> YInvertImageSurface(gfxImageSurface* aSurf)
static TemporaryRef<DataSourceSurface> YInvertImageSurface(DataSourceSurface* aSurf)
{
gfxIntSize size = aSurf->GetSize();
nsRefPtr<gfxImageSurface> temp = new gfxImageSurface(size, aSurf->Format());
nsRefPtr<gfxContext> ctx = new gfxContext(temp);
RefPtr<DataSourceSurface> temp =
Factory::CreateDataSourceSurfaceWithStride(aSurf->GetSize(),
aSurf->GetFormat(),
aSurf->Stride());
RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForData(BACKEND_CAIRO,
temp->GetData(),
temp->GetSize(),
temp->Stride(),
temp->GetFormat());
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
ctx->Scale(1.0, -1.0);
ctx->Translate(-gfxPoint(0.0, size.height));
ctx->SetSource(aSurf);
ctx->Translate(-gfxPoint(0.0, aSurf->GetSize().height));
nsRefPtr<gfxImageSurface> thebesSurf =
new gfxImageSurface(aSurf->GetData(),
ThebesIntSize(aSurf->GetSize()),
aSurf->Stride(),
SurfaceFormatToImageFormat(aSurf->GetFormat()));
ctx->SetSource(thebesSurf);
ctx->Paint();
return temp.forget();
}
already_AddRefed<gfxImageSurface>
GetTexImage(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat)
TemporaryRef<DataSourceSurface>
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, SurfaceFormat aFormat)
{
gl->MakeCurrent();
gl->GuaranteeResolve();
gl->fActiveTexture(LOCAL_GL_TEXTURE0);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
gfxIntSize size;
IntSize size;
gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(size, gfxImageFormatARGB32);
if (!surf || surf->CairoStatus()) {
RefPtr<DataSourceSurface> surf =
Factory::CreateDataSourceSurfaceWithStride(size, FORMAT_B8G8R8A8,
GetAlignedStride<4>(size.width * BytesPerPixel(FORMAT_B8G8R8A8)));
if (!surf) {
return nullptr;
}
@ -432,31 +456,18 @@ GetTexImage(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aF
if (currentPackAlignment != 4) {
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
}
gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->Data());
gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, surf->GetData());
if (currentPackAlignment != 4) {
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
if (aFormat == gfx::FORMAT_R8G8B8A8 || aFormat == gfx::FORMAT_R8G8B8X8) {
if (aFormat == FORMAT_R8G8B8A8 || aFormat == FORMAT_R8G8B8X8) {
SwapRAndBComponents(surf);
}
if (aYInvert) {
surf = YInvertImageSurface(surf);
}
return surf.forget();
}
TemporaryRef<gfx::DataSourceSurface>
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat)
{
nsRefPtr<gfxImageSurface> image = GetTexImage(gl, aTexture, aYInvert, aFormat);
RefPtr<gfx::DataSourceSurface> surf =
gfx::Factory::CreateDataSourceSurface(gfx::ToIntSize(image->GetSize()), aFormat);
if (!image->CopyTo(surf)) {
return nullptr;
}
return surf.forget();
}

View File

@ -27,9 +27,6 @@ namespace gl {
void ReadPixelsIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
void ReadScreenIntoImageSurface(GLContext* aGL, gfxImageSurface* aSurface);
already_AddRefed<gfxImageSurface>
GetTexImage(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);
TemporaryRef<gfx::DataSourceSurface>
ReadBackSurface(GLContext* gl, GLuint aTexture, bool aYInvert, gfx::SurfaceFormat aFormat);

View File

@ -11,12 +11,14 @@
#include "SharedSurfaceGL.h"
#include "SurfaceFactory.h"
#include "GLLibraryEGL.h"
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/ShadowLayers.h"
#include "ui/GraphicBuffer.h"
#include "../layers/ipc/ShadowLayers.h"
#include "ScopedGLHelpers.h"
#include "gfxPlatform.h"
#include "gfx2DGlue.h"
#define DEBUG_GRALLOC
@ -72,22 +74,23 @@ SharedSurface_Gralloc::Create(GLContext* prodGL,
if (!HasExtensions(egl, prodGL))
return nullptr;
SurfaceDescriptor baseDesc;
SurfaceDescriptorGralloc desc;
gfxContentType type = hasAlpha ? GFX_CONTENT_COLOR_ALPHA
: GFX_CONTENT_COLOR;
if (!allocator->AllocSurfaceDescriptorWithCaps(size, type, USING_GL_RENDERING_ONLY, &baseDesc))
return false;
: GFX_CONTENT_COLOR;
if (baseDesc.type() != SurfaceDescriptor::TSurfaceDescriptorGralloc) {
allocator->DestroySharedSurface(&baseDesc);
return false;
gfxImageFormat format
= gfxPlatform::GetPlatform()->OptimalFormatForContent(type);
GrallocTextureClientOGL* grallocTC =
new GrallocTextureClientOGL(
allocator,
gfx::ImageFormatToSurfaceFormat(format),
TEXTURE_FLAGS_DEFAULT);
if (!grallocTC->AllocateForGLRendering(size)) {
return nullptr;
}
desc = baseDesc.get_SurfaceDescriptorGralloc();
sp<GraphicBuffer> buffer = GrallocBufferActor::GetFrom(desc);
sp<GraphicBuffer> buffer = grallocTC->GetGraphicBuffer();
EGLDisplay display = egl->Display();
EGLClientBuffer clientBuffer = buffer->getNativeBuffer();
@ -99,7 +102,7 @@ SharedSurface_Gralloc::Create(GLContext* prodGL,
LOCAL_EGL_NATIVE_BUFFER_ANDROID,
clientBuffer, attrs);
if (!image) {
allocator->DestroySharedSurface(&baseDesc);
grallocTC->DropTextureData()->DeallocateSharedData(allocator);
return nullptr;
}
@ -117,7 +120,7 @@ SharedSurface_Gralloc::Create(GLContext* prodGL,
egl->fDestroyImage(display, image);
SharedSurface_Gralloc *surf = new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl, allocator, desc, prodTex);
SharedSurface_Gralloc *surf = new SharedSurface_Gralloc(prodGL, size, hasAlpha, egl, allocator, grallocTC, prodTex);
DEBUG_PRINT("SharedSurface_Gralloc::Create: success -- surface %p, GraphicBuffer %p.\n", surf, buffer.get());
@ -139,12 +142,6 @@ SharedSurface_Gralloc::~SharedSurface_Gralloc()
mGL->MakeCurrent();
mGL->fDeleteTextures(1, (GLuint*)&mProdTex);
SurfaceDescriptor desc(mDesc);
if (mAllocator) {
mAllocator->DestroySharedSurface(&desc);
}
}
void

View File

@ -7,13 +7,13 @@
#define SHARED_SURFACE_GRALLOC_H_
#include "SharedSurfaceGL.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/layers/TextureClient.h"
namespace mozilla {
namespace layers {
class ISurfaceAllocator;
class SurfaceDescriptorGralloc;
}
namespace gl {
@ -39,16 +39,7 @@ public:
protected:
GLLibraryEGL* const mEGL;
RefPtr<layers::ISurfaceAllocator> mAllocator;
// We keep the SurfaceDescriptor around, because we'll end up
// using it often and it's handy to do so. The actual
// GraphicBuffer is kept alive by the sp<GraphicBuffer> in
// GrallocBufferActor; the actor will stay alive until we
// explicitly destroy this descriptor (and thus deallocate the
// actor) it in the destructor of this class. This is okay to do
// on the client, but is very bad to do on the server (because on
// the client, the actor has no chance of going away unless the
// whole app died).
layers::SurfaceDescriptorGralloc mDesc;
RefPtr<layers::TextureClient> mTextureClient;
const GLuint mProdTex;
SharedSurface_Gralloc(GLContext* prodGL,
@ -56,7 +47,7 @@ protected:
bool hasAlpha,
GLLibraryEGL* egl,
layers::ISurfaceAllocator* allocator,
layers::SurfaceDescriptorGralloc& desc,
layers::TextureClient* textureClient,
GLuint prodTex)
: SharedSurface_GL(SharedSurfaceType::Gralloc,
AttachmentType::GLTexture,
@ -65,7 +56,7 @@ protected:
hasAlpha)
, mEGL(egl)
, mAllocator(allocator)
, mDesc(desc)
, mTextureClient(textureClient)
, mProdTex(prodTex)
{}
@ -84,8 +75,8 @@ public:
return mProdTex;
}
layers::SurfaceDescriptorGralloc& GetDescriptor() {
return mDesc;
layers::TextureClient* GetTextureClient() {
return mTextureClient;
}
};

View File

@ -1115,34 +1115,40 @@ void WriteSnapshotLinkToDumpFile(T* aObj, FILE* aFile)
}
template <typename T>
void WriteSnapshotToDumpFile_internal(T* aObj, gfxASurface* aSurf)
void WriteSnapshotToDumpFile_internal(T* aObj, DataSourceSurface* aSurf)
{
nsRefPtr<gfxImageSurface> deprecatedSurf =
new gfxImageSurface(aSurf->GetData(),
ThebesIntSize(aSurf->GetSize()),
aSurf->Stride(),
SurfaceFormatToImageFormat(aSurf->GetFormat()));
nsCString string(aObj->Name());
string.Append("-");
string.AppendInt((uint64_t)aObj);
if (gfxUtils::sDumpPaintFile) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "array[\"%s\"]=\"", string.BeginReading());
}
aSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
deprecatedSurf->DumpAsDataURL(gfxUtils::sDumpPaintFile);
if (gfxUtils::sDumpPaintFile) {
fprintf_stderr(gfxUtils::sDumpPaintFile, "\";");
}
}
void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf)
void WriteSnapshotToDumpFile(Layer* aLayer, DataSourceSurface* aSurf)
{
WriteSnapshotToDumpFile_internal(aLayer, aSurf);
}
void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf)
void WriteSnapshotToDumpFile(LayerManager* aManager, DataSourceSurface* aSurf)
{
WriteSnapshotToDumpFile_internal(aManager, aSurf);
}
void WriteSnapshotToDumpFile(Compositor* aCompositor, DrawTarget* aTarget)
{
nsRefPtr<gfxASurface> surf = gfxPlatform::GetPlatform()->GetThebesSurfaceForDrawTarget(aTarget);
WriteSnapshotToDumpFile_internal(aCompositor, surf);
RefPtr<SourceSurface> surf = aTarget->Snapshot();
RefPtr<DataSourceSurface> dSurf = surf->GetDataSurface();
WriteSnapshotToDumpFile_internal(aCompositor, dSurf);
}
#endif

View File

@ -2046,8 +2046,8 @@ void SetAntialiasingFlags(Layer* aLayer, gfxContext* aTarget);
void SetAntialiasingFlags(Layer* aLayer, gfx::DrawTarget* aTarget);
#ifdef MOZ_DUMP_PAINTING
void WriteSnapshotToDumpFile(Layer* aLayer, gfxASurface* aSurf);
void WriteSnapshotToDumpFile(LayerManager* aManager, gfxASurface* aSurf);
void WriteSnapshotToDumpFile(Layer* aLayer, gfx::DataSourceSurface* aSurf);
void WriteSnapshotToDumpFile(LayerManager* aManager, gfx::DataSourceSurface* aSurf);
void WriteSnapshotToDumpFile(Compositor* aCompositor, gfx::DrawTarget* aTarget);
#endif

View File

@ -15,8 +15,10 @@
#include "gfxPlatform.h" // for gfxPlatform
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/GrallocTextureClient.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
#include "mozilla/layers/TextureClientOGL.h"
#include "nsAutoPtr.h" // for nsRefPtr
#include "nsDebug.h" // for printf_stderr, NS_ASSERTION
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
@ -27,12 +29,6 @@
using namespace mozilla::gfx;
using namespace mozilla::gl;
namespace mozilla {
namespace gfx {
class SharedSurface;
}
}
namespace mozilla {
namespace layers {
@ -44,7 +40,7 @@ CanvasClient::CreateCanvasClient(CanvasClientType aType,
if (aType == CanvasClientGLContext &&
aForwarder->GetCompositorBackendType() == LAYERS_OPENGL) {
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
return new DeprecatedCanvasClientSurfaceStream(aForwarder, aFlags);
return new CanvasClientSurfaceStream(aForwarder, aFlags);
}
if (gfxPlatform::GetPlatform()->UseDeprecatedTextures()) {
aFlags |= TEXTURE_DEALLOCATE_CLIENT;
@ -106,6 +102,73 @@ CanvasClient2D::CreateBufferTextureClient(gfx::SurfaceFormat aFormat, TextureFla
mTextureInfo.mTextureFlags | aFlags);
}
CanvasClientSurfaceStream::CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder,
TextureFlags aFlags)
: CanvasClient(aLayerForwarder, aFlags)
{
}
void
CanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer)
{
GLScreenBuffer* screen = aLayer->mGLContext->Screen();
SurfaceStream* stream = screen->Stream();
bool isCrossProcess = !(XRE_GetProcessType() == GeckoProcessType_Default);
bool bufferCreated = false;
if (isCrossProcess) {
#ifdef MOZ_WIDGET_GONK
SharedSurface* surf = stream->SwapConsumer();
if (!surf) {
printf_stderr("surf is null post-SwapConsumer!\n");
return;
}
if (surf->Type() != SharedSurfaceType::Gralloc) {
printf_stderr("Unexpected non-Gralloc SharedSurface in IPC path!");
MOZ_ASSERT(false);
return;
}
SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
GrallocTextureClientOGL* grallocTextureClient =
static_cast<GrallocTextureClientOGL*>(grallocSurf->GetTextureClient());
// If IPDLActor is null means this TextureClient didn't AddTextureClient yet
if (!grallocTextureClient->GetIPDLActor()) {
grallocTextureClient->SetTextureFlags(mTextureInfo.mTextureFlags);
AddTextureClient(grallocTextureClient);
}
if (grallocTextureClient->GetIPDLActor()) {
GetForwarder()->UseTexture(this, grallocTextureClient);
}
#else
printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
MOZ_ASSERT(false);
#endif
} else {
if (!mBuffer) {
StreamTextureClientOGL* textureClient =
new StreamTextureClientOGL(mTextureInfo.mTextureFlags);
textureClient->InitWith(stream);
mBuffer = textureClient;
bufferCreated = true;
}
if (bufferCreated && !AddTextureClient(mBuffer)) {
mBuffer = nullptr;
}
if (mBuffer) {
GetForwarder()->UseTexture(this, mBuffer);
}
}
aLayer->Painted();
}
void
DeprecatedCanvasClient2D::Updated()
{
@ -206,7 +269,8 @@ DeprecatedCanvasClientSurfaceStream::Update(gfx::IntSize aSize, ClientCanvasLaye
}
SharedSurface_Gralloc* grallocSurf = SharedSurface_Gralloc::Cast(surf);
mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
//XXX todo
//mDeprecatedTextureClient->SetDescriptor(grallocSurf->GetDescriptor());
#else
printf_stderr("isCrossProcess, but not MOZ_WIDGET_GONK! Someone needs to write some code!");
MOZ_ASSERT(false);

View File

@ -18,6 +18,12 @@
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/gfx/Types.h" // for SurfaceFormat
namespace mozilla {
namespace gfx {
class SharedSurface;
}
}
namespace mozilla {
namespace layers {
@ -95,6 +101,29 @@ private:
RefPtr<TextureClient> mBuffer;
};
// Used for GL canvases where we don't need to do any readback, i.e., with a
// GL backend.
class CanvasClientSurfaceStream : public CanvasClient
{
public:
CanvasClientSurfaceStream(CompositableForwarder* aLayerForwarder, TextureFlags aFlags);
TextureInfo GetTextureInfo() const
{
return TextureInfo(COMPOSITABLE_IMAGE);
}
virtual void Update(gfx::IntSize aSize, ClientCanvasLayer* aLayer) MOZ_OVERRIDE;
virtual void OnDetach() MOZ_OVERRIDE
{
mBuffer = nullptr;
}
private:
RefPtr<TextureClient> mBuffer;
};
class DeprecatedCanvasClient2D : public CanvasClient
{
public:

View File

@ -51,11 +51,11 @@ public:
"Can only set properties in construction phase");
CanvasLayer::SetVisibleRegion(aRegion);
}
virtual void Initialize(const Data& aData);
virtual void RenderLayer();
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
{
aAttrs = CanvasLayerAttributes(mFilter, mBounds);
@ -63,7 +63,7 @@ public:
virtual Layer* AsLayer() { return this; }
virtual ShadowableLayer* AsShadowableLayer() { return this; }
virtual void Disconnect()
{
mCanvasClient = nullptr;
@ -79,7 +79,7 @@ protected:
{
return static_cast<ClientLayerManager*>(mManager);
}
CanvasClientType GetCanvasClientType()
{
if (mGLContext) {
@ -93,6 +93,7 @@ protected:
friend class DeprecatedCanvasClient2D;
friend class CanvasClient2D;
friend class DeprecatedCanvasClientSurfaceStream;
friend class CanvasClientSurfaceStream;
};
}
}

View File

@ -522,8 +522,8 @@ TemporaryRef<gfx::DrawTarget>
BufferTextureClient::GetAsDrawTarget()
{
MOZ_ASSERT(IsValid());
// XXX - uncomment when ContentClient's locking is fixed
// MOZ_ASSERT(mLocked);
// XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
NS_WARN_IF_FALSE(mLocked, "GetAsDrawTarget should be called on locked textures only");
if (mDrawTarget) {
return mDrawTarget;
@ -560,7 +560,8 @@ BufferTextureClient::GetAsDrawTarget()
bool
BufferTextureClient::Lock(OpenMode aMode)
{
MOZ_ASSERT(!mLocked);
// XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
NS_WARN_IF_FALSE(!mLocked, "The TextureClient is already Locked!");
mOpenMode = aMode;
mLocked = true;
return true;
@ -569,7 +570,8 @@ BufferTextureClient::Lock(OpenMode aMode)
void
BufferTextureClient::Unlock()
{
MOZ_ASSERT(mLocked);
// XXX - Turn this into a fatal assertion as soon as Bug 952507 is fixed
NS_WARN_IF_FALSE(mLocked, "The TextureClient is already Unlocked!");
mLocked = false;
if (!mDrawTarget) {
mUsingFallbackDrawTarget = false;

View File

@ -70,13 +70,7 @@ CanvasLayerComposite::RenderLayer(const nsIntRect& aClipRect)
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
RefPtr<gfx::DataSourceSurface> dSurf = mImageHost->GetAsSurface();
gfxPlatform *platform = gfxPlatform::GetPlatform();
RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
dSurf->GetSize(),
dSurf->Stride(),
dSurf->GetFormat());
nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
RefPtr<gfx::DataSourceSurface> surf = mImageHost->GetAsSurface();
WriteSnapshotToDumpFile(this, surf);
}
#endif

View File

@ -333,7 +333,7 @@ ContainerRender(ContainerT* aContainer,
// Unbind the current surface and rebind the previous one.
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
nsRefPtr<gfxImageSurface> surf = surface->Dump(aManager->GetCompositor());
RefPtr<gfx::DataSourceSurface> surf = surface->Dump(aManager->GetCompositor());
WriteSnapshotToDumpFile(aContainer, surf);
}
#endif

View File

@ -84,13 +84,7 @@ ImageLayerComposite::RenderLayer(const nsIntRect& aClipRect)
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
RefPtr<gfx::DataSourceSurface> dSurf = mImageHost->GetAsSurface();
gfxPlatform *platform = gfxPlatform::GetPlatform();
RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
dSurf->GetSize(),
dSurf->Stride(),
dSurf->GetFormat());
nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
RefPtr<gfx::DataSourceSurface> surf = mImageHost->GetAsSurface();
WriteSnapshotToDumpFile(this, surf);
}
#endif

View File

@ -843,7 +843,7 @@ public:
virtual ~CompositingRenderTarget() {}
#ifdef MOZ_DUMP_PAINTING
virtual already_AddRefed<gfxImageSurface> Dump(Compositor* aCompositor) { return nullptr; }
virtual TemporaryRef<gfx::DataSourceSurface> Dump(Compositor* aCompositor) { return nullptr; }
#endif
const gfx::IntPoint& GetOrigin() { return mOrigin; }

View File

@ -111,14 +111,8 @@ ThebesLayerComposite::RenderLayer(const nsIntRect& aClipRect)
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
RefPtr<gfx::DataSourceSurface> dSurf = mBuffer->GetAsSurface();
if (dSurf) {
gfxPlatform *platform = gfxPlatform::GetPlatform();
RefPtr<gfx::DrawTarget> dt = platform->CreateDrawTargetForData(dSurf->GetData(),
dSurf->GetSize(),
dSurf->Stride(),
dSurf->GetFormat());
nsRefPtr<gfxASurface> surf = platform->GetThebesSurfaceForDrawTarget(dt);
RefPtr<gfx::DataSourceSurface> surf = mBuffer->GetAsSurface();
if (surf) {
WriteSnapshotToDumpFile(this, surf);
}
}

View File

@ -133,7 +133,7 @@ namespace layers {
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*/
static float gTouchStartTolerance = 1.0f/16.0f;
static float gTouchStartTolerance = 1.0f/2.0f;
/**
* Angle from axis within which we stay axis-locked

View File

@ -6,8 +6,11 @@
#include "CompositingRenderTargetOGL.h"
#include "GLContext.h"
#include "GLReadTexImageHelper.h"
#include "mozilla/gfx/2D.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::gl;
using namespace mozilla::layers;
CompositingRenderTargetOGL::~CompositingRenderTargetOGL()
@ -57,12 +60,12 @@ CompositingRenderTargetOGL::BindRenderTarget()
}
#ifdef MOZ_DUMP_PAINTING
already_AddRefed<gfxImageSurface>
TemporaryRef<DataSourceSurface>
CompositingRenderTargetOGL::Dump(Compositor* aCompositor)
{
MOZ_ASSERT(mInitParams.mStatus == InitParams::INITIALIZED);
CompositorOGL* compositorOGL = static_cast<CompositorOGL*>(aCompositor);
return GetTexImage(mGL, mTextureHandle, true, compositorOGL->GetFBOFormat());
return ReadBackSurface(mGL, mTextureHandle, true, compositorOGL->GetFBOFormat());
}
#endif

View File

@ -29,6 +29,9 @@ namespace mozilla {
namespace gl {
class BindableTexture;
}
namespace gfx {
class DataSourceSurface;
}
namespace layers {
@ -152,7 +155,7 @@ public:
}
#ifdef MOZ_DUMP_PAINTING
virtual already_AddRefed<gfxImageSurface> Dump(Compositor* aCompositor);
virtual TemporaryRef<gfx::DataSourceSurface> Dump(Compositor* aCompositor);
#endif
private:

View File

@ -93,6 +93,7 @@ GrallocTextureClientOGL::GrallocTextureClientOGL(GrallocBufferActor* aActor,
gfx::IntSize aSize,
TextureFlags aFlags)
: BufferTextureClient(nullptr, gfx::FORMAT_UNKNOWN, aFlags)
, mAllocator(nullptr)
, mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
, mMappedBuffer(nullptr)
{
@ -104,6 +105,18 @@ GrallocTextureClientOGL::GrallocTextureClientOGL(CompositableClient* aCompositab
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: BufferTextureClient(aCompositable, aFormat, aFlags)
, mAllocator(nullptr)
, mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
, mMappedBuffer(nullptr)
{
MOZ_COUNT_CTOR(GrallocTextureClientOGL);
}
GrallocTextureClientOGL::GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags)
: BufferTextureClient(nullptr, aFormat, aFlags)
, mAllocator(aAllocator)
, mGrallocFlags(android::GraphicBuffer::USAGE_SW_READ_OFTEN)
, mMappedBuffer(nullptr)
{
@ -119,13 +132,14 @@ GrallocTextureClientOGL::~GrallocTextureClientOGL()
if (mBufferLocked) {
mBufferLocked->Unlock();
} else {
MOZ_ASSERT(mCompositable);
// We just need to wrap the actor in a SurfaceDescriptor because that's what
// ISurfaceAllocator uses as input, we don't care about the other parameters.
SurfaceDescriptor sd = SurfaceDescriptorGralloc(nullptr, mGrallocActor,
IntSize(0, 0),
false, false);
mCompositable->GetForwarder()->DestroySharedSurface(&sd);
ISurfaceAllocator* allocator = GetAllocator();
allocator->DestroySharedSurface(&sd);
}
}
}
@ -195,8 +209,6 @@ GrallocTextureClientOGL::AllocateForSurface(gfx::IntSize aSize,
TextureAllocationFlags)
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mCompositable);
ISurfaceAllocator* allocator = mCompositable->GetForwarder();
uint32_t format;
uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN;
@ -237,14 +249,46 @@ GrallocTextureClientOGL::AllocateForYCbCr(gfx::IntSize aYSize, gfx::IntSize aCbC
android::GraphicBuffer::USAGE_SW_READ_OFTEN);
}
bool
GrallocTextureClientOGL::AllocateForGLRendering(gfx::IntSize aSize)
{
MOZ_ASSERT(IsValid());
uint32_t format;
uint32_t usage = android::GraphicBuffer::USAGE_HW_RENDER |
android::GraphicBuffer::USAGE_HW_TEXTURE;
switch (mFormat) {
case gfx::FORMAT_R8G8B8A8:
case gfx::FORMAT_B8G8R8A8:
format = android::PIXEL_FORMAT_RGBA_8888;
break;
case gfx::FORMAT_R8G8B8X8:
case gfx::FORMAT_B8G8R8X8:
// there is no android BGRX format?
format = android::PIXEL_FORMAT_RGBX_8888;
break;
case gfx::FORMAT_R5G6B5:
format = android::PIXEL_FORMAT_RGB_565;
break;
case gfx::FORMAT_A8:
format = android::PIXEL_FORMAT_A_8;
break;
default:
NS_WARNING("Unsupported surface format");
return false;
}
return AllocateGralloc(aSize, format, usage);
}
bool
GrallocTextureClientOGL::AllocateGralloc(gfx::IntSize aSize,
uint32_t aAndroidFormat,
uint32_t aUsage)
{
MOZ_ASSERT(IsValid());
MOZ_ASSERT(mCompositable);
ISurfaceAllocator* allocator = mCompositable->GetForwarder();
ISurfaceAllocator* allocator = GetAllocator();
MaybeMagicGrallocBufferHandle handle;
PGrallocBufferChild* actor =
@ -295,6 +339,15 @@ GrallocTextureClientOGL::GetBufferSize() const
return 0;
}
ISurfaceAllocator*
GrallocTextureClientOGL::GetAllocator()
{
MOZ_ASSERT(mCompositable || mAllocator);
return mCompositable ?
mCompositable->GetForwarder() :
mAllocator;
}
} // namesapace layers
} // namesapace mozilla

View File

@ -39,6 +39,9 @@ public:
GrallocTextureClientOGL(CompositableClient* aCompositable,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
GrallocTextureClientOGL(ISurfaceAllocator* aAllocator,
gfx::SurfaceFormat aFormat,
TextureFlags aFlags = TEXTURE_FLAGS_DEFAULT);
~GrallocTextureClientOGL();
@ -56,6 +59,8 @@ public:
void InitWith(GrallocBufferActor* aActor, gfx::IntSize aSize);
void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
android::GraphicBuffer* GetGraphicBuffer()
@ -87,6 +92,8 @@ public:
gfx::IntSize aCbCrSize,
StereoMode aStereoMode) MOZ_OVERRIDE;
bool AllocateForGLRendering(gfx::IntSize aSize);
bool AllocateGralloc(gfx::IntSize aYSize, uint32_t aAndroidFormat, uint32_t aUsage);
virtual bool Allocate(uint32_t aSize) MOZ_OVERRIDE;
@ -96,6 +103,7 @@ public:
void SetGraphicBufferLocked(GraphicBufferLocked* aBufferLocked);
protected:
ISurfaceAllocator* GetAllocator();
/**
* Unfortunately, until bug 879681 is fixed we need to use a GrallocBufferActor.
@ -106,6 +114,8 @@ protected:
android::sp<android::GraphicBuffer> mGraphicBuffer;
RefPtr<ISurfaceAllocator> mAllocator;
/**
* Flags that are used when locking the gralloc buffer
*/

View File

@ -3,10 +3,11 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/layers/TextureClientOGL.h"
#include "GLContext.h" // for GLContext, etc
#include "SurfaceStream.h"
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
#include "mozilla/layers/ISurfaceAllocator.h"
#include "mozilla/layers/TextureClientOGL.h"
#include "nsSize.h" // for nsIntSize
using namespace mozilla::gl;
@ -65,6 +66,42 @@ SharedTextureClientOGL::IsAllocated() const
return mHandle != 0;
}
StreamTextureClientOGL::StreamTextureClientOGL(TextureFlags aFlags)
: TextureClient(aFlags)
, mStream(0)
{
}
StreamTextureClientOGL::~StreamTextureClientOGL()
{
// the data is owned externally.
}
bool
StreamTextureClientOGL::ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor)
{
if (!IsAllocated()) {
return false;
}
gfx::SurfaceStreamHandle handle = mStream->GetShareHandle();
aOutDescriptor = SurfaceStreamDescriptor(handle, false);
return true;
}
void
StreamTextureClientOGL::InitWith(gfx::SurfaceStream* aStream)
{
MOZ_ASSERT(!IsAllocated());
mStream = aStream;
}
bool
StreamTextureClientOGL::IsAllocated() const
{
return mStream != 0;
}
DeprecatedTextureClientSharedOGL::DeprecatedTextureClientSharedOGL(CompositableForwarder* aForwarder,
const TextureInfo& aTextureInfo)
: DeprecatedTextureClient(aForwarder, aTextureInfo)

View File

@ -14,6 +14,12 @@
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
#include "mozilla/layers/TextureClient.h" // for DeprecatedTextureClient, etc
namespace mozilla {
namespace gfx {
class SurfaceStream;
}
}
namespace mozilla {
namespace layers {
@ -57,6 +63,30 @@ protected:
bool mInverted;
};
/**
* A TextureClient implementation to share SurfaceStream.
*/
class StreamTextureClientOGL : public TextureClient
{
public:
StreamTextureClientOGL(TextureFlags aFlags);
~StreamTextureClientOGL();
virtual bool IsAllocated() const MOZ_OVERRIDE;
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
virtual TextureClientData* DropTextureData() MOZ_OVERRIDE { return nullptr; }
void InitWith(gfx::SurfaceStream* aStream);
virtual gfx::IntSize GetSize() const { return gfx::IntSize(); }
protected:
gfx::SurfaceStream* mStream;
};
class DeprecatedTextureClientSharedOGL : public DeprecatedTextureClient
{
public:

View File

@ -108,6 +108,11 @@ CreateTextureHostOGL(const SurfaceDescriptor& aDesc,
desc.inverted());
break;
}
case SurfaceDescriptor::TSurfaceStreamDescriptor: {
const SurfaceStreamDescriptor& desc = aDesc.get_SurfaceStreamDescriptor();
result = new StreamTextureHostOGL(aFlags, desc);
break;
}
#ifdef XP_MACOSX
case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
const SurfaceDescriptorMacIOSurface& desc =
@ -463,6 +468,184 @@ SharedTextureHostOGL::GetFormat() const
return mTextureSource->GetFormat();
}
void
StreamTextureSourceOGL::BindTexture(GLenum activetex)
{
MOZ_ASSERT(gl());
gl()->fActiveTexture(activetex);
gl()->fBindTexture(mTextureTarget, mTextureHandle);
}
bool
StreamTextureSourceOGL::RetrieveTextureFromStream()
{
gl()->MakeCurrent();
SharedSurface* sharedSurf = mStream->SwapConsumer();
if (!sharedSurf) {
// We don't have a valid surf to show yet.
return false;
}
gl()->MakeCurrent();
mSize = IntSize(sharedSurf->Size().width, sharedSurf->Size().height);
DataSourceSurface* toUpload = nullptr;
switch (sharedSurf->Type()) {
case SharedSurfaceType::GLTextureShare: {
SharedSurface_GLTexture* glTexSurf = SharedSurface_GLTexture::Cast(sharedSurf);
glTexSurf->SetConsumerGL(gl());
mTextureHandle = glTexSurf->Texture();
mTextureTarget = glTexSurf->TextureTarget();
MOZ_ASSERT(mTextureHandle);
mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8
: FORMAT_R8G8B8X8;
break;
}
case SharedSurfaceType::EGLImageShare: {
SharedSurface_EGLImage* eglImageSurf =
SharedSurface_EGLImage::Cast(sharedSurf);
mTextureHandle = eglImageSurf->AcquireConsumerTexture(gl());
mTextureTarget = eglImageSurf->TextureTarget();
if (!mTextureHandle) {
toUpload = eglImageSurf->GetPixels();
MOZ_ASSERT(toUpload);
} else {
mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8
: FORMAT_R8G8B8X8;
}
break;
}
#ifdef XP_MACOSX
case SharedSurfaceType::IOSurface: {
SharedSurface_IOSurface* glTexSurf = SharedSurface_IOSurface::Cast(sharedSurf);
mTextureHandle = glTexSurf->Texture();
mTextureTarget = glTexSurf->TextureTarget();
MOZ_ASSERT(mTextureHandle);
mFormat = sharedSurf->HasAlpha() ? FORMAT_R8G8B8A8
: FORMAT_R8G8B8X8;
break;
}
#endif
case SharedSurfaceType::Basic: {
toUpload = SharedSurface_Basic::Cast(sharedSurf)->GetData();
MOZ_ASSERT(toUpload);
break;
}
default:
MOZ_CRASH("Invalid SharedSurface type.");
}
if (toUpload) {
// mBounds seems to end up as (0,0,0,0) a lot, so don't use it?
nsIntSize size(ThebesIntSize(toUpload->GetSize()));
nsIntRect rect(nsIntPoint(0,0), size);
nsIntRegion bounds(rect);
mFormat = UploadSurfaceToTexture(gl(),
toUpload,
bounds,
mUploadTexture,
true);
mTextureHandle = mUploadTexture;
mTextureTarget = LOCAL_GL_TEXTURE_2D;
}
MOZ_ASSERT(mTextureHandle);
gl()->fBindTexture(mTextureTarget, mTextureHandle);
gl()->fTexParameteri(mTextureTarget,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
gl()->fTexParameteri(mTextureTarget,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
return true;
}
void
StreamTextureSourceOGL::DeallocateDeviceData()
{
if (mUploadTexture) {
MOZ_ASSERT(gl());
gl()->MakeCurrent();
gl()->fDeleteTextures(1, &mUploadTexture);
mUploadTexture = 0;
mTextureHandle = 0;
}
}
gl::GLContext*
StreamTextureSourceOGL::gl() const
{
return mCompositor ? mCompositor->gl() : nullptr;
}
void
StreamTextureSourceOGL::SetCompositor(Compositor* aCompositor)
{
mCompositor = static_cast<CompositorOGL*>(aCompositor);
}
StreamTextureHostOGL::StreamTextureHostOGL(TextureFlags aFlags,
const SurfaceStreamDescriptor& aDesc)
: TextureHost(aFlags)
{
mStream = SurfaceStream::FromHandle(aDesc.handle());
MOZ_ASSERT(mStream);
}
StreamTextureHostOGL::~StreamTextureHostOGL()
{
// If need to deallocate textures, call DeallocateSharedData() before
// the destructor
}
bool
StreamTextureHostOGL::Lock()
{
if (!mCompositor) {
return false;
}
if (!mTextureSource) {
mTextureSource = new StreamTextureSourceOGL(mCompositor,
mStream);
}
return mTextureSource->RetrieveTextureFromStream();
}
void
StreamTextureHostOGL::Unlock()
{
}
void
StreamTextureHostOGL::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
mCompositor = glCompositor;
if (mTextureSource) {
mTextureSource->SetCompositor(glCompositor);
}
}
gfx::SurfaceFormat
StreamTextureHostOGL::GetFormat() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource->GetFormat();
}
gfx::IntSize
StreamTextureHostOGL::GetSize() const
{
MOZ_ASSERT(mTextureSource);
return mTextureSource->GetSize();
}
TextureImageDeprecatedTextureHostOGL::~TextureImageDeprecatedTextureHostOGL()
{
MOZ_COUNT_DTOR(TextureImageDeprecatedTextureHostOGL);

View File

@ -335,6 +335,108 @@ protected:
RefPtr<SharedTextureSourceOGL> mTextureSource;
};
/**
* A texture source meant for use with StreamTextureHostOGL.
*
* It does not own any texture, we get texture from SurfaceStream.
*/
class StreamTextureSourceOGL : public NewTextureSource
, public TextureSourceOGL
{
public:
StreamTextureSourceOGL(CompositorOGL* aCompositor,
gfx::SurfaceStream* aStream)
: mCompositor(aCompositor)
, mStream(aStream)
, mTextureHandle(0)
, mTextureTarget(LOCAL_GL_TEXTURE_2D)
, mUploadTexture(0)
, mFormat(gfx::FORMAT_UNKNOWN)
{
MOZ_COUNT_CTOR(StreamTextureSourceOGL);
}
~StreamTextureSourceOGL()
{
MOZ_COUNT_DTOR(StreamTextureSourceOGL);
}
virtual TextureSourceOGL* AsSourceOGL() { return this; }
virtual void BindTexture(GLenum activetex) MOZ_OVERRIDE;
virtual bool IsValid() const MOZ_OVERRIDE { return !!gl(); }
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE { return mFormat; }
virtual GLenum GetTextureTarget() const { return mTextureTarget; }
virtual GLenum GetWrapMode() const MOZ_OVERRIDE { return LOCAL_GL_CLAMP_TO_EDGE; }
virtual void DeallocateDeviceData();
bool RetrieveTextureFromStream();
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
protected:
gl::GLContext* gl() const;
CompositorOGL* mCompositor;
gfx::SurfaceStream* mStream;
GLuint mTextureHandle;
GLenum mTextureTarget;
GLuint mUploadTexture;
gfx::IntSize mSize;
gfx::SurfaceFormat mFormat;
};
/**
* A TextureHost for shared SurfaceStream
*/
class StreamTextureHostOGL : public TextureHost
{
public:
StreamTextureHostOGL(TextureFlags aFlags,
const SurfaceStreamDescriptor& aDesc);
virtual ~StreamTextureHostOGL();
// SharedTextureHostOGL doesn't own any GL texture
virtual void DeallocateDeviceData() MOZ_OVERRIDE {}
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE;
virtual bool Lock() MOZ_OVERRIDE;
virtual void Unlock() MOZ_OVERRIDE;
virtual gfx::SurfaceFormat GetFormat() const MOZ_OVERRIDE;
virtual NewTextureSource* GetTextureSources() MOZ_OVERRIDE
{
return mTextureSource;
}
virtual TemporaryRef<gfx::DataSourceSurface> GetAsSurface() MOZ_OVERRIDE
{
return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
}
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
#ifdef MOZ_LAYERS_HAVE_LOG
virtual const char* Name() { return "StreamTextureHostOGL"; }
#endif
protected:
CompositorOGL* mCompositor;
gfx::SurfaceStream* mStream;
RefPtr<StreamTextureSourceOGL> mTextureSource;
};
/**
* DeprecatedTextureHost implementation using a TextureImage as the underlying texture.
*/

View File

@ -0,0 +1,135 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gtest/gtest.h"
#include "gfxSkipChars.h"
#include "mozilla/ArrayUtils.h"
static bool
TestConstructor()
{
gfxSkipChars skipChars;
EXPECT_TRUE(skipChars.GetOriginalCharCount() == 0) <<
"[1] Make sure the gfxSkipChars was properly initialized with constructor";
return true;
}
static bool
TestLength()
{
gfxSkipChars skipChars;
skipChars.KeepChars(100);
EXPECT_TRUE(skipChars.GetOriginalCharCount() == 100) <<
"[1] Check length after keeping chars";
skipChars.SkipChars(50);
EXPECT_TRUE(skipChars.GetOriginalCharCount() == 150) <<
"[2] Check length after skipping chars";
skipChars.SkipChars(50);
EXPECT_TRUE(skipChars.GetOriginalCharCount() == 200) <<
"[3] Check length after skipping more chars";
skipChars.KeepChar();
EXPECT_TRUE(skipChars.GetOriginalCharCount() == 201) <<
"[4] Check length after keeping a final char";
return true;
}
static bool
TestIterator()
{
// Test a gfxSkipChars that starts with kept chars
gfxSkipChars skipChars1;
skipChars1.KeepChars(9);
skipChars1.SkipChar();
skipChars1.KeepChars(9);
skipChars1.SkipChar();
skipChars1.KeepChars(9);
EXPECT_TRUE(skipChars1.GetOriginalCharCount() == 29) <<
"[1] Check length";
gfxSkipCharsIterator iter1(skipChars1);
EXPECT_TRUE(iter1.GetOriginalOffset() == 0) <<
"[2] Check initial original offset";
EXPECT_TRUE(iter1.GetSkippedOffset() == 0) <<
"[3] Check initial skipped offset";
uint32_t expectSkipped1[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
18, 19, 20, 21, 22, 23, 24, 25, 26, 27 };
for (uint32_t i = 0; i < mozilla::ArrayLength(expectSkipped1); i++) {
EXPECT_TRUE(iter1.ConvertOriginalToSkipped(i) == expectSkipped1[i]) <<
"[4] Check mapping of original to skipped for " << i;
}
uint32_t expectOriginal1[] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8,
10, 11, 12, 13, 14, 15, 16, 17, 18,
20, 21, 22, 23, 24, 25, 26, 27, 28 };
for (uint32_t i = 0; i < mozilla::ArrayLength(expectOriginal1); i++) {
EXPECT_TRUE(iter1.ConvertSkippedToOriginal(i) == expectOriginal1[i]) <<
"[5] Check mapping of skipped to original for " << i;
}
// Test a gfxSkipChars that starts with skipped chars
gfxSkipChars skipChars2;
skipChars2.SkipChars(9);
skipChars2.KeepChar();
skipChars2.SkipChars(9);
skipChars2.KeepChar();
skipChars2.SkipChars(9);
EXPECT_TRUE(skipChars2.GetOriginalCharCount() == 29) <<
"[6] Check length";
gfxSkipCharsIterator iter2(skipChars2);
EXPECT_TRUE(iter2.GetOriginalOffset() == 0) <<
"[7] Check initial original offset";
EXPECT_TRUE(iter2.GetSkippedOffset() == 0) <<
"[8] Check initial skipped offset";
uint32_t expectSkipped2[] =
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
for (uint32_t i = 0; i < mozilla::ArrayLength(expectSkipped2); i++) {
EXPECT_TRUE(iter2.ConvertOriginalToSkipped(i) == expectSkipped2[i]) <<
"[9] Check mapping of original to skipped for " << i;
}
uint32_t expectOriginal2[] = { 9, 19, 29 };
for (uint32_t i = 0; i < mozilla::ArrayLength(expectOriginal2); i++) {
EXPECT_TRUE(iter2.ConvertSkippedToOriginal(i) == expectOriginal2[i]) <<
"[10] Check mapping of skipped to original for " << i;
}
return true;
}
TEST(Gfx, gfxSkipChars) {
TestConstructor();
TestLength();
TestIterator();
}

View File

@ -15,6 +15,7 @@ UNIFIED_SOURCES += [
'TestColorNames.cpp',
'TestLayers.cpp',
'TestRegion.cpp',
'TestSkipChars.cpp',
# Hangs on linux in ApplyGdkScreenFontOptions
#'gfxFontSelectionTest.cpp',
'TestTextures.cpp',

View File

@ -179,8 +179,11 @@ gfxPattern::GetPattern(DrawTarget *aTarget, Matrix *aPatternTransform)
}
if (!mPattern) {
Matrix adjustedMatrix = mTransform;
if (aPatternTransform)
AdjustTransformForPattern(adjustedMatrix, aTarget->GetTransform(), aPatternTransform);
mGfxPattern = new (mSurfacePattern.addr())
SurfacePattern(mSourceSurface, ToExtendMode(mExtend), mTransform, mFilter);
SurfacePattern(mSourceSurface, ToExtendMode(mExtend), adjustedMatrix, mFilter);
return mGfxPattern;
}

View File

@ -5,227 +5,136 @@
#include "gfxSkipChars.h"
#include <stdlib.h>
#include <algorithm>
#define SHORTCUT_FREQUENCY 256
// Even numbered list entries are "keep" entries
static bool
IsKeepEntry(uint32_t aEntry)
{
return !(aEntry & 1);
}
void
gfxSkipChars::BuildShortcuts()
gfxSkipCharsIterator::SetOriginalOffset(int32_t aOffset)
{
if (!mList || mCharCount < SHORTCUT_FREQUENCY)
return;
mShortcuts = new Shortcut[mCharCount/SHORTCUT_FREQUENCY];
if (!mShortcuts)
return;
uint32_t i;
uint32_t nextShortcutIndex = 0;
uint32_t originalCharOffset = 0;
uint32_t skippedCharOffset = 0;
for (i = 0; i < mListLength; ++i) {
uint8_t len = mList[i];
// We use >= here to ensure that when mCharCount is a multiple of
// SHORTCUT_FREQUENCY, we fill in the final shortcut with a reference
// to the last element of mList. This means that in general when a list
// element ends on an offset that's a multiple of SHORTCUT_FREQUENCY,
// that list element is the shortcut for that offset, which is
// slightly suboptimal (the *next* element is the one we really want),
// but it's all correct and simpler this way.
while (originalCharOffset + len >= (nextShortcutIndex + 1)*SHORTCUT_FREQUENCY) {
mShortcuts[nextShortcutIndex] =
Shortcut(i, originalCharOffset, skippedCharOffset);
++nextShortcutIndex;
}
originalCharOffset += len;
if (IsKeepEntry(i)) {
skippedCharOffset += len;
}
}
}
void
gfxSkipCharsIterator::SetOffsets(uint32_t aOffset, bool aInOriginalString)
{
NS_ASSERTION(aOffset <= mSkipChars->mCharCount,
aOffset += mOriginalStringToSkipCharsOffset;
NS_ASSERTION(uint32_t(aOffset) <= mSkipChars->mCharCount,
"Invalid offset");
if (mSkipChars->mListLength == 0) {
mOriginalStringOffset = mSkippedStringOffset = aOffset;
mOriginalStringOffset = aOffset;
uint32_t rangeCount = mSkipChars->mRanges.Length();
if (rangeCount == 0) {
mSkippedStringOffset = aOffset;
return;
}
// at start of string?
if (aOffset == 0) {
// Start from the beginning of the string.
mSkippedStringOffset = 0;
mOriginalStringOffset = 0;
mListPrefixLength = 0;
mListPrefixKeepCharCount = 0;
mListPrefixCharCount = 0;
if (aInOriginalString) {
// Nothing more to do!
mCurrentRangeIndex =
rangeCount && mSkipChars->mRanges[0].Start() == 0 ? 0 : -1;
return;
}
// find the range that includes or precedes aOffset
uint32_t lo = 0, hi = rangeCount;
const gfxSkipChars::SkippedRange* ranges = mSkipChars->mRanges.Elements();
while (lo < hi) {
uint32_t mid = (lo + hi) / 2;
if (uint32_t(aOffset) < ranges[mid].Start()) {
hi = mid;
} else {
lo = mid + 1;
}
}
if (lo == rangeCount) {
mCurrentRangeIndex = rangeCount - 1;
} else if (uint32_t(aOffset) < ranges[lo].Start()) {
mCurrentRangeIndex = lo - 1;
if (mCurrentRangeIndex == -1) {
mSkippedStringOffset = aOffset;
return;
}
} else {
mCurrentRangeIndex = lo;
}
if (aInOriginalString && mSkipChars->mShortcuts &&
abs(int32_t(aOffset) - int32_t(mListPrefixCharCount)) > SHORTCUT_FREQUENCY) {
// Take a shortcut. This makes SetOffsets(..., true) O(1) by bounding
// the iterations in the loop below to at most SHORTCUT_FREQUENCY iterations
uint32_t shortcutIndex = aOffset/SHORTCUT_FREQUENCY;
if (shortcutIndex == 0) {
mListPrefixLength = 0;
mListPrefixKeepCharCount = 0;
mListPrefixCharCount = 0;
const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex];
if (uint32_t(aOffset) < r.End()) {
mSkippedStringOffset = r.SkippedOffset();
return;
}
mSkippedStringOffset = aOffset - r.NextDelta();
}
void
gfxSkipCharsIterator::SetSkippedOffset(uint32_t aOffset)
{
NS_ASSERTION((mSkipChars->mRanges.IsEmpty() &&
aOffset <= mSkipChars->mCharCount) ||
(aOffset <= mSkipChars->LastRange().SkippedOffset() +
mSkipChars->mCharCount -
mSkipChars->LastRange().End()),
"Invalid skipped offset");
mSkippedStringOffset = aOffset;
uint32_t rangeCount = mSkipChars->mRanges.Length();
if (rangeCount == 0) {
mOriginalStringOffset = aOffset;
return;
}
uint32_t lo = 0, hi = rangeCount;
const gfxSkipChars::SkippedRange* ranges = mSkipChars->mRanges.Elements();
while (lo < hi) {
uint32_t mid = (lo + hi) / 2;
if (aOffset < ranges[mid].SkippedOffset()) {
hi = mid;
} else {
const gfxSkipChars::Shortcut& shortcut = mSkipChars->mShortcuts[shortcutIndex - 1];
mListPrefixLength = shortcut.mListPrefixLength;
mListPrefixKeepCharCount = shortcut.mListPrefixKeepCharCount;
mListPrefixCharCount = shortcut.mListPrefixCharCount;
lo = mid + 1;
}
}
int32_t currentRunLength = mSkipChars->mList[mListPrefixLength];
for (;;) {
// See if aOffset is in the string segment described by
// mSkipChars->mList[mListPrefixLength]
uint32_t segmentOffset = aInOriginalString ? mListPrefixCharCount : mListPrefixKeepCharCount;
if ((aInOriginalString || IsKeepEntry(mListPrefixLength)) &&
aOffset >= segmentOffset && aOffset < segmentOffset + currentRunLength) {
int32_t offsetInSegment = aOffset - segmentOffset;
mOriginalStringOffset = mListPrefixCharCount + offsetInSegment;
mSkippedStringOffset = mListPrefixKeepCharCount;
if (IsKeepEntry(mListPrefixLength)) {
mSkippedStringOffset += offsetInSegment;
}
if (lo == rangeCount) {
mCurrentRangeIndex = rangeCount - 1;
} else if (aOffset < ranges[lo].SkippedOffset()) {
mCurrentRangeIndex = lo - 1;
if (mCurrentRangeIndex == -1) {
mOriginalStringOffset = aOffset;
return;
}
if (aOffset < segmentOffset) {
// We need to move backwards
if (mListPrefixLength <= 0) {
// nowhere to go backwards
mOriginalStringOffset = mSkippedStringOffset = 0;
return;
}
// Go backwards one segment and restore invariants
--mListPrefixLength;
currentRunLength = mSkipChars->mList[mListPrefixLength];
mListPrefixCharCount -= currentRunLength;
if (IsKeepEntry(mListPrefixLength)) {
mListPrefixKeepCharCount -= currentRunLength;
}
} else {
// We need to move forwards
if (mListPrefixLength >= mSkipChars->mListLength - 1) {
// nowhere to go forwards
mOriginalStringOffset = mListPrefixCharCount + currentRunLength;
mSkippedStringOffset = mListPrefixKeepCharCount;
if (IsKeepEntry(mListPrefixLength)) {
mSkippedStringOffset += currentRunLength;
}
return;
}
// Go forwards one segment and restore invariants
mListPrefixCharCount += currentRunLength;
if (IsKeepEntry(mListPrefixLength)) {
mListPrefixKeepCharCount += currentRunLength;
}
++mListPrefixLength;
currentRunLength = mSkipChars->mList[mListPrefixLength];
}
} else {
mCurrentRangeIndex = lo;
}
const gfxSkipChars::SkippedRange& r = ranges[mCurrentRangeIndex];
mOriginalStringOffset = r.End() + aOffset - r.SkippedOffset();
}
bool
gfxSkipCharsIterator::IsOriginalCharSkipped(int32_t* aRunLength) const
{
if (mSkipChars->mListLength == 0) {
if (mCurrentRangeIndex == -1) {
// we're before the first skipped range (if any)
if (aRunLength) {
*aRunLength = mSkipChars->mCharCount - mOriginalStringOffset;
uint32_t end = mSkipChars->mRanges.IsEmpty() ?
mSkipChars->mCharCount : mSkipChars->mRanges[0].Start();
*aRunLength = end - mOriginalStringOffset;
}
return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset);
}
uint32_t listPrefixLength = mListPrefixLength;
// figure out which segment we're in
uint32_t currentRunLength = mSkipChars->mList[listPrefixLength];
// Zero-length list entries are possible. Advance until mListPrefixLength
// is pointing to a run with real characters (or we're at the end of the
// string).
while (currentRunLength == 0 && listPrefixLength < mSkipChars->mListLength - 1) {
++listPrefixLength;
// This does not break the iterator's invariant because no skipped
// or kept characters are being added
currentRunLength = mSkipChars->mList[listPrefixLength];
}
NS_ASSERTION(uint32_t(mOriginalStringOffset) >= mListPrefixCharCount,
"Invariant violation");
uint32_t offsetIntoCurrentRun =
uint32_t(mOriginalStringOffset) - mListPrefixCharCount;
if (listPrefixLength >= mSkipChars->mListLength - 1 &&
offsetIntoCurrentRun >= currentRunLength) {
NS_ASSERTION(listPrefixLength == mSkipChars->mListLength - 1 &&
offsetIntoCurrentRun == currentRunLength,
"Overran end of string");
// We're at the end of the string
const gfxSkipChars::SkippedRange& range =
mSkipChars->mRanges[mCurrentRangeIndex];
if (uint32_t(mOriginalStringOffset) < range.End()) {
if (aRunLength) {
*aRunLength = 0;
*aRunLength = range.End() - mOriginalStringOffset;
}
return true;
}
bool isSkipped = !IsKeepEntry(listPrefixLength);
if (aRunLength) {
// Long runs of all-skipped or all-kept characters will be encoded as
// sequences of 255, 0, 255, 0 etc. Compute the maximum run length by skipping
// over zero entries.
uint32_t runLength = currentRunLength - offsetIntoCurrentRun;
for (uint32_t i = listPrefixLength + 2; i < mSkipChars->mListLength; i += 2) {
if (mSkipChars->mList[i - 1] != 0)
break;
runLength += mSkipChars->mList[i];
}
*aRunLength = runLength;
}
return isSkipped;
}
void
gfxSkipCharsBuilder::FlushRun()
{
NS_ASSERTION((mBuffer.Length() & 1) == mRunSkipped,
"out of sync?");
// Fill in buffer entries starting at mBufferLength, as many as necessary
uint32_t charCount = mRunCharCount;
for (;;) {
uint32_t chars = std::min<uint32_t>(255, charCount);
if (!mBuffer.AppendElement(chars)) {
mInErrorState = true;
return;
}
charCount -= chars;
if (charCount == 0)
break;
if (!mBuffer.AppendElement(0)) {
mInErrorState = true;
return;
}
if (aRunLength) {
uint32_t end =
uint32_t(mCurrentRangeIndex) + 1 < mSkipChars->mRanges.Length() ?
mSkipChars->mRanges[mCurrentRangeIndex + 1].Start() :
mSkipChars->mCharCount;
*aRunLength = end - mOriginalStringOffset;
}
NS_ASSERTION(mCharCount + mRunCharCount >= mCharCount,
"String length overflow");
mCharCount += mRunCharCount;
mRunCharCount = 0;
mRunSkipped = !mRunSkipped;
return mSkipChars->mCharCount == uint32_t(mOriginalStringOffset);
}

View File

@ -6,7 +6,6 @@
#ifndef GFX_SKIP_CHARS_H
#define GFX_SKIP_CHARS_H
#include "nsAutoPtr.h"
#include "nsTArray.h"
/*
@ -20,146 +19,126 @@
*/
/**
* gfxSkipCharsBuilder is a helper class that accumulates a list of (skip, keep)
* commands and can eventually be used to construct a real gfxSkipChars.
* gfxSkipCharsBuilder objects are quite large so don't keep these around.
* On the positive side, the Skip/KeepChar(s) methods are very efficient,
* especially when you have runs of all-kept or all-skipped characters.
*
* mBuffer is an array of bytes; even numbered bytes represent characters kept,
* odd numbered bytes represent characters skipped. After those characters
* are accounted for, we have mRunCharCount characters which are kept or
* skipped depending on the value of mRunSkipped.
*
* mCharCount is the sum of counts of all skipped and kept characters, i.e.,
* the length of the original string.
*/
class gfxSkipCharsBuilder {
public:
gfxSkipCharsBuilder() :
mCharCount(0), mRunCharCount(0), mRunSkipped(false), mInErrorState(false)
{}
void SkipChars(uint32_t aChars) {
DoChars(aChars, true);
}
void KeepChars(uint32_t aChars) {
DoChars(aChars, false);
}
void SkipChar() {
SkipChars(1);
}
void KeepChar() {
KeepChars(1);
}
void DoChars(uint32_t aChars, bool aSkipped) {
if (aSkipped != mRunSkipped && aChars > 0) {
FlushRun();
}
NS_ASSERTION(mRunCharCount + aChars > mRunCharCount,
"Character count overflow");
mRunCharCount += aChars;
}
bool IsOK() { return !mInErrorState; }
uint32_t GetCharCount() { return mCharCount + mRunCharCount; }
bool GetAllCharsKept() { return mBuffer.Length() == 0; }
friend class gfxSkipChars;
private:
typedef AutoFallibleTArray<uint8_t,256> Buffer;
/**
* Moves mRunCharCount/mRunSkipped to the buffer (updating mCharCount),
* sets mRunCharCount to zero and toggles mRunSkipped.
*/
void FlushRun();
Buffer mBuffer;
uint32_t mCharCount;
uint32_t mRunCharCount;
bool mRunSkipped; // == mBuffer.Length()&1
bool mInErrorState;
};
/**
* The gfxSkipChars list is represented as a list of bytes of the form
* [chars to keep, chars to skip, chars to keep, chars to skip, ...]
* In the special case where all chars are to be kept, the list is length
* zero.
*
* The gfxSkipChars is represented as a sorted array of skipped ranges.
*
* A freshly-created gfxSkipChars means "all chars kept".
*/
class gfxSkipChars {
class gfxSkipChars
{
private:
class SkippedRange
{
public:
SkippedRange(uint32_t aOffset, uint32_t aLength, uint32_t aDelta)
: mOffset(aOffset), mLength(aLength), mDelta(aDelta)
{ }
uint32_t Start() const
{
return mOffset;
}
uint32_t End() const
{
return mOffset + mLength;
}
uint32_t Length() const
{
return mLength;
}
uint32_t SkippedOffset() const
{
return mOffset - mDelta;
}
uint32_t Delta() const
{
return mDelta;
}
uint32_t NextDelta() const
{
return mDelta + mLength;
}
void Extend(uint32_t aChars)
{
mLength += aChars;
}
private:
uint32_t mOffset; // original-string offset at which we want to skip
uint32_t mLength; // number of skipped chars at this offset
uint32_t mDelta; // sum of lengths of preceding skipped-ranges
};
public:
gfxSkipChars() : mListLength(0), mCharCount(0) {}
void TakeFrom(gfxSkipChars* aSkipChars) {
mList = aSkipChars->mList.forget();
mListLength = aSkipChars->mListLength;
gfxSkipChars()
: mCharCount(0)
{ }
void SkipChars(uint32_t aChars)
{
NS_ASSERTION(mCharCount + aChars > mCharCount,
"Character count overflow");
uint32_t rangeCount = mRanges.Length();
uint32_t delta = 0;
if (rangeCount > 0) {
SkippedRange& lastRange = mRanges[rangeCount - 1];
if (lastRange.End() == mCharCount) {
lastRange.Extend(aChars);
mCharCount += aChars;
return;
}
delta = lastRange.NextDelta();
}
mRanges.AppendElement(SkippedRange(mCharCount, aChars, delta));
mCharCount += aChars;
}
void KeepChars(uint32_t aChars)
{
NS_ASSERTION(mCharCount + aChars > mCharCount,
"Character count overflow");
mCharCount += aChars;
}
void SkipChar()
{
SkipChars(1);
}
void KeepChar()
{
KeepChars(1);
}
void TakeFrom(gfxSkipChars* aSkipChars)
{
mRanges.SwapElements(aSkipChars->mRanges);
mCharCount = aSkipChars->mCharCount;
aSkipChars->mCharCount = 0;
aSkipChars->mListLength = 0;
BuildShortcuts();
}
void TakeFrom(gfxSkipCharsBuilder* aSkipCharsBuilder) {
if (!aSkipCharsBuilder->mBuffer.Length()) {
NS_ASSERTION(!aSkipCharsBuilder->mRunSkipped, "out of sync");
// all characters kept
mCharCount = aSkipCharsBuilder->mRunCharCount;
mList = nullptr;
mListLength = 0;
} else {
aSkipCharsBuilder->FlushRun();
mCharCount = aSkipCharsBuilder->mCharCount;
mList = new uint8_t[aSkipCharsBuilder->mBuffer.Length()];
if (!mList) {
mListLength = 0;
} else {
mListLength = aSkipCharsBuilder->mBuffer.Length();
memcpy(mList, aSkipCharsBuilder->mBuffer.Elements(), mListLength);
}
}
aSkipCharsBuilder->mBuffer.Clear();
aSkipCharsBuilder->mCharCount = 0;
aSkipCharsBuilder->mRunCharCount = 0;
aSkipCharsBuilder->mRunSkipped = false;
BuildShortcuts();
int32_t GetOriginalCharCount() const
{
return mCharCount;
}
void SetAllKeep(uint32_t aLength) {
mCharCount = aLength;
mList = nullptr;
mListLength = 0;
const SkippedRange& LastRange() const
{
// this is only valid if mRanges is non-empty; no assertion here
// because nsTArray will already assert if we abuse it
return mRanges[mRanges.Length() - 1];
}
int32_t GetOriginalCharCount() const { return mCharCount; }
friend class gfxSkipCharsIterator;
private:
struct Shortcut {
uint32_t mListPrefixLength;
uint32_t mListPrefixCharCount;
uint32_t mListPrefixKeepCharCount;
Shortcut() {}
Shortcut(uint32_t aListPrefixLength, uint32_t aListPrefixCharCount,
uint32_t aListPrefixKeepCharCount) :
mListPrefixLength(aListPrefixLength),
mListPrefixCharCount(aListPrefixCharCount),
mListPrefixKeepCharCount(aListPrefixKeepCharCount) {}
};
void BuildShortcuts();
nsAutoArrayPtr<uint8_t> mList;
nsAutoArrayPtr<Shortcut> mShortcuts;
uint32_t mListLength;
uint32_t mCharCount;
nsTArray<SkippedRange> mRanges;
uint32_t mCharCount;
};
/**
@ -169,17 +148,18 @@ private:
* incoming original string offsets and subtracted from all outgoing original
* string offsets --- useful when the gfxSkipChars corresponds to something
* offset from the original DOM coordinates, which it often does for gfxTextRuns.
*
*
* The current positions (in both the original and skipped strings) are
* always constrained to be >= 0 and <= the string length. When the position
* is equal to the string length, it is at the end of the string. The current
* positions do not include any aOriginalStringToSkipCharsOffset.
*
*
* When the position in the original string corresponds to a skipped character,
* the skipped-characters offset is the offset of the next unskipped character,
* or the skipped-characters string length if there is no next unskipped character.
*/
class gfxSkipCharsIterator {
class gfxSkipCharsIterator
{
public:
/**
* @param aOriginalStringToSkipCharsOffset add this to all incoming and
@ -189,66 +169,72 @@ public:
int32_t aOriginalStringToSkipCharsOffset,
int32_t aOriginalStringOffset)
: mSkipChars(&aSkipChars),
mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset),
mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) {
mOriginalStringOffset(0),
mSkippedStringOffset(0),
mCurrentRangeIndex(-1),
mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
{
SetOriginalOffset(aOriginalStringOffset);
}
gfxSkipCharsIterator(const gfxSkipChars& aSkipChars,
int32_t aOriginalStringToSkipCharsOffset = 0)
: mSkipChars(&aSkipChars),
mOriginalStringOffset(0), mSkippedStringOffset(0),
mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset),
mListPrefixLength(0), mListPrefixCharCount(0), mListPrefixKeepCharCount(0) {
}
mOriginalStringOffset(0),
mSkippedStringOffset(0),
mCurrentRangeIndex(-1),
mOriginalStringToSkipCharsOffset(aOriginalStringToSkipCharsOffset)
{ }
gfxSkipCharsIterator(const gfxSkipCharsIterator& aIterator)
: mSkipChars(aIterator.mSkipChars),
mOriginalStringOffset(aIterator.mOriginalStringOffset),
mSkippedStringOffset(aIterator.mSkippedStringOffset),
mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset),
mListPrefixLength(aIterator.mListPrefixLength),
mListPrefixCharCount(aIterator.mListPrefixCharCount),
mListPrefixKeepCharCount(aIterator.mListPrefixKeepCharCount)
{}
mCurrentRangeIndex(aIterator.mCurrentRangeIndex),
mOriginalStringToSkipCharsOffset(aIterator.mOriginalStringToSkipCharsOffset)
{ }
/**
* The empty constructor creates an object that is useless until it is assigned.
*/
gfxSkipCharsIterator() : mSkipChars(nullptr) {}
gfxSkipCharsIterator()
: mSkipChars(nullptr)
{ }
/**
* Return true if this iterator is properly initialized and usable.
*/
bool IsInitialized() { return mSkipChars != nullptr; }
*/
bool IsInitialized()
{
return mSkipChars != nullptr;
}
/**
* Set the iterator to aOriginalStringOffset in the original string.
* This can efficiently move forward or backward from the current position.
* aOriginalStringOffset is clamped to [0,originalStringLength].
*/
void SetOriginalOffset(int32_t aOriginalStringOffset) {
SetOffsets(aOriginalStringOffset + mOriginalStringToSkipCharsOffset, true);
}
void SetOriginalOffset(int32_t aOriginalStringOffset);
/**
* Set the iterator to aSkippedStringOffset in the skipped string.
* This can efficiently move forward or backward from the current position.
* aSkippedStringOffset is clamped to [0,skippedStringLength].
*/
void SetSkippedOffset(uint32_t aSkippedStringOffset) {
SetOffsets(aSkippedStringOffset, false);
}
uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset) {
void SetSkippedOffset(uint32_t aSkippedStringOffset);
uint32_t ConvertOriginalToSkipped(int32_t aOriginalStringOffset)
{
SetOriginalOffset(aOriginalStringOffset);
return GetSkippedOffset();
}
uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset) {
uint32_t ConvertSkippedToOriginal(int32_t aSkippedStringOffset)
{
SetSkippedOffset(aSkippedStringOffset);
return GetOriginalOffset();
}
/**
* Test if the character at the current position in the original string
* is skipped or not. If aRunLength is non-null, then *aRunLength is set
@ -257,20 +243,25 @@ public:
* string, we return true and *aRunLength is set to zero.
*/
bool IsOriginalCharSkipped(int32_t* aRunLength = nullptr) const;
void AdvanceOriginal(int32_t aDelta) {
SetOffsets(mOriginalStringOffset + aDelta, true);
void AdvanceOriginal(int32_t aDelta)
{
SetOriginalOffset(GetOriginalOffset() + aDelta);
}
void AdvanceSkipped(int32_t aDelta) {
SetOffsets(mSkippedStringOffset + aDelta, false);
void AdvanceSkipped(int32_t aDelta)
{
SetSkippedOffset(GetSkippedOffset() + aDelta);
}
/**
* @return the offset within the original string
*/
int32_t GetOriginalOffset() const {
int32_t GetOriginalOffset() const
{
return mOriginalStringOffset - mOriginalStringToSkipCharsOffset;
}
/**
* @return the offset within the skipped string corresponding to the
* current position in the original string. If the current position
@ -279,38 +270,33 @@ public:
* original string after the current position, or the length of the skipped
* string if there is no such character.
*/
uint32_t GetSkippedOffset() const { return mSkippedStringOffset; }
uint32_t GetSkippedOffset() const
{
return mSkippedStringOffset;
}
int32_t GetOriginalEnd() const {
int32_t GetOriginalEnd() const
{
return mSkipChars->GetOriginalCharCount() -
mOriginalStringToSkipCharsOffset;
}
private:
void SetOffsets(uint32_t aOffset, bool aInOriginalString);
const gfxSkipChars* mSkipChars;
// Current position
int32_t mOriginalStringOffset;
uint32_t mSkippedStringOffset;
// Index of the last skippedRange that precedes or contains the current
// position in the original string.
// If index == -1 then we are before the first skipped char.
int32_t mCurrentRangeIndex;
// This offset is added to map from "skipped+unskipped characters in
// the original DOM string" character space to "skipped+unskipped
// characters in the textrun's gfxSkipChars" character space
int32_t mOriginalStringToSkipCharsOffset;
/*
* This is used to speed up cursor-style traversal. The invariant is that
* the first mListPrefixLength bytes of mSkipChars.mList sum to
* mListPrefixCharCount, and the even-indexed bytes in that prefix sum to
* mListPrefixKeepCharCount.
* Also, 0 <= mListPrefixLength < mSkipChars.mListLength, or else
* mSkipChars.mListLength is zero.
* Also, mListPrefixCharCount <= mOriginalStringOffset (and therefore
* mListPrefixKeepCharCount < mSkippedStringOffset).
*/
uint32_t mListPrefixLength;
uint32_t mListPrefixCharCount;
uint32_t mListPrefixKeepCharCount;
};
#endif /*GFX_SKIP_CHARS_H*/

View File

@ -1,14 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef ubase_h__
#define ubase_h__
#include "prtypes.h"
#include <stdint.h>
#define PRIVATE
#define MODULE_PRIVATE
#endif

View File

@ -6,166 +6,166 @@
/*=================================================================================
=================================================================================*/
typedef PRBool (*uSubGeneratorFunc) (uint16_t in, unsigned char* out);
typedef int (*uSubGeneratorFunc) (uint16_t in, unsigned char* out);
/*=================================================================================
=================================================================================*/
typedef PRBool (*uGeneratorFunc) (
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
typedef int (*uGeneratorFunc) (
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
MODULE_PRIVATE PRBool uGenerate(
uScanClassID scanClass,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uGenerate(
uScanClassID scanClass,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
#define uSubGenerator(sub,in,out) (* m_subgenerator[sub])((in),(out))
PRIVATE PRBool uCheckAndGenAlways1Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGenAlways2Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGenAlways2ByteShiftGR(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
MODULE_PRIVATE PRBool uGenerateShift(
uShiftOutTable *shift,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
int uCheckAndGenAlways1Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGenAlways2Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGenAlways2ByteShiftGR(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uGenerateShift(
uShiftOutTable *shift,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8F(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8EA2(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8EA3(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8EA4(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8EA5(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8EA6(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen2ByteGRPrefix8EA7(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCnGAlways8BytesDecomposedHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8F(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA2(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA3(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGenJohabHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA4(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA5(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA6(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA7(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCnGAlways8BytesDecomposedHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGenJohabHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGenJohabSymbol(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGenJohabSymbol(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
PRIVATE PRBool uCheckAndGen4BytesGB18030(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uCheckAndGen4BytesGB18030(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
);
int uGenAlways2Byte(
uint16_t in,
unsigned char* out
);
int uGenAlways2ByteShiftGR(
uint16_t in,
unsigned char* out
);
int uGenAlways1Byte(
uint16_t in,
unsigned char* out
);
int uGenAlways1BytePrefix8E(
uint16_t in,
unsigned char* out
);
/*=================================================================================
PRIVATE PRBool uGenAlways2Byte(
uint16_t in,
unsigned char* out
);
PRIVATE PRBool uGenAlways2ByteShiftGR(
uint16_t in,
unsigned char* out
);
PRIVATE PRBool uGenAlways1Byte(
uint16_t in,
unsigned char* out
);
PRIVATE PRBool uGenAlways1BytePrefix8E(
uint16_t in,
unsigned char* out
);
/*=================================================================================
=================================================================================*/
PRIVATE const uGeneratorFunc m_generator[uNumOfCharsetType] =
const uGeneratorFunc m_generator[uNumOfCharsetType] =
{
uCheckAndGenAlways1Byte,
uCheckAndGenAlways2Byte,
@ -188,152 +188,151 @@ PRIVATE const uGeneratorFunc m_generator[uNumOfCharsetType] =
=================================================================================*/
PRIVATE const uSubGeneratorFunc m_subgenerator[uNumOfCharType] =
const uSubGeneratorFunc m_subgenerator[uNumOfCharType] =
{
uGenAlways1Byte,
uGenAlways2Byte,
uGenAlways2ByteShiftGR,
uGenAlways1BytePrefix8E
};
/*=================================================================================
=================================================================================*/
MODULE_PRIVATE PRBool uGenerate(
uScanClassID scanClass,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uGenerate(
uScanClassID scanClass,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
return (* m_generator[scanClass]) (state,in,out,outbuflen,outlen);
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uGenAlways1Byte(
uint16_t in,
unsigned char* out
)
int uGenAlways1Byte(
uint16_t in,
unsigned char* out
)
{
out[0] = (unsigned char)in;
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uGenAlways2Byte(
uint16_t in,
unsigned char* out
)
int uGenAlways2Byte(
uint16_t in,
unsigned char* out
)
{
out[0] = (unsigned char)((in >> 8) & 0xff);
out[1] = (unsigned char)(in & 0xff);
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uGenAlways2ByteShiftGR(
uint16_t in,
unsigned char* out
)
int uGenAlways2ByteShiftGR(
uint16_t in,
unsigned char* out
)
{
out[0] = (unsigned char)(((in >> 8) & 0xff) | 0x80);
out[1] = (unsigned char)((in & 0xff) | 0x80);
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uGenAlways1BytePrefix8E(
uint16_t in,
unsigned char* out
)
int uGenAlways1BytePrefix8E(
uint16_t in,
unsigned char* out
)
{
out[0] = 0x8E;
out[1] = (unsigned char)(in & 0xff);
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGenAlways1Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGenAlways1Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
/* Don't check inlen. The caller should ensure it is larger than 0 */
/* Oops, I don't agree. Code changed to check every time. [CATA] */
if(outbuflen < 1)
return PR_FALSE;
return 0;
else
{
*outlen = 1;
out[0] = in & 0xff;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGenAlways2Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGenAlways2Byte(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 2)
return PR_FALSE;
return 0;
else
{
*outlen = 2;
out[0] = ((in >> 8 ) & 0xff);
out[1] = in & 0xff;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGenAlways2ByteShiftGR(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGenAlways2ByteShiftGR(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 2)
return PR_FALSE;
return 0;
else
{
*outlen = 2;
out[0] = ((in >> 8 ) & 0xff) | 0x80;
out[1] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
MODULE_PRIVATE PRBool uGenerateShift(
uShiftOutTable *shift,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uGenerateShift(
uShiftOutTable *shift,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
int16_t i;
const uShiftOutCell* cell = &(shift->shiftcell[0]);
@ -350,7 +349,7 @@ MODULE_PRIVATE PRBool uGenerateShift(
{
if(outbuflen < cell[i].reserveLen)
{
return PR_FALSE;
return 0;
}
else
{
@ -359,41 +358,41 @@ MODULE_PRIVATE PRBool uGenerateShift(
}
}
}
return PR_FALSE;
return 0;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8F( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8F(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 3)
return PR_FALSE;
return 0;
else
{
*outlen = 3;
out[0] = 0x8F;
out[1] = ((in >> 8 ) & 0xff) | 0x80;
out[2] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA2( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8EA2(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
else
{
*outlen = 4;
@ -401,7 +400,7 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA2( int32_t* state,
out[1] = 0xA2;
out[2] = ((in >> 8 ) & 0xff) | 0x80;
out[3] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
@ -409,15 +408,15 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA2( int32_t* state,
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA3( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8EA3(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
else
{
*outlen = 4;
@ -425,21 +424,21 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA3( int32_t* state,
out[1] = 0xA3;
out[2] = ((in >> 8 ) & 0xff) | 0x80;
out[3] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA4( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8EA4(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
else
{
*outlen = 4;
@ -447,21 +446,21 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA4( int32_t* state,
out[1] = 0xA4;
out[2] = ((in >> 8 ) & 0xff) | 0x80;
out[3] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA5( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8EA5(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
else
{
*outlen = 4;
@ -469,21 +468,21 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA5( int32_t* state,
out[1] = 0xA5;
out[2] = ((in >> 8 ) & 0xff) | 0x80;
out[3] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA6( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8EA6(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
else
{
*outlen = 4;
@ -491,21 +490,21 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA6( int32_t* state,
out[1] = 0xA6;
out[2] = ((in >> 8 ) & 0xff) | 0x80;
out[3] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA7( int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen2ByteGRPrefix8EA7(int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
else
{
*outlen = 4;
@ -513,7 +512,7 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA7( int32_t* state,
out[1] = 0xA7;
out[2] = ((in >> 8 ) & 0xff) | 0x80;
out[3] = (in & 0xff) | 0x80;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
@ -527,13 +526,13 @@ PRIVATE PRBool uCheckAndGen2ByteGRPrefix8EA7( int32_t* state,
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCnGAlways8BytesDecomposedHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCnGAlways8BytesDecomposedHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
static const uint8_t lMap[LCount] = {
0xa1, 0xa2, 0xa4, 0xa7, 0xa8, 0xa9, 0xb1, 0xb2, 0xb3, 0xb5,
@ -549,7 +548,7 @@ PRIVATE PRBool uCnGAlways8BytesDecomposedHangul(
uint16_t SIndex, LIndex, VIndex, TIndex;
if(outbuflen < 8)
return PR_FALSE;
return 0;
/* the following line are copy from Unicode 2.0 page 3-13 */
/* item 1 of Hangul Syllabel Decomposition */
@ -575,19 +574,19 @@ PRIVATE PRBool uCnGAlways8BytesDecomposedHangul(
out[5] = (VIndex + 0xbf);
out[7] = tMap[TIndex];
return PR_TRUE;
return 1;
}
PRIVATE PRBool uCheckAndGenJohabHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGenJohabHangul(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 2)
return PR_FALSE;
return 0;
else
{
/*
@ -633,19 +632,19 @@ PRIVATE PRBool uCheckAndGenJohabHangul(
#if 0
printf("Johab Hangul %x %x in=%x L=%d V=%d T=%d\n", out[0], out[1], in, LIndex, VIndex, TIndex);
#endif
return PR_TRUE;
return 1;
}
}
PRIVATE PRBool uCheckAndGenJohabSymbol(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGenJohabSymbol(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 2)
return PR_FALSE;
return 0;
else
{
/* The following code are based on the Perl code listed under
@ -689,19 +688,19 @@ PRIVATE PRBool uCheckAndGenJohabSymbol(
#if 0
printf("Johab Symbol %x %x in=%x\n", out[0], out[1], in);
#endif
return PR_TRUE;
return 1;
}
}
PRIVATE PRBool uCheckAndGen4BytesGB18030(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
int uCheckAndGen4BytesGB18030(
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen
)
{
if(outbuflen < 4)
return PR_FALSE;
return 0;
out[0] = (in / (10*126*10)) + 0x81;
in %= (10*126*10);
out[1] = (in / (10*126)) + 0x30;
@ -709,5 +708,5 @@ PRIVATE PRBool uCheckAndGen4BytesGB18030(
out[2] = (in / (10)) + 0x81;
out[3] = (in % 10) + 0x30;
*outlen = 4;
return PR_TRUE;
return 1;
}

View File

@ -7,28 +7,28 @@
typedef uint16_t (* MapFormatFunc)(uint16_t in,const uTable *uT,const uMapCell *cell);
typedef PRBool (* HitFormateFunc)(uint16_t in,const uMapCell *cell);
typedef int (* HitFormateFunc)(uint16_t in,const uMapCell *cell);
typedef void (* FillInfoFormateFunc)(const uTable *uT, const uMapCell *cell, uint32_t* info);
PRIVATE PRBool uHitFormate0(uint16_t in,const uMapCell *cell);
PRIVATE PRBool uHitFormate2(uint16_t in,const uMapCell *cell);
PRIVATE uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell);
PRIVATE uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell);
PRIVATE uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell);
PRIVATE void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
PRIVATE void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
PRIVATE void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
int uHitFormate0(uint16_t in,const uMapCell *cell);
int uHitFormate2(uint16_t in,const uMapCell *cell);
uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell);
uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell);
uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell);
void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* aInfo);
PRIVATE const uMapCell *uGetMapCell(const uTable *uT, int16_t item);
PRIVATE char uGetFormat(const uTable *uT, int16_t item);
const uMapCell *uGetMapCell(const uTable *uT, int16_t item);
char uGetFormat(const uTable *uT, int16_t item);
/*=================================================================================
=================================================================================*/
PRIVATE const MapFormatFunc m_map[uNumFormatTag] =
const MapFormatFunc m_map[uNumFormatTag] =
{
uMapFormate0,
uMapFormate1,
@ -38,7 +38,7 @@ PRIVATE const MapFormatFunc m_map[uNumFormatTag] =
/*=================================================================================
=================================================================================*/
PRIVATE const FillInfoFormateFunc m_fillinfo[uNumFormatTag] =
const FillInfoFormateFunc m_fillinfo[uNumFormatTag] =
{
uFillInfoFormate0,
uFillInfoFormate1,
@ -48,7 +48,7 @@ PRIVATE const FillInfoFormateFunc m_fillinfo[uNumFormatTag] =
/*=================================================================================
=================================================================================*/
PRIVATE const HitFormateFunc m_hit[uNumFormatTag] =
const HitFormateFunc m_hit[uNumFormatTag] =
{
uHitFormate0,
uHitFormate0,
@ -63,9 +63,9 @@ PRIVATE const HitFormateFunc m_hit[uNumFormatTag] =
/*=================================================================================
=================================================================================*/
MODULE_PRIVATE PRBool uMapCode(const uTable *uT, uint16_t in, uint16_t* out)
int uMapCode(const uTable *uT, uint16_t in, uint16_t* out)
{
PRBool done = PR_FALSE;
int done = 0;
uint16_t itemOfList = uT->itemOfList;
uint16_t i;
*out = NOMAPPING;
@ -77,7 +77,7 @@ MODULE_PRIVATE PRBool uMapCode(const uTable *uT, uint16_t in, uint16_t* out)
if(uHit(format, in, uCell))
{
*out = uMap(format, in, uT,uCell);
done = PR_TRUE;
done = 1;
break;
}
}
@ -91,7 +91,7 @@ member function
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uHitFormate0(uint16_t in,const uMapCell *cell)
int uHitFormate0(uint16_t in,const uMapCell *cell)
{
return ( (in >= cell->fmt.format0.srcBegin) &&
(in <= cell->fmt.format0.srcEnd) ) ;
@ -99,21 +99,21 @@ PRIVATE PRBool uHitFormate0(uint16_t in,const uMapCell *cell)
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uHitFormate2(uint16_t in,const uMapCell *cell)
int uHitFormate2(uint16_t in,const uMapCell *cell)
{
return (in == cell->fmt.format2.srcBegin);
}
/*=================================================================================
=================================================================================*/
PRIVATE uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell)
uint16_t uMapFormate0(uint16_t in,const uTable *uT,const uMapCell *cell)
{
return ((in - cell->fmt.format0.srcBegin) + cell->fmt.format0.destBegin);
}
/*=================================================================================
=================================================================================*/
PRIVATE uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell)
uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell)
{
return (*(((uint16_t *)uT) + uT->offsetToMappingTable
+ cell->fmt.format1.mappingOffset + in - cell->fmt.format1.srcBegin));
@ -121,7 +121,7 @@ PRIVATE uint16_t uMapFormate1(uint16_t in,const uTable *uT,const uMapCell *cell)
/*=================================================================================
=================================================================================*/
PRIVATE uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell)
uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell)
{
return (cell->fmt.format2.destBegin);
}
@ -130,7 +130,7 @@ PRIVATE uint16_t uMapFormate2(uint16_t in,const uTable *uT,const uMapCell *cell)
/*=================================================================================
=================================================================================*/
PRIVATE void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* info)
void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* info)
{
uint16_t begin, end, i;
begin = cell->fmt.format0.srcBegin;
@ -152,7 +152,7 @@ PRIVATE void uFillInfoFormate0(const uTable *uT,const uMapCell *cell,uint32_t* i
/*=================================================================================
=================================================================================*/
PRIVATE void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* info)
void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* info)
{
uint16_t begin, end, i;
uint16_t *base;
@ -168,7 +168,7 @@ PRIVATE void uFillInfoFormate1(const uTable *uT,const uMapCell *cell,uint32_t* i
/*=================================================================================
=================================================================================*/
PRIVATE void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* info)
void uFillInfoFormate2(const uTable *uT,const uMapCell *cell,uint32_t* info)
{
SET_REPRESENTABLE(info, cell->fmt.format2.srcBegin);
}

View File

@ -5,7 +5,7 @@
#ifndef __UNIPRIV__
#define __UNIPRIV__
#include "ubase.h"
#include <stdint.h>
#include "umap.h"
#include "uconvutil.h"
@ -13,37 +13,37 @@
extern "C" {
#endif
PRBool uMapCode(const uTable *uT,
uint16_t in,
uint16_t* out);
int uMapCode(const uTable *uT,
uint16_t in,
uint16_t* out);
PRBool uGenerate(uScanClassID scanClass,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen);
int uGenerate(uScanClassID scanClass,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen);
PRBool uScan(uScanClassID scanClass,
int32_t *state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen);
int uScan(uScanClassID scanClass,
int32_t *state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen);
PRBool uGenerateShift(uShiftOutTable *shift,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen);
int uGenerateShift(uShiftOutTable *shift,
int32_t* state,
uint16_t in,
unsigned char* out,
uint32_t outbuflen,
uint32_t* outlen);
PRBool uScanShift(uShiftInTable *shift,
int32_t *state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen);
int uScanShift(uShiftInTable *shift,
int32_t *state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen);
#ifdef __cplusplus
}

View File

@ -8,166 +8,166 @@
/*=================================================================================
=================================================================================*/
typedef PRBool (*uSubScannerFunc) (unsigned char* in, uint16_t* out);
typedef int (*uSubScannerFunc) (unsigned char* in, uint16_t* out);
/*=================================================================================
=================================================================================*/
typedef PRBool (*uScannerFunc) (
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
typedef int (*uScannerFunc) (
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
MODULE_PRIVATE PRBool uScan(
uScanClassID scanClass,
int uScan(
uScanClassID scanClass,
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
#define uSubScanner(sub,in,out) (* m_subscanner[sub])((in),(out))
int uCheckAndScanAlways1Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScanAlways2Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScanAlways2ByteShiftGR(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScanAlways2ByteGR128(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uScanShift(
uShiftInTable *shift,
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
#define uSubScanner(sub,in,out) (* m_subscanner[sub])((in),(out))
PRIVATE PRBool uCheckAndScanAlways1Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScanAlways2Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
MODULE_PRIVATE PRBool uScanShift(
uShiftInTable *shift,
int uCheckAndScan2ByteGRPrefix8F(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan2ByteGRPrefix8EA2(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan2ByteGRPrefix8EA3(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan2ByteGRPrefix8EA4(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan2ByteGRPrefix8EA5(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan2ByteGRPrefix8EA6(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan2ByteGRPrefix8EA7(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCnSAlways8BytesDecomposedHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScanJohabHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScanJohabSymbol(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA3(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA4(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA5(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA6(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScanJohabHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScanJohabSymbol(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uCheckAndScan4BytesGB18030(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
PRIVATE PRBool uCheckAndScan4BytesGB18030(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
);
int uScanAlways2Byte(
unsigned char* in,
uint16_t* out
);
int uScanAlways2ByteShiftGR(
unsigned char* in,
uint16_t* out
);
int uScanAlways1Byte(
unsigned char* in,
uint16_t* out
);
int uScanAlways1BytePrefix8E(
unsigned char* in,
uint16_t* out
);
/*=================================================================================
PRIVATE PRBool uScanAlways2Byte(
unsigned char* in,
uint16_t* out
);
PRIVATE PRBool uScanAlways2ByteShiftGR(
unsigned char* in,
uint16_t* out
);
PRIVATE PRBool uScanAlways1Byte(
unsigned char* in,
uint16_t* out
);
PRIVATE PRBool uScanAlways1BytePrefix8E(
unsigned char* in,
uint16_t* out
);
/*=================================================================================
=================================================================================*/
PRIVATE const uScannerFunc m_scanner[uNumOfCharsetType] =
const uScannerFunc m_scanner[uNumOfCharsetType] =
{
uCheckAndScanAlways1Byte,
uCheckAndScanAlways2Byte,
@ -190,7 +190,7 @@ PRIVATE const uScannerFunc m_scanner[uNumOfCharsetType] =
=================================================================================*/
PRIVATE const uSubScannerFunc m_subscanner[uNumOfCharType] =
const uSubScannerFunc m_subscanner[uNumOfCharType] =
{
uScanAlways1Byte,
uScanAlways2Byte,
@ -200,111 +200,111 @@ PRIVATE const uSubScannerFunc m_subscanner[uNumOfCharType] =
/*=================================================================================
=================================================================================*/
MODULE_PRIVATE PRBool uScan(
uScanClassID scanClass,
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uScan(
uScanClassID scanClass,
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
return (* m_scanner[scanClass]) (state,in,out,inbuflen,inscanlen);
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uScanAlways1Byte(
unsigned char* in,
uint16_t* out
)
int uScanAlways1Byte(
unsigned char* in,
uint16_t* out
)
{
*out = (uint16_t) in[0];
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uScanAlways2Byte(
unsigned char* in,
uint16_t* out
)
int uScanAlways2Byte(
unsigned char* in,
uint16_t* out
)
{
*out = (uint16_t) (( in[0] << 8) | (in[1]));
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uScanAlways2ByteShiftGR(
unsigned char* in,
uint16_t* out
)
int uScanAlways2ByteShiftGR(
unsigned char* in,
uint16_t* out
)
{
*out = (uint16_t) ((( in[0] << 8) | (in[1])) & 0x7F7F);
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uScanAlways1BytePrefix8E(
unsigned char* in,
uint16_t* out
)
int uScanAlways1BytePrefix8E(
unsigned char* in,
uint16_t* out
)
{
*out = (uint16_t) in[1];
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScanAlways1Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScanAlways1Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
/* Don't check inlen. The caller should ensure it is larger than 0 */
*inscanlen = 1;
*out = (uint16_t) in[0];
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScanAlways2Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScanAlways2Byte(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
if(inbuflen < 2)
return PR_FALSE;
return 0;
else
{
*inscanlen = 2;
*out = ((in[0] << 8) | ( in[1])) ;
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScanAlways2ByteShiftGR(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
/*
* Both bytes should be in the range of [0xa1,0xfe] for 94x94 character sets
@ -313,30 +313,30 @@ PRIVATE PRBool uCheckAndScanAlways2ByteShiftGR(
* 1st byte is checked before calling this in nsUnicodeDecoerHelper.cpp
*/
if(inbuflen < 2) /* will lead to NS_OK_UDEC_MOREINPUT */
return PR_FALSE;
return 0;
else if (! CHK_GR94(in[1]))
{
*inscanlen = 2;
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
return PR_TRUE;
return 1;
}
else
{
*inscanlen = 2;
*out = (((in[0] << 8) | ( in[1])) & 0x7F7F);
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScanAlways2ByteGR128(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
/*
* The first byte should be in [0xa1,0xfe]
@ -346,31 +346,31 @@ PRIVATE PRBool uCheckAndScanAlways2ByteGR128(
* 1st byte is checked before calling this in nsUnicodeDecoderHelper.cpp
*/
if(inbuflen < 2) /* will lead to NS_OK_UDEC_MOREINPUT */
return PR_FALSE;
return 0;
else if (in[1] < 0x41) /* 2nd byte range check */
{
*inscanlen = 2;
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
return PR_TRUE;
return 1;
}
else
{
*inscanlen = 2;
*out = (in[0] << 8) | in[1];
return PR_TRUE;
return 1;
}
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uScanShift(
uShiftInTable *shift,
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uScanShift(
uShiftInTable *shift,
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
int16_t i;
const uShiftInCell* cell = &(shift->shiftcell[0]);
@ -381,7 +381,7 @@ PRIVATE PRBool uScanShift(
( in[0] <= cell[i].shiftin_Max))
{
if(inbuflen < cell[i].reserveLen)
return PR_FALSE;
return 0;
else
{
*inscanlen = cell[i].reserveLen;
@ -389,38 +389,38 @@ PRIVATE PRBool uScanShift(
}
}
}
return PR_FALSE;
return 0;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8F(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
if((inbuflen < 3) ||(in[0] != 0x8F))
return PR_FALSE;
return 0;
else if (! CHK_GR94(in[1])) /* 2nd byte range check */
{
*inscanlen = 2;
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
return PR_TRUE;
return 1;
}
else if (! CHK_GR94(in[2])) /* 3rd byte range check */
{
*inscanlen = 3;
*out = 0xFF; /* for 2-byte table, uMap() is guaranteed to fail for 0xFF. */
return PR_TRUE;
return 1;
}
else
{
*inscanlen = 3;
*out = (((in[1] << 8) | ( in[2])) & 0x7F7F);
return PR_TRUE;
return 1;
}
}
/*=================================================================================
@ -432,39 +432,39 @@ PRIVATE PRBool uCheckAndScan2ByteGRPrefix8F(
*/
#define CNS_8EAX_4BYTE(PREFIX) \
if((inbuflen < 4) || (in[0] != 0x8E)) \
return PR_FALSE; \
return 0; \
else if((in[1] != (PREFIX))) \
{ \
*inscanlen = 2; \
*out = 0xFF; \
return PR_TRUE; \
return 1; \
} \
else if(! CHK_GR94(in[2])) \
{ \
*inscanlen = 3; \
*out = 0xFF; \
return PR_TRUE; \
return 1; \
} \
else if(! CHK_GR94(in[3])) \
{ \
*inscanlen = 4; \
*out = 0xFF; \
return PR_TRUE; \
return 1; \
} \
else \
{ \
*inscanlen = 4; \
*out = (((in[2] << 8) | ( in[3])) & 0x7F7F); \
return PR_TRUE; \
return 1; \
}
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8EA2(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
CNS_8EAX_4BYTE(0xA2)
}
@ -472,65 +472,65 @@ PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA2(
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA3(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8EA3(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
CNS_8EAX_4BYTE(0xA3)
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA4(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8EA4(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
CNS_8EAX_4BYTE(0xA4)
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA5(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8EA5(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
CNS_8EAX_4BYTE(0xA5)
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA6(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8EA6(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
CNS_8EAX_4BYTE(0xA6)
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan2ByteGRPrefix8EA7(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
CNS_8EAX_4BYTE(0xA7)
}
@ -544,24 +544,24 @@ PRIVATE PRBool uCheckAndScan2ByteGRPrefix8EA7(
#define TCount 28
#define NCount (VCount * TCount)
PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCnSAlways8BytesDecomposedHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
uint16_t LIndex, VIndex, TIndex;
/* no 8 bytes, not in a4 range, or the first 2 byte are not a4d4 */
if((inbuflen < 8) || (0xa4 != in[0]) || (0xd4 != in[1]) ||
(0xa4 != in[2] ) || (0xa4 != in[4]) || (0xa4 != in[6]))
return PR_FALSE;
return 0;
/* Compute LIndex */
if((in[3] < 0xa1) || (in[3] > 0xbe)) { /* illegal leading consonant */
return PR_FALSE;
return 0;
}
else {
static const uint8_t lMap[] = {
@ -577,12 +577,12 @@ PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
LIndex = lMap[in[3] - 0xa1];
if(0xff == (0xff & LIndex))
return PR_FALSE;
return 0;
}
/* Compute VIndex */
if((in[5] < 0xbf) || (in[5] > 0xd3)) { /* illegal medial vowel */
return PR_FALSE;
return 0;
}
else {
VIndex = in[5] - 0xbf;
@ -594,7 +594,7 @@ PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
TIndex = 0;
}
else if((in[7] < 0xa1) || (in[7] > 0xbe)) {/* illegal trailing consonant */
return PR_FALSE;
return 0;
}
else {
static const uint8_t tMap[] = {
@ -609,31 +609,31 @@ PRIVATE PRBool uCnSAlways8BytesDecomposedHangul(
};
TIndex = tMap[in[7] - 0xa1];
if(0xff == (0xff & TIndex))
return PR_FALSE;
return 0;
}
*inscanlen = 8;
/* the following line is from Unicode 2.0 page 3-13 item 5 */
*out = ( LIndex * VCount + VIndex) * TCount + TIndex + SBase;
return PR_TRUE;
return 1;
}
/*=================================================================================
=================================================================================*/
PRIVATE PRBool uCheckAndScanJohabHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScanJohabHangul(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
/* since we don't have code to convert Johab to Unicode right now *
* make this part of code #if 0 to save space until we fully test it */
if(inbuflen < 2)
return PR_FALSE;
return 0;
else {
/*
* See Table 4-45 Johab Encoding's Five-Bit Binary Patterns in page 183
@ -660,30 +660,30 @@ PRIVATE PRBool uCheckAndScanJohabHangul(
uint16_t ch = (in[0] << 8) | in[1];
uint16_t LIndex, VIndex, TIndex;
if(0 == (0x8000 & ch))
return PR_FALSE;
return 0;
LIndex=lMap[(ch>>10)& 0x1F];
VIndex=vMap[(ch>>5) & 0x1F];
TIndex=tMap[(ch>>0) & 0x1F];
if((0xff==(LIndex)) ||
(0xff==(VIndex)) ||
(0xff==(TIndex)))
return PR_FALSE;
return 0;
/* the following line is from Unicode 2.0 page 3-13 item 5 */
*out = ( LIndex * VCount + VIndex) * TCount + TIndex + SBase;
*inscanlen = 2;
return PR_TRUE;
return 1;
}
}
PRIVATE PRBool uCheckAndScanJohabSymbol(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScanJohabSymbol(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
if(inbuflen < 2)
return PR_FALSE;
return 0;
else {
/*
* The following code are based on the Perl code lised under
@ -726,34 +726,34 @@ PRIVATE PRBool uCheckAndScanJohabSymbol(
(lo - ((lo < 161) ? ((lo > 126) ? 34 : 16) :
128));
*inscanlen = 2;
return PR_TRUE;
return 1;
}
}
PRIVATE PRBool uCheckAndScan4BytesGB18030(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
int uCheckAndScan4BytesGB18030(
int32_t* state,
unsigned char *in,
uint16_t *out,
uint32_t inbuflen,
uint32_t* inscanlen
)
{
uint32_t data;
if(inbuflen < 4)
return PR_FALSE;
return 0;
if((in[0] < 0x81 ) || (0xfe < in[0]))
return PR_FALSE;
return 0;
if((in[1] < 0x30 ) || (0x39 < in[1]))
return PR_FALSE;
return 0;
if((in[2] < 0x81 ) || (0xfe < in[2]))
return PR_FALSE;
return 0;
if((in[3] < 0x30 ) || (0x39 < in[3]))
return PR_FALSE;
return 0;
data = (((((in[0] - 0x81) * 10 + (in[1] - 0x30)) * 126) +
(in[2] - 0x81)) * 10 ) + (in[3] - 0x30);
*inscanlen = 4;
*out = (data < 0x00010000) ? data : 0xFFFD;
return PR_TRUE;
return 1;
}

View File

@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "prtypes.h"
#include <stdint.h>
namespace mozilla {

View File

@ -1285,6 +1285,9 @@ MessageChannel::ReportMessageRouteError(const char* channelName) const
void
MessageChannel::ReportConnectionError(const char* aChannelName) const
{
AssertWorkerThread();
mMonitor->AssertCurrentThreadOwns();
const char* errorMsg = nullptr;
switch (mChannelState) {
case ChannelClosed:
@ -1308,6 +1311,8 @@ MessageChannel::ReportConnectionError(const char* aChannelName) const
}
PrintErrorMessage(mSide, aChannelName, errorMsg);
MonitorAutoUnlock unlock(*mMonitor);
mListener->OnProcessingError(MsgDropped);
}

View File

@ -360,7 +360,7 @@ jsd_GetJSScript (JSDContext *jsdc, JSDScript *script)
JSFunction *
jsd_GetJSFunction (JSDContext *jsdc, JSDScript *script)
{
AutoSafeJSContext cx; // NB: Actually unused.
AutoSafeJSContext cx;
return JS_GetScriptFunction(cx, script->script);
}

View File

@ -608,6 +608,22 @@ function ComputeNumChunks(length) {
return chunks + 1;
}
#define SLICES_PER_WORKER 8
/**
* Compute the number of slices given an array length and the number of
* chunks. Used in tandem with the workstealing scheduler.
*/
function ComputeNumSlices(workers, length, chunks) {
if (length !== 0) {
var slices = workers * SLICES_PER_WORKER;
if (chunks < slices)
return workers;
return slices;
}
return workers;
}
/**
* Computes the bounds for slice |sliceIndex| of |numItems| items,
* assuming |numSlices| total slices. If numItems is not evenly
@ -676,9 +692,10 @@ function ArrayMapPar(func, mode) {
break parallel;
var chunks = ComputeNumChunks(length);
var numSlices = ForkJoinSlices();
var numWorkers = ForkJoinNumWorkers();
var numSlices = ComputeNumSlices(numWorkers, length, chunks);
var info = ComputeAllSliceBounds(chunks, numSlices);
ForkJoin(mapSlice, ForkJoinMode(mode));
ForkJoin(mapSlice, ForkJoinMode(mode), numSlices);
return buffer;
}
@ -691,7 +708,7 @@ function ArrayMapPar(func, mode) {
}
return buffer;
function mapSlice(sliceId, numSlices, warmup) {
function mapSlice(sliceId, warmup) {
var chunkPos = info[SLICE_POS(sliceId)];
var chunkEnd = info[SLICE_END(sliceId)];
@ -735,13 +752,14 @@ function ArrayReducePar(func, mode) {
break parallel;
var chunks = ComputeNumChunks(length);
var numSlices = ForkJoinSlices();
if (chunks < numSlices)
var numWorkers = ForkJoinNumWorkers();
if (chunks < numWorkers)
break parallel;
var numSlices = ComputeNumSlices(numWorkers, length, chunks);
var info = ComputeAllSliceBounds(chunks, numSlices);
var subreductions = NewDenseArray(numSlices);
ForkJoin(reduceSlice, ForkJoinMode(mode));
ForkJoin(reduceSlice, ForkJoinMode(mode), numSlices);
var accumulator = subreductions[0];
for (var i = 1; i < numSlices; i++)
accumulator = func(accumulator, subreductions[i]);
@ -755,7 +773,7 @@ function ArrayReducePar(func, mode) {
accumulator = func(accumulator, self[i]);
return accumulator;
function reduceSlice(sliceId, numSlices, warmup) {
function reduceSlice(sliceId, warmup) {
var chunkStart = info[SLICE_START(sliceId)];
var chunkPos = info[SLICE_POS(sliceId)];
var chunkEnd = info[SLICE_END(sliceId)];
@ -824,13 +842,15 @@ function ArrayScanPar(func, mode) {
break parallel;
var chunks = ComputeNumChunks(length);
var numSlices = ForkJoinSlices();
if (chunks < numSlices)
var numWorkers = ForkJoinNumWorkers();
if (chunks < numWorkers)
break parallel;
var numSlices = ComputeNumSlices(numWorkers, length, chunks);
var info = ComputeAllSliceBounds(chunks, numSlices);
// Scan slices individually (see comment on phase1()).
ForkJoin(phase1, ForkJoinMode(mode));
ForkJoin(phase1, ForkJoinMode(mode), numSlices);
// Compute intermediates array (see comment on phase2()).
var intermediates = [];
@ -850,7 +870,7 @@ function ArrayScanPar(func, mode) {
info[SLICE_END(numSlices - 1)] = std_Math_min(info[SLICE_END(numSlices - 1)], length);
// Complete each slice using intermediates array (see comment on phase2()).
ForkJoin(phase2, ForkJoinMode(mode));
ForkJoin(phase2, ForkJoinMode(mode), numSlices);
return buffer;
}
@ -884,7 +904,7 @@ function ArrayScanPar(func, mode) {
*
* Read on in phase2 to see what we do next!
*/
function phase1(sliceId, numSlices, warmup) {
function phase1(sliceId, warmup) {
var chunkStart = info[SLICE_START(sliceId)];
var chunkPos = info[SLICE_POS(sliceId)];
var chunkEnd = info[SLICE_END(sliceId)];
@ -967,7 +987,7 @@ function ArrayScanPar(func, mode) {
* index granularity, although this requires two memory writes per
* index.
*/
function phase2(sliceId, numSlices, warmup) {
function phase2(sliceId, warmup) {
if (sliceId === 0)
return true; // No work to do for the 0th slice.
@ -1102,7 +1122,7 @@ function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) {
function parDivideOutputRange() {
var chunks = ComputeNumChunks(targetsLength);
var numSlices = ForkJoinSlices();
var numSlices = ComputeNumSlices(ForkJoinNumWorkers(), length, chunks);
var checkpoints = NewDenseArray(numSlices);
for (var i = 0; i < numSlices; i++)
UnsafePutElements(checkpoints, i, 0);
@ -1115,10 +1135,10 @@ function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) {
UnsafePutElements(conflicts, i, false);
}
ForkJoin(fill, ForkJoinMode(mode));
ForkJoin(fill, ForkJoinMode(mode), numSlices);
return buffer;
function fill(sliceId, numSlices, warmup) {
function fill(sliceId, warmup) {
var indexPos = checkpoints[sliceId];
var indexEnd = targetsLength;
if (warmup)
@ -1149,7 +1169,7 @@ function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) {
// target array for fear of inducing a conflict where none existed
// before. Therefore, we must proceed not by chunks but rather by
// individual indices.
var numSlices = ForkJoinSlices();
var numSlices = ComputeNumSlices(ForkJoinNumWorkers(), length, ComputeNumChunks(length));
var info = ComputeAllSliceBounds(targetsLength, numSlices);
// FIXME(bug 844890): Use typed arrays here.
@ -1172,11 +1192,11 @@ function ArrayScatterPar(targets, defaultValue, conflictFunc, length, mode) {
for (var i = 0; i < length; i++)
UnsafePutElements(outputBuffer, i, defaultValue);
ForkJoin(fill, ForkJoinMode(mode));
ForkJoin(fill, ForkJoinMode(mode), numSlices);
mergeBuffers();
return outputBuffer;
function fill(sliceId, numSlices, warmup) {
function fill(sliceId, warmup) {
var indexPos = info[SLICE_POS(sliceId)];
var indexEnd = info[SLICE_END(sliceId)];
if (warmup)
@ -1275,10 +1295,11 @@ function ArrayFilterPar(func, mode) {
break parallel;
var chunks = ComputeNumChunks(length);
var numSlices = ForkJoinSlices();
if (chunks < numSlices * 2)
var numWorkers = ForkJoinNumWorkers();
if (chunks < numWorkers * 2)
break parallel;
var numSlices = ComputeNumSlices(numWorkers, length, chunks);
var info = ComputeAllSliceBounds(chunks, numSlices);
// Step 1. Compute which items from each slice of the result
@ -1293,7 +1314,7 @@ function ArrayFilterPar(func, mode) {
for (var i = 0; i < numSlices; i++)
UnsafePutElements(counts, i, 0);
var survivors = NewDenseArray(chunks);
ForkJoin(findSurvivorsInSlice, ForkJoinMode(mode));
ForkJoin(findSurvivorsInSlice, ForkJoinMode(mode), numSlices);
// Step 2. Compress the slices into one contiguous set.
var count = 0;
@ -1301,7 +1322,7 @@ function ArrayFilterPar(func, mode) {
count += counts[i];
var buffer = NewDenseArray(count);
if (count > 0)
ForkJoin(copySurvivorsInSlice, ForkJoinMode(mode));
ForkJoin(copySurvivorsInSlice, ForkJoinMode(mode), numSlices);
return buffer;
}
@ -1322,7 +1343,7 @@ function ArrayFilterPar(func, mode) {
* time. When we finish a chunk, we record our current count and
* the next chunk sliceId, lest we should bail.
*/
function findSurvivorsInSlice(sliceId, numSlices, warmup) {
function findSurvivorsInSlice(sliceId, warmup) {
var chunkPos = info[SLICE_POS(sliceId)];
var chunkEnd = info[SLICE_END(sliceId)];
@ -1349,7 +1370,7 @@ function ArrayFilterPar(func, mode) {
return chunkEnd === info[SLICE_END(sliceId)];
}
function copySurvivorsInSlice(sliceId, numSlices, warmup) {
function copySurvivorsInSlice(sliceId, warmup) {
// Copies the survivors from this slice into the correct position.
// Note that this is an idempotent operation that does not invoke
// user code. Therefore, we don't expect bailouts and make an
@ -1432,9 +1453,10 @@ function ArrayStaticBuildPar(length, func, mode) {
break parallel;
var chunks = ComputeNumChunks(length);
var numSlices = ForkJoinSlices();
var numWorkers = ForkJoinNumWorkers();
var numSlices = ComputeNumSlices(numWorkers, length, chunks);
var info = ComputeAllSliceBounds(chunks, numSlices);
ForkJoin(constructSlice, ForkJoinMode(mode));
ForkJoin(constructSlice, ForkJoinMode(mode), numSlices);
return buffer;
}
@ -1443,7 +1465,7 @@ function ArrayStaticBuildPar(length, func, mode) {
fill(0, length);
return buffer;
function constructSlice(sliceId, numSlices, warmup) {
function constructSlice(sliceId, warmup) {
var chunkPos = info[SLICE_POS(sliceId)];
var chunkEnd = info[SLICE_END(sliceId)];

View File

@ -124,9 +124,6 @@ libs:: $(CPP_UNIT_TEST_BINS) $(call mkdir_deps,$(DIST)/cppunittests)
$(NSINSTALL) $(CPP_UNIT_TEST_BINS) $(DIST)/cppunittests
endif
check::
@$(PYTHON) $(topsrcdir)/testing/runcppunittests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(subst .cpp,$(BIN_SUFFIX),$(CPP_UNIT_TESTS))
cppunittests-remote: DM_TRANS?=adb
cppunittests-remote:
@if [ '${TEST_DEVICE}' != '' -o '$(DM_TRANS)' = 'adb' ]; then \

View File

@ -72,7 +72,9 @@ CheckArgumentsWithinEval(JSContext *cx, Parser<FullParseHandler> &parser, Handle
// Force construction of arguments objects for functions that use
// |arguments| within an eval.
RootedScript script(cx, fun->nonLazyScript());
RootedScript script(cx, fun->getOrCreateScript(cx));
if (!script)
return false;
if (script->argumentsHasVarBinding()) {
if (!JSScript::argumentsOptimizationFailed(cx, script))
return false;
@ -123,7 +125,9 @@ MaybeCheckEvalFreeVariables(ExclusiveContext *cxArg, HandleScript evalCaller, Ha
RootedObject scope(cx, scopeChain);
while (scope->is<ScopeObject>() || scope->is<DebugScopeObject>()) {
if (scope->is<CallObject>() && !scope->as<CallObject>().isForEval()) {
RootedScript script(cx, scope->as<CallObject>().callee().nonLazyScript());
RootedScript script(cx, scope->as<CallObject>().callee().getOrCreateScript(cx));
if (!script)
return false;
if (script->argumentsHasVarBinding()) {
if (!JSScript::argumentsOptimizationFailed(cx, script))
return false;
@ -235,10 +239,8 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
Directives directives(options.strictOption);
GlobalSharedContext globalsc(cx, scopeChain, directives, options.extraWarningsOption);
bool savedCallerFun =
options.compileAndGo &&
evalCaller &&
(evalCaller->function() || evalCaller->savedCallerFun());
bool savedCallerFun = options.compileAndGo &&
evalCaller && evalCaller->functionOrCallerFunction();
Rooted<JSScript*> script(cx, JSScript::Create(cx, NullPtr(), savedCallerFun,
options, staticLevel, sourceObject, 0, length));
if (!script)
@ -404,7 +406,7 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
bool
frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const jschar *chars, size_t length)
{
JS_ASSERT(cx->compartment() == lazy->function()->compartment());
JS_ASSERT(cx->compartment() == lazy->functionNonDelazifying()->compartment());
CompileOptions options(cx, lazy->version());
options.setPrincipals(cx->compartment()->principals)
@ -427,7 +429,7 @@ frontend::CompileLazyFunction(JSContext *cx, Handle<LazyScript*> lazy, const jsc
uint32_t staticLevel = lazy->staticLevel(cx);
Rooted<JSFunction*> fun(cx, lazy->function());
Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
JS_ASSERT(!lazy->isLegacyGenerator());
ParseNode *pn = parser.standaloneLazyFunction(fun, staticLevel, lazy->strict(),
lazy->generatorKind());

View File

@ -1285,7 +1285,7 @@ TryConvertFreeName(BytecodeEmitter *bce, ParseNode *pn)
continue;
}
RootedScript script(bce->sc->context, ssi.funScript());
if (script->function()->atom() == pn->pn_atom)
if (script->functionNonDelazifying()->atom() == pn->pn_atom)
return false;
if (ssi.hasDynamicScopeObject()) {
uint16_t slot;
@ -1867,7 +1867,7 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext *cx)
if (!cx->isJSContext())
return;
RootedFunction function(cx, script->function());
RootedFunction function(cx, script->functionNonDelazifying());
CallNewScriptHook(cx->asJSContext(), script, function);
// Lazy scripts are never top level (despite always being invoked with a
// nullptr parent), and so the hook should never be fired.
@ -2795,7 +2795,7 @@ frontend::EmitFunctionScript(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNo
}
/* Initialize fun->script() so that the debugger has a valid fun->script(). */
RootedFunction fun(cx, bce->script->function());
RootedFunction fun(cx, bce->script->functionNonDelazifying());
JS_ASSERT(fun->isInterpreted());
if (fun->isInterpretedLazy()) {

View File

@ -0,0 +1,9 @@
// See bug 953013
load(libdir + "asserts.js");
function test() {
var input = Array(999999+1).join('a');
var result = /^([\w])+$/.test(input);
}
assertThrowsInstanceOf(test, InternalError);

View File

@ -1,39 +1,262 @@
assertEq("abc".endsWith("abc"), true);
assertEq("abcd".endsWith("bcd"), true);
assertEq("abc".endsWith("c"), true);
assertEq("abc".endsWith("abcd"), false);
assertEq("abc".endsWith("bbc"), false);
assertEq("abc".endsWith("b"), false);
assertEq("abc".endsWith("abc", 3), true);
assertEq("abc".endsWith("bc", 3), true);
assertEq("abc".endsWith("a", 3), false);
assertEq("abc".endsWith("bc", 3), true);
assertEq("abc".endsWith("a", 1), true);
assertEq("abc".endsWith("abc", 1), false);
assertEq("abc".endsWith("b", 2), true);
assertEq("abc".endsWith("d", 2), false);
assertEq("abc".endsWith("dcd", 2), false);
assertEq("abc".endsWith("a", 42), false);
assertEq("abc".endsWith("bc", Infinity), true);
assertEq("abc".endsWith("a", Infinity), false);
assertEq("abc".endsWith("bc", undefined), true);
assertEq("abc".endsWith("bc", -43), false);
assertEq("abc".endsWith("bc", -Infinity), false);
assertEq("abc".endsWith("bc", NaN), false);
var myobj = {toString : (function () "abc"), endsWith : String.prototype.endsWith};
assertEq(myobj.endsWith("abc"), true);
assertEq(myobj.endsWith("ab"), false);
var gotStr = false, gotPos = false;
myobj = {toString : (function () {
assertEq(gotPos, false);
gotStr = true;
return "xyz";
}),
endsWith : String.prototype.endsWith};
var idx = {valueOf : (function () {
assertEq(gotStr, true);
gotPos = true;
return 42;
})};
myobj.endsWith("elephant", idx);
assertEq(gotPos, true);
/*
* Copyright (c) 2013 Mathias Bynens. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
function assertThrows(fun, errorType) {
try {
fun();
assertEq(true, false, "Expected error, but none was thrown");
} catch (e) {
assertEq(e instanceof errorType, true, "Wrong error type thrown");
}
}
assertEq(String.prototype.endsWith.length, 1);
assertEq(String.prototype.propertyIsEnumerable('endsWith'), false);
assertEq('undefined'.endsWith(), true);
assertEq('undefined'.endsWith(undefined), true);
assertEq('undefined'.endsWith(null), false);
assertEq('null'.endsWith(), false);
assertEq('null'.endsWith(undefined), false);
assertEq('null'.endsWith(null), true);
assertEq('abc'.endsWith(), false);
assertEq('abc'.endsWith(''), true);
assertEq('abc'.endsWith('\0'), false);
assertEq('abc'.endsWith('c'), true);
assertEq('abc'.endsWith('b'), false);
assertEq('abc'.endsWith('a'), false);
assertEq('abc'.endsWith('ab'), false);
assertEq('abc'.endsWith('bc'), true);
assertEq('abc'.endsWith('abc'), true);
assertEq('abc'.endsWith('bcd'), false);
assertEq('abc'.endsWith('abcd'), false);
assertEq('abc'.endsWith('bcde'), false);
assertEq('abc'.endsWith('', NaN), true);
assertEq('abc'.endsWith('\0', NaN), false);
assertEq('abc'.endsWith('c', NaN), false);
assertEq('abc'.endsWith('b', NaN), false);
assertEq('abc'.endsWith('a', NaN), false);
assertEq('abc'.endsWith('ab', NaN), false);
assertEq('abc'.endsWith('bc', NaN), false);
assertEq('abc'.endsWith('abc', NaN), false);
assertEq('abc'.endsWith('bcd', NaN), false);
assertEq('abc'.endsWith('abcd', NaN), false);
assertEq('abc'.endsWith('bcde', NaN), false);
assertEq('abc'.endsWith('', false), true);
assertEq('abc'.endsWith('\0', false), false);
assertEq('abc'.endsWith('c', false), false);
assertEq('abc'.endsWith('b', false), false);
assertEq('abc'.endsWith('a', false), false);
assertEq('abc'.endsWith('ab', false), false);
assertEq('abc'.endsWith('bc', false), false);
assertEq('abc'.endsWith('abc', false), false);
assertEq('abc'.endsWith('bcd', false), false);
assertEq('abc'.endsWith('abcd', false), false);
assertEq('abc'.endsWith('bcde', false), false);
assertEq('abc'.endsWith('', undefined), true);
assertEq('abc'.endsWith('\0', undefined), false);
assertEq('abc'.endsWith('c', undefined), true);
assertEq('abc'.endsWith('b', undefined), false);
assertEq('abc'.endsWith('a', undefined), false);
assertEq('abc'.endsWith('ab', undefined), false);
assertEq('abc'.endsWith('bc', undefined), true);
assertEq('abc'.endsWith('abc', undefined), true);
assertEq('abc'.endsWith('bcd', undefined), false);
assertEq('abc'.endsWith('abcd', undefined), false);
assertEq('abc'.endsWith('bcde', undefined), false);
assertEq('abc'.endsWith('', null), true);
assertEq('abc'.endsWith('\0', null), false);
assertEq('abc'.endsWith('c', null), false);
assertEq('abc'.endsWith('b', null), false);
assertEq('abc'.endsWith('a', null), false);
assertEq('abc'.endsWith('ab', null), false);
assertEq('abc'.endsWith('bc', null), false);
assertEq('abc'.endsWith('abc', null), false);
assertEq('abc'.endsWith('bcd', null), false);
assertEq('abc'.endsWith('abcd', null), false);
assertEq('abc'.endsWith('bcde', null), false);
assertEq('abc'.endsWith('', -Infinity), true);
assertEq('abc'.endsWith('\0', -Infinity), false);
assertEq('abc'.endsWith('c', -Infinity), false);
assertEq('abc'.endsWith('b', -Infinity), false);
assertEq('abc'.endsWith('a', -Infinity), false);
assertEq('abc'.endsWith('ab', -Infinity), false);
assertEq('abc'.endsWith('bc', -Infinity), false);
assertEq('abc'.endsWith('abc', -Infinity), false);
assertEq('abc'.endsWith('bcd', -Infinity), false);
assertEq('abc'.endsWith('abcd', -Infinity), false);
assertEq('abc'.endsWith('bcde', -Infinity), false);
assertEq('abc'.endsWith('', -1), true);
assertEq('abc'.endsWith('\0', -1), false);
assertEq('abc'.endsWith('c', -1), false);
assertEq('abc'.endsWith('b', -1), false);
assertEq('abc'.endsWith('a', -1), false);
assertEq('abc'.endsWith('ab', -1), false);
assertEq('abc'.endsWith('bc', -1), false);
assertEq('abc'.endsWith('abc', -1), false);
assertEq('abc'.endsWith('bcd', -1), false);
assertEq('abc'.endsWith('abcd', -1), false);
assertEq('abc'.endsWith('bcde', -1), false);
assertEq('abc'.endsWith('', -0), true);
assertEq('abc'.endsWith('\0', -0), false);
assertEq('abc'.endsWith('c', -0), false);
assertEq('abc'.endsWith('b', -0), false);
assertEq('abc'.endsWith('a', -0), false);
assertEq('abc'.endsWith('ab', -0), false);
assertEq('abc'.endsWith('bc', -0), false);
assertEq('abc'.endsWith('abc', -0), false);
assertEq('abc'.endsWith('bcd', -0), false);
assertEq('abc'.endsWith('abcd', -0), false);
assertEq('abc'.endsWith('bcde', -0), false);
assertEq('abc'.endsWith('', +0), true);
assertEq('abc'.endsWith('\0', +0), false);
assertEq('abc'.endsWith('c', +0), false);
assertEq('abc'.endsWith('b', +0), false);
assertEq('abc'.endsWith('a', +0), false);
assertEq('abc'.endsWith('ab', +0), false);
assertEq('abc'.endsWith('bc', +0), false);
assertEq('abc'.endsWith('abc', +0), false);
assertEq('abc'.endsWith('bcd', +0), false);
assertEq('abc'.endsWith('abcd', +0), false);
assertEq('abc'.endsWith('bcde', +0), false);
assertEq('abc'.endsWith('', 1), true);
assertEq('abc'.endsWith('\0', 1), false);
assertEq('abc'.endsWith('c', 1), false);
assertEq('abc'.endsWith('b', 1), false);
assertEq('abc'.endsWith('ab', 1), false);
assertEq('abc'.endsWith('bc', 1), false);
assertEq('abc'.endsWith('abc', 1), false);
assertEq('abc'.endsWith('bcd', 1), false);
assertEq('abc'.endsWith('abcd', 1), false);
assertEq('abc'.endsWith('bcde', 1), false);
assertEq('abc'.endsWith('', 2), true);
assertEq('abc'.endsWith('\0', 2), false);
assertEq('abc'.endsWith('c', 2), false);
assertEq('abc'.endsWith('b', 2), true);
assertEq('abc'.endsWith('ab', 2), true);
assertEq('abc'.endsWith('bc', 2), false);
assertEq('abc'.endsWith('abc', 2), false);
assertEq('abc'.endsWith('bcd', 2), false);
assertEq('abc'.endsWith('abcd', 2), false);
assertEq('abc'.endsWith('bcde', 2), false);
assertEq('abc'.endsWith('', +Infinity), true);
assertEq('abc'.endsWith('\0', +Infinity), false);
assertEq('abc'.endsWith('c', +Infinity), true);
assertEq('abc'.endsWith('b', +Infinity), false);
assertEq('abc'.endsWith('a', +Infinity), false);
assertEq('abc'.endsWith('ab', +Infinity), false);
assertEq('abc'.endsWith('bc', +Infinity), true);
assertEq('abc'.endsWith('abc', +Infinity), true);
assertEq('abc'.endsWith('bcd', +Infinity), false);
assertEq('abc'.endsWith('abcd', +Infinity), false);
assertEq('abc'.endsWith('bcde', +Infinity), false);
assertEq('abc'.endsWith('', true), true);
assertEq('abc'.endsWith('\0', true), false);
assertEq('abc'.endsWith('c', true), false);
assertEq('abc'.endsWith('b', true), false);
assertEq('abc'.endsWith('ab', true), false);
assertEq('abc'.endsWith('bc', true), false);
assertEq('abc'.endsWith('abc', true), false);
assertEq('abc'.endsWith('bcd', true), false);
assertEq('abc'.endsWith('abcd', true), false);
assertEq('abc'.endsWith('bcde', true), false);
assertEq('abc'.endsWith('', 'x'), true);
assertEq('abc'.endsWith('\0', 'x'), false);
assertEq('abc'.endsWith('c', 'x'), false);
assertEq('abc'.endsWith('b', 'x'), false);
assertEq('abc'.endsWith('a', 'x'), false);
assertEq('abc'.endsWith('ab', 'x'), false);
assertEq('abc'.endsWith('bc', 'x'), false);
assertEq('abc'.endsWith('abc', 'x'), false);
assertEq('abc'.endsWith('bcd', 'x'), false);
assertEq('abc'.endsWith('abcd', 'x'), false);
assertEq('abc'.endsWith('bcde', 'x'), false);
assertEq('[a-z]+(bar)?'.endsWith('(bar)?'), true);
assertThrows(function() { '[a-z]+(bar)?'.endsWith(/(bar)?/); }, TypeError);
assertEq('[a-z]+(bar)?'.endsWith('[a-z]+', 6), true);
assertThrows(function() { '[a-z]+(bar)?'.endsWith(/(bar)?/); }, TypeError);
assertThrows(function() { '[a-z]+/(bar)?/'.endsWith(/(bar)?/); }, TypeError);
var global = newGlobal();
global.eval('this.re = /(bar)?/');
assertThrows(function() { '[a-z]+/(bar)?/'.endsWith(global.re); }, TypeError);
// http://mathiasbynens.be/notes/javascript-unicode#poo-test
var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
assertEq(string.endsWith(''), true);
assertEq(string.endsWith('\xF1t\xEBr'), false);
assertEq(string.endsWith('\xF1t\xEBr', 5), true);
assertEq(string.endsWith('\xE0liz\xE6'), false);
assertEq(string.endsWith('\xE0liz\xE6', 16), true);
assertEq(string.endsWith('\xF8n\u2603\uD83D\uDCA9'), true);
assertEq(string.endsWith('\xF8n\u2603\uD83D\uDCA9', 23), true);
assertEq(string.endsWith('\u2603'), false);
assertEq(string.endsWith('\u2603', 21), true);
assertEq(string.endsWith('\uD83D\uDCA9'), true);
assertEq(string.endsWith('\uD83D\uDCA9', 23), true);
assertThrows(function() { String.prototype.endsWith.call(undefined); }, TypeError);
assertThrows(function() { String.prototype.endsWith.call(undefined, 'b'); }, TypeError);
assertThrows(function() { String.prototype.endsWith.call(undefined, 'b', 4); }, TypeError);
assertThrows(function() { String.prototype.endsWith.call(null); }, TypeError);
assertThrows(function() { String.prototype.endsWith.call(null, 'b'); }, TypeError);
assertThrows(function() { String.prototype.endsWith.call(null, 'b', 4); }, TypeError);
assertEq(String.prototype.endsWith.call(42, '2'), true);
assertEq(String.prototype.endsWith.call(42, '4'), false);
assertEq(String.prototype.endsWith.call(42, 'b', 4), false);
assertEq(String.prototype.endsWith.call(42, '2', 1), false);
assertEq(String.prototype.endsWith.call(42, '2', 4), true);
assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 0), false);
assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 1), false);
assertEq(String.prototype.endsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 2), true);
assertThrows(function() { String.prototype.endsWith.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError);
assertThrows(function() { String.prototype.endsWith.call({ 'toString': function() { return 'abc' } }, /./); }, TypeError);
assertThrows(function() { String.prototype.endsWith.apply(undefined); }, TypeError);
assertThrows(function() { String.prototype.endsWith.apply(undefined, ['b']); }, TypeError);
assertThrows(function() { String.prototype.endsWith.apply(undefined, ['b', 4]); }, TypeError);
assertThrows(function() { String.prototype.endsWith.apply(null); }, TypeError);
assertThrows(function() { String.prototype.endsWith.apply(null, ['b']); }, TypeError);
assertThrows(function() { String.prototype.endsWith.apply(null, ['b', 4]); }, TypeError);
assertEq(String.prototype.endsWith.apply(42, ['2']), true);
assertEq(String.prototype.endsWith.apply(42, ['4']), false);
assertEq(String.prototype.endsWith.apply(42, ['b', 4]), false);
assertEq(String.prototype.endsWith.apply(42, ['2', 1]), false);
assertEq(String.prototype.endsWith.apply(42, ['2', 4]), true);
assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), false);
assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), false);
assertEq(String.prototype.endsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), true);
assertThrows(function() { String.prototype.endsWith.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError);
assertThrows(function() { String.prototype.endsWith.apply({ 'toString': function() { return 'abc' } }, [/./]); }, TypeError);

View File

@ -1,39 +1,243 @@
assertEq("abc".startsWith("abc"), true);
assertEq("abcd".startsWith("abc"), true);
assertEq("abc".startsWith("a"), true);
assertEq("abc".startsWith("abcd"), false);
assertEq("abc".startsWith("bcde"), false);
assertEq("abc".startsWith("b"), false);
assertEq("abc".startsWith("abc", 0), true);
assertEq("abc".startsWith("bc", 0), false);
assertEq("abc".startsWith("bc", 1), true);
assertEq("abc".startsWith("c", 1), false);
assertEq("abc".startsWith("abc", 1), false);
assertEq("abc".startsWith("c", 2), true);
assertEq("abc".startsWith("d", 2), false);
assertEq("abc".startsWith("dcd", 2), false);
assertEq("abc".startsWith("a", 42), false);
assertEq("abc".startsWith("a", Infinity), false);
assertEq("abc".startsWith("a", NaN), true);
assertEq("abc".startsWith("b", NaN), false);
assertEq("abc".startsWith("ab", -43), true);
assertEq("abc".startsWith("ab", -Infinity), true);
assertEq("abc".startsWith("bc", -42), false);
assertEq("abc".startsWith("bc", -Infinity), false);
var myobj = {toString : (function () "abc"), startsWith : String.prototype.startsWith};
assertEq(myobj.startsWith("abc"), true);
assertEq(myobj.startsWith("bc"), false);
var gotStr = false, gotPos = false;
myobj = {toString : (function () {
assertEq(gotPos, false);
gotStr = true;
return "xyz";
}),
startsWith : String.prototype.startsWith};
var idx = {valueOf : (function () {
assertEq(gotStr, true);
gotPos = true;
return 42;
})};
myobj.startsWith("elephant", idx);
assertEq(gotPos, true);
/*
* Copyright (c) 2013 Mathias Bynens. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
function assertThrows(fun, errorType) {
try {
fun();
assertEq(true, false, "Expected error, but none was thrown");
} catch (e) {
assertEq(e instanceof errorType, true, "Wrong error type thrown");
}
}
Object.prototype[1] = 2; // try to break `arguments[1]`
assertEq(String.prototype.startsWith.length, 1);
assertEq(String.prototype.propertyIsEnumerable('startsWith'), false);
assertEq('undefined'.startsWith(), true);
assertEq('undefined'.startsWith(undefined), true);
assertEq('undefined'.startsWith(null), false);
assertEq('null'.startsWith(), false);
assertEq('null'.startsWith(undefined), false);
assertEq('null'.startsWith(null), true);
assertEq('abc'.startsWith(), false);
assertEq('abc'.startsWith(''), true);
assertEq('abc'.startsWith('\0'), false);
assertEq('abc'.startsWith('a'), true);
assertEq('abc'.startsWith('b'), false);
assertEq('abc'.startsWith('ab'), true);
assertEq('abc'.startsWith('bc'), false);
assertEq('abc'.startsWith('abc'), true);
assertEq('abc'.startsWith('bcd'), false);
assertEq('abc'.startsWith('abcd'), false);
assertEq('abc'.startsWith('bcde'), false);
assertEq('abc'.startsWith('', NaN), true);
assertEq('abc'.startsWith('\0', NaN), false);
assertEq('abc'.startsWith('a', NaN), true);
assertEq('abc'.startsWith('b', NaN), false);
assertEq('abc'.startsWith('ab', NaN), true);
assertEq('abc'.startsWith('bc', NaN), false);
assertEq('abc'.startsWith('abc', NaN), true);
assertEq('abc'.startsWith('bcd', NaN), false);
assertEq('abc'.startsWith('abcd', NaN), false);
assertEq('abc'.startsWith('bcde', NaN), false);
assertEq('abc'.startsWith('', false), true);
assertEq('abc'.startsWith('\0', false), false);
assertEq('abc'.startsWith('a', false), true);
assertEq('abc'.startsWith('b', false), false);
assertEq('abc'.startsWith('ab', false), true);
assertEq('abc'.startsWith('bc', false), false);
assertEq('abc'.startsWith('abc', false), true);
assertEq('abc'.startsWith('bcd', false), false);
assertEq('abc'.startsWith('abcd', false), false);
assertEq('abc'.startsWith('bcde', false), false);
assertEq('abc'.startsWith('', undefined), true);
assertEq('abc'.startsWith('\0', undefined), false);
assertEq('abc'.startsWith('a', undefined), true);
assertEq('abc'.startsWith('b', undefined), false);
assertEq('abc'.startsWith('ab', undefined), true);
assertEq('abc'.startsWith('bc', undefined), false);
assertEq('abc'.startsWith('abc', undefined), true);
assertEq('abc'.startsWith('bcd', undefined), false);
assertEq('abc'.startsWith('abcd', undefined), false);
assertEq('abc'.startsWith('bcde', undefined), false);
assertEq('abc'.startsWith('', null), true);
assertEq('abc'.startsWith('\0', null), false);
assertEq('abc'.startsWith('a', null), true);
assertEq('abc'.startsWith('b', null), false);
assertEq('abc'.startsWith('ab', null), true);
assertEq('abc'.startsWith('bc', null), false);
assertEq('abc'.startsWith('abc', null), true);
assertEq('abc'.startsWith('bcd', null), false);
assertEq('abc'.startsWith('abcd', null), false);
assertEq('abc'.startsWith('bcde', null), false);
assertEq('abc'.startsWith('', -Infinity), true);
assertEq('abc'.startsWith('\0', -Infinity), false);
assertEq('abc'.startsWith('a', -Infinity), true);
assertEq('abc'.startsWith('b', -Infinity), false);
assertEq('abc'.startsWith('ab', -Infinity), true);
assertEq('abc'.startsWith('bc', -Infinity), false);
assertEq('abc'.startsWith('abc', -Infinity), true);
assertEq('abc'.startsWith('bcd', -Infinity), false);
assertEq('abc'.startsWith('abcd', -Infinity), false);
assertEq('abc'.startsWith('bcde', -Infinity), false);
assertEq('abc'.startsWith('', -1), true);
assertEq('abc'.startsWith('\0', -1), false);
assertEq('abc'.startsWith('a', -1), true);
assertEq('abc'.startsWith('b', -1), false);
assertEq('abc'.startsWith('ab', -1), true);
assertEq('abc'.startsWith('bc', -1), false);
assertEq('abc'.startsWith('abc', -1), true);
assertEq('abc'.startsWith('bcd', -1), false);
assertEq('abc'.startsWith('abcd', -1), false);
assertEq('abc'.startsWith('bcde', -1), false);
assertEq('abc'.startsWith('', -0), true);
assertEq('abc'.startsWith('\0', -0), false);
assertEq('abc'.startsWith('a', -0), true);
assertEq('abc'.startsWith('b', -0), false);
assertEq('abc'.startsWith('ab', -0), true);
assertEq('abc'.startsWith('bc', -0), false);
assertEq('abc'.startsWith('abc', -0), true);
assertEq('abc'.startsWith('bcd', -0), false);
assertEq('abc'.startsWith('abcd', -0), false);
assertEq('abc'.startsWith('bcde', -0), false);
assertEq('abc'.startsWith('', +0), true);
assertEq('abc'.startsWith('\0', +0), false);
assertEq('abc'.startsWith('a', +0), true);
assertEq('abc'.startsWith('b', +0), false);
assertEq('abc'.startsWith('ab', +0), true);
assertEq('abc'.startsWith('bc', +0), false);
assertEq('abc'.startsWith('abc', +0), true);
assertEq('abc'.startsWith('bcd', +0), false);
assertEq('abc'.startsWith('abcd', +0), false);
assertEq('abc'.startsWith('bcde', +0), false);
assertEq('abc'.startsWith('', 1), true);
assertEq('abc'.startsWith('\0', 1), false);
assertEq('abc'.startsWith('a', 1), false);
assertEq('abc'.startsWith('b', 1), true);
assertEq('abc'.startsWith('ab', 1), false);
assertEq('abc'.startsWith('bc', 1), true);
assertEq('abc'.startsWith('abc', 1), false);
assertEq('abc'.startsWith('bcd', 1), false);
assertEq('abc'.startsWith('abcd', 1), false);
assertEq('abc'.startsWith('bcde', 1), false);
assertEq('abc'.startsWith('', +Infinity), true);
assertEq('abc'.startsWith('\0', +Infinity), false);
assertEq('abc'.startsWith('a', +Infinity), false);
assertEq('abc'.startsWith('b', +Infinity), false);
assertEq('abc'.startsWith('ab', +Infinity), false);
assertEq('abc'.startsWith('bc', +Infinity), false);
assertEq('abc'.startsWith('abc', +Infinity), false);
assertEq('abc'.startsWith('bcd', +Infinity), false);
assertEq('abc'.startsWith('abcd', +Infinity), false);
assertEq('abc'.startsWith('bcde', +Infinity), false);
assertEq('abc'.startsWith('', true), true);
assertEq('abc'.startsWith('\0', true), false);
assertEq('abc'.startsWith('a', true), false);
assertEq('abc'.startsWith('b', true), true);
assertEq('abc'.startsWith('ab', true), false);
assertEq('abc'.startsWith('bc', true), true);
assertEq('abc'.startsWith('abc', true), false);
assertEq('abc'.startsWith('bcd', true), false);
assertEq('abc'.startsWith('abcd', true), false);
assertEq('abc'.startsWith('bcde', true), false);
assertEq('abc'.startsWith('', 'x'), true);
assertEq('abc'.startsWith('\0', 'x'), false);
assertEq('abc'.startsWith('a', 'x'), true);
assertEq('abc'.startsWith('b', 'x'), false);
assertEq('abc'.startsWith('ab', 'x'), true);
assertEq('abc'.startsWith('bc', 'x'), false);
assertEq('abc'.startsWith('abc', 'x'), true);
assertEq('abc'.startsWith('bcd', 'x'), false);
assertEq('abc'.startsWith('abcd', 'x'), false);
assertEq('abc'.startsWith('bcde', 'x'), false);
assertEq('[a-z]+(bar)?'.startsWith('[a-z]+'), true);
assertThrows(function() { '[a-z]+(bar)?'.startsWith(/[a-z]+/); }, TypeError);
assertEq('[a-z]+(bar)?'.startsWith('(bar)?', 6), true);
assertThrows(function() { '[a-z]+(bar)?'.startsWith(/(bar)?/); }, TypeError);
assertThrows(function() { '[a-z]+/(bar)?/'.startsWith(/(bar)?/); }, TypeError);
var global = newGlobal();
global.eval('this.re = /(bar)?/');
assertThrows(function() { '[a-z]+/(bar)?/'.startsWith(global.re); }, TypeError);
// http://mathiasbynens.be/notes/javascript-unicode#poo-test
var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9';
assertEq(string.startsWith(''), true);
assertEq(string.startsWith('\xF1t\xEBr'), false);
assertEq(string.startsWith('\xF1t\xEBr', 1), true);
assertEq(string.startsWith('\xE0liz\xE6'), false);
assertEq(string.startsWith('\xE0liz\xE6', 11), true);
assertEq(string.startsWith('\xF8n\u2603\uD83D\uDCA9'), false);
assertEq(string.startsWith('\xF8n\u2603\uD83D\uDCA9', 18), true);
assertEq(string.startsWith('\u2603'), false);
assertEq(string.startsWith('\u2603', 20), true);
assertEq(string.startsWith('\uD83D\uDCA9'), false);
assertEq(string.startsWith('\uD83D\uDCA9', 21), true);
assertThrows(function() { String.prototype.startsWith.call(undefined); }, TypeError);
assertThrows(function() { String.prototype.startsWith.call(undefined, 'b'); }, TypeError);
assertThrows(function() { String.prototype.startsWith.call(undefined, 'b', 4); }, TypeError);
assertThrows(function() { String.prototype.startsWith.call(null); }, TypeError);
assertThrows(function() { String.prototype.startsWith.call(null, 'b'); }, TypeError);
assertThrows(function() { String.prototype.startsWith.call(null, 'b', 4); }, TypeError);
assertEq(String.prototype.startsWith.call(42, '2'), false);
assertEq(String.prototype.startsWith.call(42, '4'), true);
assertEq(String.prototype.startsWith.call(42, 'b', 4), false);
assertEq(String.prototype.startsWith.call(42, '2', 1), true);
assertEq(String.prototype.startsWith.call(42, '2', 4), false);
assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 0), false);
assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 1), true);
assertEq(String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, 'b', 2), false);
assertThrows(function() { String.prototype.startsWith.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError);
assertThrows(function() { String.prototype.startsWith.call({ 'toString': function() { return 'abc'; } }, /./); }, TypeError);
assertThrows(function() { String.prototype.startsWith.apply(undefined); }, TypeError);
assertThrows(function() { String.prototype.startsWith.apply(undefined, ['b']); }, TypeError);
assertThrows(function() { String.prototype.startsWith.apply(undefined, ['b', 4]); }, TypeError);
assertThrows(function() { String.prototype.startsWith.apply(null); }, TypeError);
assertThrows(function() { String.prototype.startsWith.apply(null, ['b']); }, TypeError);
assertThrows(function() { String.prototype.startsWith.apply(null, ['b', 4]); }, TypeError);
assertEq(String.prototype.startsWith.apply(42, ['2']), false);
assertEq(String.prototype.startsWith.apply(42, ['4']), true);
assertEq(String.prototype.startsWith.apply(42, ['b', 4]), false);
assertEq(String.prototype.startsWith.apply(42, ['2', 1]), true);
assertEq(String.prototype.startsWith.apply(42, ['2', 4]), false);
assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), false);
assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), true);
assertEq(String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), false);
assertThrows(function() { String.prototype.startsWith.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError);
assertThrows(function() { String.prototype.startsWith.apply({ 'toString': function() { return 'abc'; } }, [/./]); }, TypeError);

View File

@ -15,7 +15,8 @@ function testReduce() {
return r;
}
var array = build(4096, function() { return 1; });
// We use a big array, to make sure that the test runs with 64 slices.
var array = build(8 * 4096, function() { return 1; });
var seqResult = array.reduce(sum);
var seqCounter = aCounter;

View File

@ -3,7 +3,7 @@ load(libdir + "parallelarray-helpers.js");
function makeObject(e, i, c) {
var v = {element: e, index: i, collection: c};
if (e == 512) // note: happens once
if (e == 0) // note: happens once
delete v.index;
return v;

View File

@ -113,8 +113,8 @@ BaselineCompiler::compile()
return Method_Error;
JSObject *templateScope = nullptr;
if (script->function()) {
RootedFunction fun(cx, script->function());
if (script->functionNonDelazifying()) {
RootedFunction fun(cx, script->functionNonDelazifying());
if (fun->isHeavyweight()) {
templateScope = CallObject::createTemplateObject(cx, script, gc::TenuredHeap);
if (!templateScope)

View File

@ -182,7 +182,7 @@ class BaselineFrame
offsetOfNumActualArgs());
}
unsigned numFormalArgs() const {
return script()->function()->nargs();
return script()->functionNonDelazifying()->nargs();
}
Value &thisValue() const {
return *(Value *)(reinterpret_cast<const uint8_t *>(this) +

View File

@ -182,7 +182,7 @@ class FrameInfo
return script->nfixed();
}
uint32_t nargs() const {
return script->function()->nargs();
return script->functionNonDelazifying()->nargs();
}
private:

View File

@ -220,6 +220,8 @@ jit::BaselineCompile(JSContext *cx, HandleScript script)
LifoAlloc alloc(BASELINE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
script->ensureNonLazyCanonicalFunction(cx);
TempAllocator *temp = alloc.new_<TempAllocator>(&alloc);
if (!temp)
return Method_Error;

View File

@ -3401,7 +3401,8 @@ CodeGenerator::visitNewDeclEnvObject(LNewDeclEnvObject *lir)
// If we have a template object, we can inline call object creation.
OutOfLineCode *ool = oolCallVM(NewDeclEnvObjectInfo, lir,
(ArgList(), ImmGCPtr(info.fun()), Imm32(gc::DefaultHeap)),
(ArgList(), ImmGCPtr(info.funMaybeLazy()),
Imm32(gc::DefaultHeap)),
StoreRegisterTo(obj));
if (!ool)
return false;

View File

@ -51,10 +51,12 @@ class CompileInfo
{
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
// The function here can flow in from anywhere so look up the canonical function to ensure that
// we do not try to embed a nursery pointer in jit-code.
// The function here can flow in from anywhere so look up the canonical
// function to ensure that we do not try to embed a nursery pointer in
// jit-code. Precisely because it can flow in from anywhere, it's not
// guaranteed to be non-lazy. Hence, don't access its script!
if (fun_) {
fun_ = fun_->nonLazyScript()->function();
fun_ = fun_->nonLazyScript()->functionNonDelazifying();
JS_ASSERT(fun_->isTenured());
}
@ -80,7 +82,7 @@ class CompileInfo
JSScript *script() const {
return script_;
}
JSFunction *fun() const {
JSFunction *funMaybeLazy() const {
return fun_;
}
bool constructing() const {
@ -174,7 +176,7 @@ class CompileInfo
return 2;
}
uint32_t thisSlot() const {
JS_ASSERT(fun());
JS_ASSERT(funMaybeLazy());
JS_ASSERT(nimplicit_ > 0);
return nimplicit_ - 1;
}
@ -213,16 +215,16 @@ class CompileInfo
}
uint32_t endArgSlot() const {
JS_ASSERT(script());
return CountArgSlots(script(), fun());
return CountArgSlots(script(), funMaybeLazy());
}
uint32_t totalSlots() const {
JS_ASSERT(script() && fun());
JS_ASSERT(script() && funMaybeLazy());
return nimplicit() + nargs() + nlocals();
}
bool isSlotAliased(uint32_t index) const {
if (fun() && index == thisSlot())
if (funMaybeLazy() && index == thisSlot())
return false;
uint32_t arg = index - firstArgSlot();

View File

@ -1622,7 +1622,9 @@ TrackPropertiesForSingletonScopes(JSContext *cx, JSScript *script, BaselineFrame
// could access are tracked. These are generally accessed through
// ALIASEDVAR operations in baseline and will not be tracked even if they
// have been accessed in baseline code.
JSObject *environment = script->function() ? script->function()->environment() : nullptr;
JSObject *environment = script->functionNonDelazifying()
? script->functionNonDelazifying()->environment()
: nullptr;
while (environment && !environment->is<GlobalObject>()) {
if (environment->is<CallObject>() && environment->hasSingletonType())
@ -1651,6 +1653,10 @@ IonCompile(JSContext *cx, JSScript *script,
#endif
JS_ASSERT(optimizationLevel > Optimization_DontCompile);
// Make sure the script's canonical function isn't lazy. We can't de-lazify
// it in a worker thread.
script->ensureNonLazyCanonicalFunction(cx);
TrackPropertiesForSingletonScopes(cx, script, baselineFrame);
LifoAlloc *alloc = cx->new_<LifoAlloc>(BUILDER_LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
@ -1677,8 +1683,9 @@ IonCompile(JSContext *cx, JSScript *script,
if (!graph)
return AbortReason_Alloc;
CompileInfo *info = alloc->new_<CompileInfo>(script, script->function(), osrPc, constructing,
executionMode, script->needsArgsObj());
CompileInfo *info = alloc->new_<CompileInfo>(script, script->functionNonDelazifying(), osrPc,
constructing, executionMode,
script->needsArgsObj());
if (!info)
return AbortReason_Alloc;
@ -2218,7 +2225,7 @@ jit::CanEnterUsingFastInvoke(JSContext *cx, HandleScript script, uint32_t numAct
// Don't handle arguments underflow, to make this work we would have to pad
// missing arguments with |undefined|.
if (numActualArgs < script->function()->nargs())
if (numActualArgs < script->functionNonDelazifying()->nargs())
return Method_Skipped;
if (!cx->compartment()->ensureJitCompartmentExists(cx))
@ -2279,7 +2286,7 @@ jit::SetEnterJitData(JSContext *cx, EnterJitData &data, RunState &state, AutoVal
if (state.isInvoke()) {
CallArgs &args = state.asInvoke()->args();
unsigned numFormals = state.script()->function()->nargs();
unsigned numFormals = state.script()->functionNonDelazifying()->nargs();
data.constructing = state.asInvoke()->constructing();
data.numActualArgs = args.length();
data.maxArgc = Max(args.length(), numFormals) + 1;

View File

@ -216,7 +216,7 @@ IsPhiObservable(MPhi *phi, Observability observe)
uint32_t slot = phi->slot();
CompileInfo &info = phi->block()->info();
JSFunction *fun = info.fun();
JSFunction *fun = info.funMaybeLazy();
// If the Phi is of the |this| value, it must always be observable.
if (fun && slot == info.thisSlot())
@ -2143,11 +2143,10 @@ jit::AnalyzeNewScriptProperties(JSContext *cx, JSFunction *fun,
// which will definitely be added to the created object before it has a
// chance to escape and be accessed elsewhere.
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
RootedScript script(cx, fun->getOrCreateScript(cx));
if (!script)
return false;
RootedScript script(cx, fun->nonLazyScript());
if (!script->compileAndGo() || !script->canBaselineCompile())
return true;

View File

@ -75,7 +75,7 @@ jit::NewBaselineFrameInspector(TempAllocator *temp, BaselineFrame *frame)
JSScript *script = frame->script();
if (script->function()) {
if (script->functionNonDelazifying()) {
if (!inspector->argTypes.reserve(frame->numFormalArgs()))
return nullptr;
for (size_t i = 0; i < frame->numFormalArgs(); i++) {
@ -349,10 +349,10 @@ IonBuilder::canInlineTarget(JSFunction *target, CallInfo &callInfo)
// Allow constructing lazy scripts when performing the definite properties
// analysis, as baseline has not been used to warm the caller up yet.
if (target->isInterpreted() && info().executionMode() == DefinitePropertiesAnalysis) {
if (!target->getOrCreateScript(analysisContext))
RootedScript script(analysisContext, target->getOrCreateScript(analysisContext));
if (!script)
return InliningDecision_Error;
RootedScript script(analysisContext, target->nonLazyScript());
if (!script->hasBaselineScript() && script->canBaselineCompile()) {
MethodStatus status = BaselineCompile(analysisContext, script);
if (status == Method_Error)
@ -687,7 +687,7 @@ IonBuilder::build()
return false;
// Prevent |this| from being DCE'd: necessary for constructors.
if (info().fun())
if (info().funMaybeLazy())
current->getSlot(info().thisSlot())->setGuard();
// The type analysis phase attempts to insert unbox operations near
@ -919,7 +919,7 @@ IonBuilder::rewriteParameters()
{
JS_ASSERT(info().scopeChainSlot() == 0);
if (!info().fun())
if (!info().funMaybeLazy())
return;
for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) {
@ -931,7 +931,7 @@ IonBuilder::rewriteParameters()
bool
IonBuilder::initParameters()
{
if (!info().fun())
if (!info().funMaybeLazy())
return true;
// If we are doing OSR on a frame which initially executed in the
@ -990,7 +990,7 @@ IonBuilder::initScopeChain(MDefinition *callee)
lock();
if (JSFunction *fun = info().fun()) {
if (JSFunction *fun = info().funMaybeLazy()) {
if (!callee) {
MCallee *calleeIns = MCallee::New(alloc());
current->add(calleeIns);
@ -3830,7 +3830,7 @@ class AutoAccumulateReturns
bool
IonBuilder::inlineScriptedCall(CallInfo &callInfo, JSFunction *target)
{
JS_ASSERT(target->isInterpreted());
JS_ASSERT(target->hasScript());
JS_ASSERT(IsIonInlinablePC(pc));
callInfo.setImplicitlyUsedUnchecked();
@ -5298,7 +5298,7 @@ IonBuilder::jsop_eval(uint32_t argc)
if (argc != 1)
return abort("Direct eval with more than one argument");
if (!info().fun())
if (!info().funMaybeLazy())
return abort("Direct eval in global code");
// The 'this' value for the outer and eval scripts must be the
@ -5720,7 +5720,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
osrBlock->initSlot(info().argsObjSlot(), argsObj);
}
if (info().fun()) {
if (info().funMaybeLazy()) {
// Initialize |this| parameter.
MParameter *thisv = MParameter::New(alloc(), MParameter::THIS_SLOT, nullptr);
osrBlock->add(thisv);
@ -5825,7 +5825,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
// Wrap |this| with a guaranteed use, to prevent instruction elimination.
// Prevent |this| from being DCE'd: necessary for constructors.
if (info().fun())
if (info().funMaybeLazy())
preheader->getSlot(info().thisSlot())->setGuard();
return preheader;
@ -5865,7 +5865,7 @@ IonBuilder::newPendingLoopHeader(MBasicBlock *predecessor, jsbytecode *pc, bool
types::Type existingType = types::Type::UndefinedType();
uint32_t arg = i - info().firstArgSlot();
uint32_t var = i - info().firstLocalSlot();
if (info().fun() && i == info().thisSlot())
if (info().funMaybeLazy() && i == info().thisSlot())
existingType = baselineFrame_->thisType;
else if (arg < info().nargs())
existingType = baselineFrame_->argTypes[arg];
@ -9240,10 +9240,10 @@ IonBuilder::jsop_deffun(uint32_t index)
bool
IonBuilder::jsop_this()
{
if (!info().fun())
if (!info().funMaybeLazy())
return abort("JSOP_THIS outside of a JSFunction.");
if (script()->strict() || info().fun()->isSelfHostedBuiltin()) {
if (script()->strict() || info().funMaybeLazy()->isSelfHostedBuiltin()) {
// No need to wrap primitive |this| in strict mode or self-hosted code.
current->pushSlot(info().thisSlot());
return true;
@ -9399,7 +9399,8 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall)
if (!outerScript || !outerScript->treatAsRunOnce())
return false;
types::TypeObjectKey *funType = types::TypeObjectKey::get(outerScript->function());
types::TypeObjectKey *funType =
types::TypeObjectKey::get(outerScript->functionNonDelazifying());
if (funType->hasFlags(constraints(), types::OBJECT_FLAG_RUNONCE_INVALIDATED))
return false;
@ -9415,7 +9416,7 @@ IonBuilder::hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall)
MDefinition *scope = current->getSlot(info().scopeChainSlot());
scope->setImplicitlyUsedUnchecked();
JSObject *environment = script()->function()->environment();
JSObject *environment = script()->functionNonDelazifying()->environment();
while (environment && !environment->is<GlobalObject>()) {
if (environment->is<CallObject>() &&
!environment->as<CallObject>().isForEval() &&

View File

@ -619,7 +619,7 @@ HandleException(ResumeFromException *rfe)
// the function has exited, so invoke the probe that a function
// is exiting.
JSScript *script = frames.script();
probes::ExitScript(cx, script, script->function(), popSPSFrame);
probes::ExitScript(cx, script, script->functionNonDelazifying(), popSPSFrame);
if (!frames.more())
break;
++frames;
@ -638,7 +638,7 @@ HandleException(ResumeFromException *rfe)
// Unwind profiler pseudo-stack
JSScript *script = iter.script();
probes::ExitScript(cx, script, script->function(),
probes::ExitScript(cx, script, script->functionNonDelazifying(),
iter.baselineFrame()->hasPushedSPSFrame());
// After this point, any pushed SPS frame would have been popped if it needed
// to be. Unset the flag here so that if we call DebugEpilogue below,

View File

@ -516,13 +516,13 @@ NewStringObject(JSContext *cx, HandleString str)
bool
SPSEnter(JSContext *cx, HandleScript script)
{
return cx->runtime()->spsProfiler.enter(cx, script, script->function());
return cx->runtime()->spsProfiler.enter(cx, script, script->functionNonDelazifying());
}
bool
SPSExit(JSContext *cx, HandleScript script)
{
cx->runtime()->spsProfiler.exit(cx, script, script->function());
cx->runtime()->spsProfiler.exit(cx, script, script->functionNonDelazifying());
return true;
}

View File

@ -96,7 +96,9 @@ class BaselineCompilerShared
}
JSFunction *function() const {
return script->function();
// Not delazifying here is ok as the function is guaranteed to have
// been delazified before compilation started.
return script->functionNonDelazifying();
}
PCMappingSlotInfo getStackTopSlotInfo() {

View File

@ -261,7 +261,7 @@ CodeGeneratorShared::encode(LSnapshot *snapshot)
{
MResumePoint *mir = *it;
MBasicBlock *block = mir->block();
JSFunction *fun = block->info().fun();
JSFunction *fun = block->info().funMaybeLazy();
JSScript *script = block->info().script();
jsbytecode *pc = mir->pc();
uint32_t exprStack = mir->stackDepth() - block->info().ninvoke();

View File

@ -355,7 +355,7 @@ MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 301, 0, JSEXN_SYNTAXERR, "yield in default
MSG_DEF(JSMSG_INTRINSIC_NOT_DEFINED, 302, 1, JSEXN_REFERENCEERR, "no intrinsic function {0}")
MSG_DEF(JSMSG_ALREADY_HAS_PRAGMA, 303, 2, JSEXN_ERR, "{0} is being assigned a {1}, but already has one")
MSG_DEF(JSMSG_PAR_ARRAY_BAD_ARG, 304, 0, JSEXN_RANGEERR, "invalid parallel method argument")
MSG_DEF(JSMSG_UNUSED305, 305, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_REGEXP_RUNTIME_ERROR, 305, 0, JSEXN_INTERNALERR, "an error occurred while executing regular expression")
MSG_DEF(JSMSG_UNUSED306, 306, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_UNUSED307, 307, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_PAR_ARRAY_SCATTER_CONFLICT, 308, 0, JSEXN_ERR, "no conflict resolution function provided")
@ -434,3 +434,4 @@ MSG_DEF(JSMSG_DECLARATION_AFTER_EXPORT, 379, 0, JSEXN_SYNTAXERR, "missing declar
MSG_DEF(JSMSG_INVALID_PROTOTYPE, 380, 0, JSEXN_TYPEERR, "prototype field is not an object")
MSG_DEF(JSMSG_TYPEDOBJECT_HANDLE_TO_UNSIZED, 381, 0, JSEXN_TYPEERR, "cannot create a handle to an unsized type")
MSG_DEF(JSMSG_SETPROTOTYPEOF_FAIL, 382, 0, JSEXN_TYPEERR, "[[SetPrototypeOf]] failed")
MSG_DEF(JSMSG_INVALID_ARG_TYPE, 383, 3, JSEXN_TYPEERR, "Invalid type: {0} can't be a{1} {2}")

View File

@ -225,7 +225,8 @@ static inline uint32_t ArgSlot(uint32_t arg) {
return 1 + arg;
}
static inline uint32_t LocalSlot(JSScript *script, uint32_t local) {
return 1 + (script->function() ? script->function()->nargs() : 0) + local;
return 1 + local +
(script->functionNonDelazifying() ? script->functionNonDelazifying()->nargs() : 0);
}
static inline uint32_t TotalSlots(JSScript *script) {
return LocalSlot(script, 0) + script->nfixed();

View File

@ -3984,16 +3984,16 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobjArg, JSObject *parentArg)
return nullptr;
}
/*
* If a function was compiled to be lexically nested inside some other
* script, we cannot clone it without breaking the compiler's assumptions.
*/
RootedFunction fun(cx, &funobj->as<JSFunction>());
if (fun->isInterpretedLazy()) {
AutoCompartment ac(cx, funobj);
if (!fun->getOrCreateScript(cx))
return nullptr;
}
/*
* If a function was compiled to be lexically nested inside some other
* script, we cannot clone it without breaking the compiler's assumptions.
*/
if (fun->isInterpreted() && (fun->nonLazyScript()->enclosingStaticScope() ||
(fun->nonLazyScript()->compileAndGo() && !parent->is<GlobalObject>())))
{
@ -4691,7 +4691,8 @@ JS_DecompileScript(JSContext *cx, JSScript *scriptArg, const char *name, unsigne
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
RootedScript script(cx, scriptArg);
RootedFunction fun(cx, script->function());
script->ensureNonLazyCanonicalFunction(cx);
RootedFunction fun(cx, script->functionNonDelazifying());
if (fun)
return JS_DecompileFunction(cx, fun, indent);
bool haveSource = script->scriptSource()->hasSourceData();

View File

@ -43,6 +43,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
runtime_(zone->runtimeFromMainThread()),
principals(nullptr),
isSystem(false),
isSelfHosting(false),
marked(true),
#ifdef DEBUG
firedOnNewGlobalObject(false),
@ -724,7 +725,7 @@ CreateLazyScriptsForCompartment(JSContext *cx)
// compiled.
for (gc::CellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) {
LazyScript *lazy = i.get<LazyScript>();
JSFunction *fun = lazy->function();
JSFunction *fun = lazy->functionNonDelazifying();
if (fun->compartment() == cx->compartment() &&
lazy->sourceObject() && !lazy->maybeScript())
{

View File

@ -127,6 +127,7 @@ struct JSCompartment
public:
JSPrincipals *principals;
bool isSystem;
bool isSelfHosting;
bool marked;
#ifdef DEBUG

View File

@ -455,7 +455,9 @@ js::CloneFunctionAndScript(JSContext *cx, HandleObject enclosingScope, HandleFun
if (!clone)
return nullptr;
RootedScript srcScript(cx, srcFun->nonLazyScript());
RootedScript srcScript(cx, srcFun->getOrCreateScript(cx));
if (!srcScript)
return nullptr;
RootedScript clonedScript(cx, CloneScript(cx, enclosingScope, clone, srcScript));
if (!clonedScript)
return nullptr;
@ -522,11 +524,30 @@ JSFunction::trace(JSTracer *trc)
if (isInterpreted()) {
// Functions can be be marked as interpreted despite having no script
// yet at some points when parsing, and can be lazy with no lazy script
// for self hosted code.
if (hasScript() && u.i.s.script_)
MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
else if (isInterpretedLazy() && u.i.s.lazy_)
// for self-hosted code.
if (hasScript() && u.i.s.script_) {
// Functions can be relazified under the following conditions:
// - their compartment isn't currently executing scripts or being
// debugged
// - they are not in the self-hosting compartment
// - they aren't generators
// - they don't have JIT code attached
// - they don't have child functions
// - they have information for un-lazifying them again later
// This information can either be a LazyScript, or the name of a
// self-hosted function which can be cloned over again. The latter
// is stored in the first extended slot.
if (IS_GC_MARKING_TRACER(trc) && !compartment()->hasBeenEntered() &&
!compartment()->debugMode() && !compartment()->isSelfHosting &&
u.i.s.script_->isRelazifiable() && (!isSelfHostedBuiltin() || isExtended()))
{
relazify(trc);
} else {
MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
}
} else if (isInterpretedLazy() && u.i.s.lazy_) {
MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript");
}
if (u.i.env_)
MarkObjectUnbarriered(trc, &u.i.env_, "fun_callscope");
}
@ -1126,11 +1147,18 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
if (script) {
AutoLockForCompilation lock(cx);
fun->setUnlazifiedScript(script);
// Remember the lazy script on the compiled script, so it can be
// stored on the function again in case of re-lazification.
// Only functions without inner functions are re-lazified.
if (!lazy->numInnerFunctions())
script->setLazyScript(lazy);
return true;
}
if (fun != lazy->function()) {
script = lazy->function()->getOrCreateScript(cx);
if (fun != lazy->functionNonDelazifying()) {
if (!lazy->functionDelazifying(cx))
return false;
script = lazy->functionNonDelazifying()->nonLazyScript();
if (!script)
return false;
@ -1160,7 +1188,7 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
clonedScript->setSourceObject(lazy->sourceObject());
fun->initAtom(script->function()->displayAtom());
fun->initAtom(script->functionNonDelazifying()->displayAtom());
clonedScript->setFunction(fun);
{
@ -1170,7 +1198,8 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
CallNewScriptHook(cx, clonedScript, fun);
lazy->initScript(clonedScript);
if (!lazy->maybeScript())
lazy->initScript(clonedScript);
return true;
}
@ -1190,6 +1219,11 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
script = fun->nonLazyScript();
// Remember the compiled script on the lazy script itself, in case
// there are clones of the function still pointing to the lazy script.
if (!lazy->maybeScript())
lazy->initScript(script);
// Try to insert the newly compiled script into the lazy script cache.
if (!lazy->numInnerFunctions()) {
// A script's starting column isn't set by the bytecode emitter, so
@ -1199,15 +1233,17 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
LazyScriptCache::Lookup lookup(cx, lazy);
cx->runtime()->lazyScriptCache.insert(lookup, script);
}
// Remember the compiled script on the lazy script itself, in case
// there are clones of the function still pointing to the lazy script.
lazy->initScript(script);
// Remember the lazy script on the compiled script, so it can be
// stored on the function again in case of re-lazification.
// Only functions without inner functions are re-lazified.
script->setLazyScript(lazy);
}
return true;
}
/* Lazily cloned self hosted script. */
/* Lazily cloned self-hosted script. */
JS_ASSERT(fun->isSelfHostedBuiltin());
RootedAtom funAtom(cx, &fun->getExtendedSlot(0).toString()->asAtom());
if (!funAtom)
return false;
@ -1215,6 +1251,45 @@ JSFunction::createScriptForLazilyInterpretedFunction(JSContext *cx, HandleFuncti
return cx->runtime()->cloneSelfHostedFunctionScript(cx, funName, fun);
}
void
JSFunction::relazify(JSTracer *trc)
{
JSScript *script = nonLazyScript();
JS_ASSERT(script->isRelazifiable());
JS_ASSERT(!compartment()->hasBeenEntered());
JS_ASSERT(!compartment()->debugMode());
// If the script's canonical function isn't lazy, we have to mark the
// script. Otherwise, the following scenario would leave it unmarked
// and cause it to be swept while a function is still expecting it to be
// valid:
// 1. an incremental GC slice causes the canonical function to relazify
// 2. a clone is used and delazifies the canonical function
// 3. another GC slice causes the clone to relazify
// The result is that no function marks the script, but the canonical
// function expects it to be valid.
if (script->functionNonDelazifying()->hasScript())
MarkScriptUnbarriered(trc, &u.i.s.script_, "script");
flags_ &= ~INTERPRETED;
flags_ |= INTERPRETED_LAZY;
LazyScript *lazy = script->maybeLazyScript();
u.i.s.lazy_ = lazy;
if (lazy) {
JS_ASSERT(!isSelfHostedBuiltin());
// If this is the script stored in the lazy script to be cloned
// for un-lazifying other functions, reset it so the script can
// be freed.
if (lazy->maybeScript() == script)
lazy->resetScript();
MarkLazyScriptUnbarriered(trc, &u.i.s.lazy_, "lazyScript");
} else {
JS_ASSERT(isSelfHostedBuiltin());
JS_ASSERT(isExtended());
JS_ASSERT(getExtendedSlot(0).toString()->isAtom());
}
}
/* ES5 15.3.4.5.1 and 15.3.4.5.2. */
bool
js::CallOrConstructBoundFunction(JSContext *cx, unsigned argc, Value *vp)

View File

@ -279,6 +279,7 @@ class JSFunction : public JSObject
static inline size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
static bool createScriptForLazilyInterpretedFunction(JSContext *cx, js::HandleFunction fun);
void relazify(JSTracer *trc);
// Function Scripts
//
@ -308,11 +309,9 @@ class JSFunction : public JSObject
JS::RootedFunction self(cx, this);
if (!createScriptForLazilyInterpretedFunction(cx, self))
return nullptr;
JS_ASSERT(self->hasScript());
return self->u.i.s.script_;
return self->nonLazyScript();
}
JS_ASSERT(hasScript());
return u.i.s.script_;
return nonLazyScript();
}
JSScript *existingScript() {
@ -329,14 +328,14 @@ class JSFunction : public JSObject
flags_ |= INTERPRETED;
initScript(script);
}
JS_ASSERT(hasScript());
return u.i.s.script_;
return nonLazyScript();
}
JSScript *nonLazyScript() const {
js::AutoThreadSafeAccess ts(this);
JS_ASSERT(hasScript());
JS_ASSERT(js::CurrentThreadCanReadCompilationData());
JS_ASSERT(hasScript());
JS_ASSERT(u.i.s.script_);
return u.i.s.script_;
}
@ -391,6 +390,8 @@ class JSFunction : public JSObject
// lazy script before it is overwritten here.
JS_ASSERT(js::CurrentThreadCanWriteCompilationData());
JS_ASSERT(isInterpretedLazy());
if (!lazyScript()->maybeScript())
lazyScript()->initScript(script);
flags_ &= ~INTERPRETED_LAZY;
flags_ |= INTERPRETED;
initScript(script);

View File

@ -706,7 +706,7 @@ TypeScript::FreezeTypeSets(CompilerConstraintList *constraints, JSScript *script
}
*pThisTypes = types + (ThisTypes(script) - existing);
*pArgTypes = (script->function() && script->function()->nargs())
*pArgTypes = (script->functionNonDelazifying() && script->functionNonDelazifying()->nargs())
? (types + (ArgTypes(script, 0) - existing))
: nullptr;
*pBytecodeTypes = types;
@ -1001,7 +1001,9 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
if (!CheckFrozenTypeSet(cx, entry.thisTypes, types::TypeScript::ThisTypes(entry.script)))
succeeded = false;
unsigned nargs = entry.script->function() ? entry.script->function()->nargs() : 0;
unsigned nargs = entry.script->functionNonDelazifying()
? entry.script->functionNonDelazifying()->nargs()
: 0;
for (size_t i = 0; i < nargs; i++) {
if (!CheckFrozenTypeSet(cx, &entry.argTypes[i], types::TypeScript::ArgTypes(entry.script, i)))
succeeded = false;
@ -1065,7 +1067,9 @@ types::FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *c
JS_ASSERT(TypeScript::ThisTypes(script)->isSubset(entry.thisTypes));
unsigned nargs = script->function() ? script->function()->nargs() : 0;
unsigned nargs = entry.script->functionNonDelazifying()
? entry.script->functionNonDelazifying()->nargs()
: 0;
for (size_t j = 0; j < nargs; j++)
JS_ASSERT(TypeScript::ArgTypes(script, j)->isSubset(&entry.argTypes[j]));
@ -1081,7 +1085,9 @@ types::FinishDefinitePropertiesAnalysis(JSContext *cx, CompilerConstraintList *c
CheckDefinitePropertiesTypeSet(cx, entry.thisTypes, TypeScript::ThisTypes(script));
unsigned nargs = script->function() ? script->function()->nargs() : 0;
unsigned nargs = script->functionNonDelazifying()
? script->functionNonDelazifying()->nargs()
: 0;
for (size_t j = 0; j < nargs; j++)
CheckDefinitePropertiesTypeSet(cx, &entry.argTypes[j], TypeScript::ArgTypes(script, j));
@ -2063,7 +2069,7 @@ types::UseNewTypeForInitializer(JSScript *script, jsbytecode *pc, JSProtoKey key
* arrays, but not normal arrays.
*/
if (script->function() && !script->treatAsRunOnce())
if (script->functionNonDelazifying() && !script->treatAsRunOnce())
return GenericObject;
if (key != JSProto_Object && !(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
@ -2279,8 +2285,8 @@ TypeZone::addPendingRecompile(JSContext *cx, JSScript *script)
// When one script is inlined into another the caller listens to state
// changes on the callee's script, so trigger these to force recompilation
// of any such callers.
if (script->function() && !script->function()->hasLazyType())
ObjectStateChange(cx, script->function()->type(), false);
if (script->functionNonDelazifying() && !script->functionNonDelazifying()->hasLazyType())
ObjectStateChange(cx, script->functionNonDelazifying()->type(), false);
}
void
@ -3402,7 +3408,7 @@ types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
// This ensures that the inlining performed when the definite properties
// analysis was done is stable.
TypeObjectKey *calleeKey = Type::ObjectType(calleeScript->function()).objectKey();
TypeObjectKey *calleeKey = Type::ObjectType(calleeScript->functionNonDelazifying()).objectKey();
unsigned count = TypeScript::NumTypeSets(script);
StackTypeSet *typeArray = script->types->typeArray();
@ -3696,7 +3702,7 @@ JSScript::makeTypes(JSContext *cx)
InferSpew(ISpewOps, "typeSet: %sT%p%s this #%u",
InferSpewColor(thisTypes), thisTypes, InferSpewColorReset(),
id());
unsigned nargs = function() ? function()->nargs() : 0;
unsigned nargs = functionNonDelazifying() ? functionNonDelazifying()->nargs() : 0;
for (unsigned i = 0; i < nargs; i++) {
TypeSet *types = TypeScript::ArgTypes(this, i);
InferSpew(ISpewOps, "typeSet: %sT%p%s arg%u #%u",
@ -3980,9 +3986,9 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
// Canonicalize new functions to use the original one associated with its script.
if (fun) {
if (fun->hasScript())
fun = fun->nonLazyScript()->function();
fun = fun->nonLazyScript()->functionNonDelazifying();
else if (fun->isInterpretedLazy())
fun = fun->lazyScript()->function();
fun = fun->lazyScript()->functionNonDelazifying();
else
fun = nullptr;
}
@ -4570,7 +4576,7 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
AutoEnterAnalysis enter(nullptr, script->compartment());
if (script->function())
if (script->functionNonDelazifying())
fprintf(stderr, "Function");
else if (script->isForEval())
fprintf(stderr, "Eval");
@ -4578,8 +4584,8 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
fprintf(stderr, "Main");
fprintf(stderr, " #%u %s:%d ", script->id(), script->filename(), (int) script->lineno());
if (script->function()) {
if (js::PropertyName *name = script->function()->name()) {
if (script->functionNonDelazifying()) {
if (js::PropertyName *name = script->functionNonDelazifying()->name()) {
const jschar *chars = name->getChars(nullptr);
JSString::dumpChars(chars, name->length());
}
@ -4588,7 +4594,10 @@ TypeScript::printTypes(JSContext *cx, HandleScript script) const
fprintf(stderr, "\n this:");
TypeScript::ThisTypes(script)->print();
for (unsigned i = 0; script->function() && i < script->function()->nargs(); i++) {
for (unsigned i = 0;
script->functionNonDelazifying() && i < script->functionNonDelazifying()->nargs();
i++)
{
fprintf(stderr, "\n arg%u:", i);
TypeScript::ArgTypes(script, i)->print();
}

Some files were not shown because too many files have changed in this diff Show More