This commit is contained in:
Ryan VanderMeulen 2014-01-30 16:40:31 -05:00
Родитель 9b73303b7f 997a649ab0
Коммит 36edb17218
222 изменённых файлов: 3740 добавлений и 1206 удалений

Просмотреть файл

@ -578,6 +578,7 @@ pref("dom.sysmsg.enabled", true);
pref("media.plugins.enabled", false);
pref("media.omx.enabled", true);
pref("media.rtsp.enabled", true);
pref("media.rtsp.video.enabled", false);
// Disable printing (particularly, window.print())
pref("dom.disable_window_print", true);

Просмотреть файл

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

Просмотреть файл

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ff2eb11982b9d3c7a3333900cf0d3a5c0f77e32"/>

Просмотреть файл

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

Просмотреть файл

@ -1,4 +1,4 @@
{
"revision": "d369bbb3b7c415097c7c1fa303843cf5683cd843",
"revision": "7240a5ab28eff83c26891c7a9141613149f226e9",
"repo_path": "/integration/gaia-central"
}

Просмотреть файл

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

Просмотреть файл

@ -10,7 +10,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

Просмотреть файл

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

Просмотреть файл

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

Просмотреть файл

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="e33ea242b4328fb0d1824c951f379332b5021512"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0ff2eb11982b9d3c7a3333900cf0d3a5c0f77e32"/>

Просмотреть файл

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="61866f17977a440a3297aa8ade8f410c68d2cdd7"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="09064f43116d1b965cb3ab6516fa0f1fa3c98a4c"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

Просмотреть файл

@ -5221,12 +5221,23 @@ function UpdateCurrentCharset(target) {
pref_item.setAttribute('checked', 'false');
}
var menuitem = charsetMenuGetElement(target, "charset." + wnd.document.characterSet);
var menuitem = charsetMenuGetElement(target, "charset." + FoldCharset(wnd.document.characterSet));
if (menuitem) {
menuitem.setAttribute('checked', 'true');
}
}
function FoldCharset(charset) {
// For substantially similar encodings, treat two encodings as the same
// for the purpose of the check mark.
if (charset == "ISO-8859-8-I") {
return "windows-1255";
} else if (charset == "gb18030") {
return "gbk";
}
return charset;
}
function UpdateCharsetDetector(target) {
var prefvalue;
@ -5249,7 +5260,7 @@ function UpdateMenus(event) {
}
function charsetLoadListener() {
var charset = window.content.document.characterSet;
var charset = FoldCharset(window.content.document.characterSet);
if (charset.length > 0 && (charset != gLastBrowserCharset)) {
gPrevCharset = gLastBrowserCharset;

Просмотреть файл

@ -10,6 +10,7 @@
#include "ThreeDPoint.h"
#include "AudioChannelFormat.h"
#include "AudioParamTimeline.h"
#include "AudioContext.h"
using namespace mozilla::dom;
@ -30,7 +31,7 @@ AudioNodeStream::~AudioNodeStream()
}
void
AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, MediaStream* aRelativeToStream,
AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, AudioContext* aContext,
double aStreamTime)
{
class Message : public ControlMessage {
@ -50,7 +51,9 @@ AudioNodeStream::SetStreamTimeParameter(uint32_t aIndex, MediaStream* aRelativeT
};
MOZ_ASSERT(this);
GraphImpl()->AppendMessage(new Message(this, aIndex, aRelativeToStream, aStreamTime));
GraphImpl()->AppendMessage(new Message(this, aIndex,
aContext->DestinationStream(),
aContext->DOMTimeToStreamTime(aStreamTime)));
}
void
@ -407,7 +410,12 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
uint16_t outputCount = std::max(uint16_t(1), mEngine->OutputCount());
mLastChunks.SetLength(outputCount);
if (mMuted || IsFinishedOnGraphThread()) {
// Consider this stream blocked if it has already finished output. Normally
// mBlocked would reflect this, but due to rounding errors our audio track may
// appear to extend slightly beyond aFrom, so we might not be blocked yet.
bool blocked = mFinished || mBlocked.GetAt(aFrom);
// If the stream has finished at this time, it will be blocked.
if (mMuted || blocked) {
for (uint16_t i = 0; i < outputCount; ++i) {
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
}
@ -439,16 +447,16 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags)
if (finished) {
mMarkAsFinishedAfterThisBlock = true;
}
}
if (mDisabledTrackIDs.Contains(static_cast<TrackID>(AUDIO_TRACK))) {
for (uint32_t i = 0; i < mLastChunks.Length(); ++i) {
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
if (mDisabledTrackIDs.Contains(static_cast<TrackID>(AUDIO_TRACK))) {
for (uint32_t i = 0; i < outputCount; ++i) {
mLastChunks[i].SetNull(WEBAUDIO_BLOCK_SIZE);
}
}
}
if (!IsFinishedOnGraphThread()) {
// Don't output anything after we've finished!
if (!blocked) {
// Don't output anything while blocked
AdvanceOutputSegment();
if (mMarkAsFinishedAfterThisBlock && (aFlags & ALLOW_FINISH)) {
// This stream was finished the last time that we looked at it, and all

Просмотреть файл

@ -16,6 +16,7 @@ namespace dom {
struct ThreeDPoint;
class AudioParamTimeline;
class DelayNodeEngine;
class AudioContext;
}
class ThreadSharedFloatArrayBufferList;
@ -33,6 +34,8 @@ class AudioNodeEngine;
*/
class AudioNodeStream : public ProcessedMediaStream {
public:
typedef mozilla::dom::AudioContext AudioContext;
enum { AUDIO_TRACK = 1 };
typedef nsAutoTArray<AudioChunk, 1> OutputChunks;
@ -66,7 +69,7 @@ public:
* Sets a parameter that's a time relative to some stream's played time.
* This time is converted to a time relative to this stream when it's set.
*/
void SetStreamTimeParameter(uint32_t aIndex, MediaStream* aRelativeToStream,
void SetStreamTimeParameter(uint32_t aIndex, AudioContext* aContext,
double aStreamTime);
void SetDoubleParameter(uint32_t aIndex, double aValue);
void SetInt32Parameter(uint32_t aIndex, int32_t aValue);

Просмотреть файл

@ -172,7 +172,8 @@ class MediaRecorder::Session: public nsIObserver
// We need to switch MediaRecorder to "Stop" state first to make sure
// MediaRecorder is not associated with this Session anymore, then, it's
// safe to delete this Session.
if (recorder->mState != RecordingState::Inactive) {
// Also avoid to run if this session already call stop before
if (!mSession->mStopIssued) {
ErrorResult result;
recorder->Stop(result);
NS_DispatchToMainThread(new DestroyRunnable(mSession.forget()));
@ -182,8 +183,8 @@ class MediaRecorder::Session: public nsIObserver
// Dispatch stop event and clear MIME type.
recorder->DispatchSimpleEvent(NS_LITERAL_STRING("stop"));
recorder->SetMimeType(NS_LITERAL_STRING(""));
mSession->mMimeType = NS_LITERAL_STRING("");
recorder->SetMimeType(mSession->mMimeType);
return NS_OK;
}
@ -200,7 +201,8 @@ class MediaRecorder::Session: public nsIObserver
public:
Session(MediaRecorder* aRecorder, int32_t aTimeSlice)
: mRecorder(aRecorder),
mTimeSlice(aTimeSlice)
mTimeSlice(aTimeSlice),
mStopIssued(false)
{
MOZ_ASSERT(NS_IsMainThread());
@ -226,6 +228,7 @@ public:
{
MOZ_ASSERT(NS_IsMainThread());
mStopIssued = true;
CleanupStreams();
nsContentUtils::UnregisterShutdownObserver(this);
}
@ -248,10 +251,7 @@ public:
already_AddRefed<nsIDOMBlob> GetEncodedData()
{
nsString mimeType;
mRecorder->GetMimeType(mimeType);
return mEncodedBufferCache->ExtractBlob(mimeType);
return mEncodedBufferCache->ExtractBlob(mMimeType);
}
bool IsEncoderError()
@ -274,10 +274,8 @@ private:
// Pull encoded media data from MediaEncoder
nsTArray<nsTArray<uint8_t> > encodedBuf;
nsString mimeType;
mEncoder->GetEncodedData(&encodedBuf, mimeType);
mRecorder->SetMimeType(mimeType);
mEncoder->GetEncodedData(&encodedBuf, mMimeType);
mRecorder->SetMimeType(mMimeType);
// Append pulled data into cache buffer.
for (uint32_t i = 0; i < encodedBuf.Length(); i++) {
@ -325,8 +323,10 @@ private:
return;
}
// media stream is ready but has been issued stop command
if (mRecorder->mState == RecordingState::Inactive) {
// Media stream is ready but UA issues a stop method follow by start method.
// The Session::stop would clean the mTrackUnionStream. If the AfterTracksAdded
// comes after stop command, this function would crash.
if (!mTrackUnionStream) {
DoSessionEndTask(NS_OK);
return;
}
@ -400,6 +400,8 @@ private:
nsRefPtr<MediaEncoder> mEncoder;
// A buffer to cache encoded meda data.
nsAutoPtr<EncodedBufferCache> mEncodedBufferCache;
// Current session mimeType
nsString mMimeType;
// Timestamp of the last fired dataavailable event.
TimeStamp mLastBlobTimeStamp;
// The interval of passing encoded data from EncodedBufferCache to onDataAvailable
@ -407,6 +409,8 @@ private:
// onDataAvailable, instead, it passive wait the client side pull encoded data
// by calling requestData API.
const int32_t mTimeSlice;
// Indicate this session's stop has been called.
bool mStopIssued;
};
NS_IMPL_ISUPPORTS1(MediaRecorder::Session, nsIObserver)

Просмотреть файл

@ -1116,6 +1116,28 @@ MediaStreamGraphImpl::AllFinishedStreamsNotified()
return true;
}
void
MediaStreamGraphImpl::PauseAllAudioOutputs()
{
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
MediaStream* s = mStreams[i];
for (uint32_t j = 0; j < s->mAudioOutputStreams.Length(); ++j) {
s->mAudioOutputStreams[j].mStream->Pause();
}
}
}
void
MediaStreamGraphImpl::ResumeAllAudioOutputs()
{
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
MediaStream* s = mStreams[i];
for (uint32_t j = 0; j < s->mAudioOutputStreams.Length(); ++j) {
s->mAudioOutputStreams[j].mStream->Resume();
}
}
}
void
MediaStreamGraphImpl::RunThread()
{
@ -1180,7 +1202,6 @@ MediaStreamGraphImpl::RunThread()
RecomputeBlocking(endBlockingDecisions);
// Play stream contents.
uint32_t audioStreamsActive = 0;
bool allBlockedForever = true;
// True when we've done ProduceOutput for all processed streams.
bool doneAllProducing = false;
@ -1221,7 +1242,6 @@ MediaStreamGraphImpl::RunThread()
// Only playback audio and video in real-time mode
CreateOrDestroyAudioStreams(prevComputedTime, stream);
PlayAudio(stream, prevComputedTime, mStateComputedTime);
audioStreamsActive += stream->mAudioOutputStreams.Length();
PlayVideo(stream);
}
SourceMediaStream* is = stream->AsSourceStream();
@ -1233,7 +1253,7 @@ MediaStreamGraphImpl::RunThread()
allBlockedForever = false;
}
}
if (ensureNextIteration || !allBlockedForever || audioStreamsActive > 0) {
if (ensureNextIteration || !allBlockedForever) {
EnsureNextIteration();
}
@ -1261,6 +1281,7 @@ MediaStreamGraphImpl::RunThread()
if (mRealtime) {
PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
TimeStamp now = TimeStamp::Now();
bool pausedOutputs = false;
if (mNeedAnotherIteration) {
int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
int64_t((now - mCurrentTimeStamp).ToMilliseconds());
@ -1273,6 +1294,8 @@ MediaStreamGraphImpl::RunThread()
mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
} else {
mWaitState = WAITSTATE_WAITING_INDEFINITELY;
PauseAllAudioOutputs();
pausedOutputs = true;
}
if (timeout > 0) {
mMonitor.Wait(timeout);
@ -1280,6 +1303,9 @@ MediaStreamGraphImpl::RunThread()
(TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
(TimeStamp::Now() - now).ToSeconds()));
}
if (pausedOutputs) {
ResumeAllAudioOutputs();
}
}
mWaitState = WAITSTATE_RUNNING;
mNeedAnotherIteration = false;
@ -1531,7 +1557,8 @@ MediaStreamGraphImpl::RunInStableState()
}
}
if (mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
if (mForceShutDown &&
mLifecycleState == LIFECYCLE_WAITING_FOR_MAIN_THREAD_CLEANUP) {
// Defer calls to RunDuringShutdown() to happen while mMonitor is not held.
for (uint32_t i = 0; i < mMessageQueue.Length(); ++i) {
MessageBlock& mb = mMessageQueue[i];

Просмотреть файл

@ -370,6 +370,14 @@ public:
{
mStreamOrderDirty = true;
}
/**
* Pause all AudioStreams being written to by MediaStreams
*/
void PauseAllAudioOutputs();
/**
* Resume all AudioStreams being written to by MediaStreams
*/
void ResumeAllAudioOutputs();
// Data members

Просмотреть файл

@ -440,6 +440,32 @@ RtspMediaResource::OnMediaDataAvailable(uint8_t aTrackIdx,
return NS_OK;
}
// Bug 962309 - Video RTSP support should be disabled in 1.3
bool
RtspMediaResource::IsVideoEnabled()
{
return Preferences::GetBool("media.rtsp.video.enabled", false);
}
bool
RtspMediaResource::IsVideo(uint8_t tracks, nsIStreamingProtocolMetaData *meta)
{
bool isVideo = false;
for (int i = 0; i < tracks; ++i) {
nsCOMPtr<nsIStreamingProtocolMetaData> trackMeta;
mMediaStreamController->GetTrackMetaData(i, getter_AddRefs(trackMeta));
MOZ_ASSERT(trackMeta);
uint32_t w = 0, h = 0;
trackMeta->GetWidth(&w);
trackMeta->GetHeight(&h);
if (w > 0 || h > 0) {
isVideo = true;
break;
}
}
return isVideo;
}
nsresult
RtspMediaResource::OnConnected(uint8_t aTrackIdx,
nsIStreamingProtocolMetaData *meta)
@ -453,6 +479,16 @@ RtspMediaResource::OnConnected(uint8_t aTrackIdx,
uint8_t tracks;
mMediaStreamController->GetTotalTracks(&tracks);
// If the preference of RTSP video feature is not enabled and the streaming is
// video, we give up moving forward.
if (!IsVideoEnabled() && IsVideo(tracks, meta)) {
// Give up, report error to media element.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
return NS_ERROR_FAILURE;
}
uint64_t duration = 0;
for (int i = 0; i < tracks; ++i) {
nsCString rtspTrackId("RtspTrack");
@ -540,10 +576,9 @@ RtspMediaResource::OnDisconnected(uint8_t aTrackIdx, nsresult aReason)
if (aReason == NS_ERROR_NOT_INITIALIZED ||
aReason == NS_ERROR_CONNECTION_REFUSED ||
aReason == NS_ERROR_NOT_CONNECTED) {
aReason == NS_ERROR_NOT_CONNECTED ||
aReason == NS_ERROR_NET_TIMEOUT) {
RTSPMLOG("Error in OnDisconnected 0x%x", aReason);
mDecoder->NetworkError();
return NS_OK;
}

Просмотреть файл

@ -216,6 +216,8 @@ protected:
nsRefPtr<Listener> mListener;
private:
bool IsVideoEnabled();
bool IsVideo(uint8_t tracks, nsIStreamingProtocolMetaData *meta);
// These two members are created at |RtspMediaResource::OnConnected|.
nsCOMPtr<nsIStreamingProtocolController> mMediaStreamController;
nsTArray<nsAutoPtr<RtspTrackBuffer>> mTrackBuffer;

Просмотреть файл

@ -89,6 +89,7 @@ public:
}
mStartTime = aStartTime;
mReset = true;
CueChanged();
}
@ -104,6 +105,7 @@ public:
}
mEndTime = aEndTime;
mReset = true;
CueChanged();
}

Просмотреть файл

@ -44,6 +44,9 @@ protected:
* The implementation records a mCurrent (the value at the current time)
* and an array of "change times" (greater than the current time) and the
* new value for each change time. This is a simple but dumb implementation.
* We maintain the invariant that each change entry in the array must have
* a different value to the value in the previous change entry (or, for
* the first change entry, mCurrent).
*/
template <typename Time, typename T, uint32_t ReservedChanges>
class TimeVarying : public TimeVaryingBase {
@ -79,6 +82,9 @@ public:
}
mChanges.RemoveElementAt(i);
}
if (mCurrent == aValue) {
return;
}
mChanges.InsertElementAt(0, Entry(aTime, aValue));
}
/**

Просмотреть файл

@ -24,8 +24,8 @@ public:
virtual ~ContainerWriter() {}
// Mapping to DOMLocalMediaStream::TrackTypeHints
enum {
HAS_AUDIO = 1 << 0,
HAS_VIDEO = 1 << 1,
CREATE_AUDIO_TRACK = 1 << 0,
CREATE_VIDEO_TRACK = 1 << 1,
};
enum {
END_OF_STREAM = 1 << 0

Просмотреть файл

@ -56,14 +56,25 @@ public:
AVC_CSD, // AVC codec specific data
UNKNOW // FrameType not set
};
nsresult SwapInFrameData(nsTArray<uint8_t>& aData)
{
mFrameData.SwapElements(aData);
return NS_OK;
}
nsresult SwapOutFrameData(nsTArray<uint8_t>& aData)
{
if (mFrameType != UNKNOW) {
// Reset this frame type to UNKNOW once the data is swapped out.
mFrameData.SwapElements(aData);
mFrameType = UNKNOW;
return NS_OK;
}
return NS_ERROR_FAILURE;
}
const nsTArray<uint8_t>& GetFrameData() const
{
return mFrameData;
}
void SetFrameData(nsTArray<uint8_t> *aData)
{
mFrameData.SwapElements(*aData);
}
uint64_t GetTimeStamp() const { return mTimeStamp; }
void SetTimeStamp(uint64_t aTimeStamp) { mTimeStamp = aTimeStamp; }

Просмотреть файл

@ -100,8 +100,8 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes)
#ifdef MOZ_WEBM_ENCODER
else if (MediaEncoder::IsWebMEncoderEnabled() &&
(aMIMEType.EqualsLiteral(VIDEO_WEBM) ||
(aTrackTypes & ContainerWriter::HAS_VIDEO))) {
if (aTrackTypes & ContainerWriter::HAS_AUDIO) {
(aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) {
if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK) {
audioEncoder = new VorbisTrackEncoder();
NS_ENSURE_TRUE(audioEncoder, nullptr);
}
@ -115,8 +115,8 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes)
#ifdef MOZ_OMX_ENCODER
else if (MediaEncoder::IsOMXEncoderEnabled() &&
(aMIMEType.EqualsLiteral(VIDEO_MP4) ||
(aTrackTypes & ContainerWriter::HAS_VIDEO))) {
if (aTrackTypes & ContainerWriter::HAS_AUDIO) {
(aTrackTypes & ContainerWriter::CREATE_VIDEO_TRACK))) {
if (aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK) {
audioEncoder = new OmxAudioTrackEncoder();
NS_ENSURE_TRUE(audioEncoder, nullptr);
}
@ -130,7 +130,7 @@ MediaEncoder::CreateEncoder(const nsAString& aMIMEType, uint8_t aTrackTypes)
#ifdef MOZ_OGG
else if (MediaDecoder::IsOggEnabled() && MediaDecoder::IsOpusEnabled() &&
(aMIMEType.EqualsLiteral(AUDIO_OGG) ||
(aTrackTypes & ContainerWriter::HAS_AUDIO))) {
(aTrackTypes & ContainerWriter::CREATE_AUDIO_TRACK))) {
writer = new OggWriter();
audioEncoder = new OpusTrackEncoder();
NS_ENSURE_TRUE(writer, nullptr);

Просмотреть файл

@ -93,7 +93,7 @@ public :
* Ogg+Opus if it is empty.
*/
static already_AddRefed<MediaEncoder> CreateEncoder(const nsAString& aMIMEType,
uint8_t aTrackTypes = ContainerWriter::HAS_AUDIO);
uint8_t aTrackTypes = ContainerWriter::CREATE_AUDIO_TRACK);
/**
* Encodes the raw track data and returns the final container data. Assuming
* it is called on a single worker thread. The buffer of container data is

Просмотреть файл

@ -121,6 +121,7 @@ OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
}
// Dequeue an encoded frame from the output buffers of OMXCodecWrapper.
nsresult rv;
nsTArray<uint8_t> buffer;
int outFlags = 0;
int64_t outTimeStampUs = 0;
@ -134,7 +135,8 @@ OmxVideoTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
videoData->SetFrameType((outFlags & OMXCodecWrapper::BUFFER_SYNC_FRAME) ?
EncodedFrame::I_FRAME : EncodedFrame::P_FRAME);
}
videoData->SetFrameData(&buffer);
rv = videoData->SwapInFrameData(buffer);
NS_ENSURE_SUCCESS(rv, rv);
videoData->SetTimeStamp(outTimeStampUs);
aData.AppendEncodedFrame(videoData);
}
@ -213,7 +215,8 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer)
audiodata->SetFrameType(isCSD ?
EncodedFrame::AAC_CSD : EncodedFrame::AUDIO_FRAME);
audiodata->SetTimeStamp(outTimeUs);
audiodata->SetFrameData(&frameData);
rv = audiodata->SwapInFrameData(frameData);
NS_ENSURE_SUCCESS(rv, rv);
aContainer.AppendEncodedFrame(audiodata);
}

Просмотреть файл

@ -374,7 +374,7 @@ OpusTrackEncoder::GetEncodedTrack(EncodedFrameContainer& aData)
}
}
audiodata->SetFrameData(&frameData);
audiodata->SwapInFrameData(frameData);
aData.AppendEncodedFrame(audiodata);
return result >= 0 ? NS_OK : NS_ERROR_FAILURE;
}

Просмотреть файл

@ -164,6 +164,7 @@ VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
vpx_codec_iter_t iter = nullptr;
EncodedFrame::FrameType frameType = EncodedFrame::P_FRAME;
nsTArray<uint8_t> frameData;
nsresult rv;
const vpx_codec_cx_pkt_t *pkt = nullptr;
while ((pkt = vpx_codec_get_cx_data(mVPXContext, &iter)) != nullptr) {
switch (pkt->kind) {
@ -202,7 +203,8 @@ VP8TrackEncoder::GetEncodedPartitions(EncodedFrameContainer& aData)
videoData->SetDuration(
(uint64_t)FramesToUsecs(pkt->data.frame.duration, mTrackRate).value());
}
videoData->SetFrameData(&frameData);
rv = videoData->SwapInFrameData(frameData);
NS_ENSURE_SUCCESS(rv, rv);
VP8LOG("GetEncodedPartitions TimeStamp %lld Duration %lld\n",
videoData->GetTimeStamp(), videoData->GetDuration());
VP8LOG("frameType %d\n", videoData->GetFrameType());

Просмотреть файл

@ -147,7 +147,7 @@ VorbisTrackEncoder::GetEncodedFrames(EncodedFrameContainer& aData)
audiodata->SetFrameType(EncodedFrame::AUDIO_FRAME);
nsTArray<uint8_t> frameData;
frameData.AppendElements(oggPacket.packet, oggPacket.bytes);
audiodata->SetFrameData(&frameData);
audiodata->SwapInFrameData(frameData);
aData.AppendEncodedFrame(audiodata);
}
}

Просмотреть файл

@ -28,10 +28,10 @@ ISOMediaWriter::ISOMediaWriter(uint32_t aType)
, mBlobReady(false)
, mType(0)
{
if (aType & HAS_AUDIO) {
if (aType & CREATE_AUDIO_TRACK) {
mType |= Audio_Track;
}
if (aType & HAS_VIDEO) {
if (aType & CREATE_VIDEO_TRACK) {
mType |= Video_Track;
}
mControl = new ISOControl();

Просмотреть файл

@ -256,6 +256,7 @@ support-files =
[test_mediarecorder_reload_crash.html]
[test_mediarecorder_record_immediate_stop.html]
[test_mediarecorder_record_session.html]
[test_mediarecorder_record_startstopstart.html]
[test_mediarecorder_unsupported_src.html]
[test_playback.html]
[test_seekLies.html]

Просмотреть файл

@ -0,0 +1,76 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test MediaRecorder crash on sequence start stop start method</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<div id="content" style="display: none">
</div>
<script class="testbody" type="text/javascript">
function startTest() {
var ac = new window.AudioContext();
var dest = ac.createMediaStreamDestination();
var recorder = new MediaRecorder(dest.stream);
var stopCount = 0;
var dataavailable = 0;
// mobile device may produce another format, but not landed.
// In audio only case, we should produce opus type.
var expectedMimeType = 'audio/ogg';
recorder.onstop = function (e) {
info('onstop fired');
is(recorder.stream, dest.stream,
'Media recorder stream = element stream post recording');
stopCount++;
if (stopCount == 2) {
is(2, dataavailable, 'Should has two dataavailable event');
SimpleTest.finish();
}
}
recorder.ondataavailable = function (evt) {
info('ondataavailable fired');
ok(evt instanceof BlobEvent,
'Events fired from ondataavailable should be BlobEvent');
is(evt.type, 'dataavailable',
'Event type should dataavailable');
// If script runs slower, it may generate header data in blob from encoder
if (evt.data.size > 0) {
info('blob size = ' + evt.data.size);
is(evt.data.type, expectedMimeType,
'Blob data received should have type = ' + expectedMimeType);
} else {
is(evt.data.type, '',
'Blob data received should have empty type');
}
dataavailable++;
}
recorder.onerror = function (e) {
ok(false, 'it should execute normally without exception');
}
recorder.onwarning = function() {
ok(false, 'onwarning unexpectedly fired');
};
recorder.start(2000);
is(recorder.state, 'recording', 'Media recorder should be recording');
recorder.stop();
is(recorder.state, 'inactive', 'check recording status is inactive');
recorder.start(10000); // This bug would crash on this line without this fix.
is(recorder.state, 'recording', 'check recording status is recording');
// Simulate delay stop, only delay stop no no stop can trigger crash.
setTimeout(function() {
recorder.stop();
is(recorder.state, 'inactive','check recording status is recording');
}, 1000);
}
startTest();
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -532,7 +532,7 @@ AudioBufferSourceNode::Start(double aWhen, double aOffset,
// Don't set parameter unnecessarily
if (aWhen > 0.0) {
ns->SetStreamTimeParameter(START, Context()->DestinationStream(), aWhen);
ns->SetStreamTimeParameter(START, Context(), aWhen);
}
MarkActive();
@ -616,8 +616,7 @@ AudioBufferSourceNode::Stop(double aWhen, ErrorResult& aRv)
return;
}
ns->SetStreamTimeParameter(STOP, Context()->DestinationStream(),
std::max(0.0, aWhen));
ns->SetStreamTimeParameter(STOP, Context(), std::max(0.0, aWhen));
}
void

Просмотреть файл

@ -84,6 +84,7 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow,
: nsDOMEventTargetHelper(aWindow)
, mSampleRate(GetSampleRateForAudioContext(aIsOffline, aSampleRate))
, mNumberOfChannels(aNumberOfChannels)
, mNodeCount(0)
, mIsOffline(aIsOffline)
, mIsStarted(!aIsOffline)
, mIsShutDown(false)
@ -95,6 +96,10 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow,
mDestination = new AudioDestinationNode(this, aIsOffline, aNumberOfChannels,
aLength, aSampleRate);
mDestination->Stream()->AddAudioOutput(&gWebAudioOutputKey);
// We skip calling SetIsOnlyNodeForContext during mDestination's constructor,
// because we can only call SetIsOnlyNodeForContext after mDestination has
// been set up.
mDestination->SetIsOnlyNodeForContext(true);
}
AudioContext::~AudioContext()
@ -543,7 +548,8 @@ AudioContext::DestinationStream() const
double
AudioContext::CurrentTime() const
{
return MediaTimeToSeconds(Destination()->Stream()->GetCurrentTime());
return MediaTimeToSeconds(Destination()->Stream()->GetCurrentTime()) +
ExtraCurrentTime();
}
void
@ -589,6 +595,18 @@ AudioContext::Resume()
}
}
void
AudioContext::UpdateNodeCount(int32_t aDelta)
{
bool firstNode = mNodeCount == 0;
mNodeCount += aDelta;
MOZ_ASSERT(mNodeCount >= 0);
// mDestinationNode may be null when we're destroying nodes unlinked by CC
if (!firstNode && mDestination) {
mDestination->SetIsOnlyNodeForContext(mNodeCount == 1);
}
}
JSContext*
AudioContext::GetJSContext() const
{
@ -679,5 +697,11 @@ AudioContext::CollectReports(nsIHandleReportCallback* aHandleReport,
amount, "Memory used by AudioContext objects (Web Audio).");
}
double
AudioContext::ExtraCurrentTime() const
{
return mDestination->ExtraCurrentTime();
}
}
}

Просмотреть файл

@ -246,7 +246,23 @@ public:
AudioChannel MozAudioChannelType() const;
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
void UpdateNodeCount(int32_t aDelta);
double DOMTimeToStreamTime(double aTime) const
{
return aTime - ExtraCurrentTime();
}
private:
/**
* Returns the amount of extra time added to the current time of the
* AudioDestinationNode's MediaStream to get this AudioContext's currentTime.
* Must be subtracted from all DOM API parameter times that are on the same
* timeline as AudioContext's currentTime to get times we can pass to the
* MediaStreamGraph.
*/
double ExtraCurrentTime() const;
void RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob);
void ShutdownDecoder();
@ -272,6 +288,8 @@ private:
nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
// Number of channels passed in the OfflineAudioContext ctor.
uint32_t mNumberOfChannels;
// Number of nodes that currently exist for this AudioContext
int32_t mNodeCount;
bool mIsOffline;
bool mIsStarted;
bool mIsShutDown;

Просмотреть файл

@ -17,6 +17,8 @@
#include "nsIPermissionManager.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsServiceManagerUtils.h"
#include "nsIAppShell.h"
#include "nsWidgetsCID.h"
namespace mozilla {
namespace dom {
@ -217,6 +219,9 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext,
, mAudioChannel(AudioChannel::Normal)
, mIsOffline(aIsOffline)
, mHasFinished(false)
, mExtraCurrentTime(0)
, mExtraCurrentTimeSinceLastStartedBlocking(0)
, mExtraCurrentTimeUpdatedSinceLastStableState(false)
{
MediaStreamGraph* graph = aIsOffline ?
MediaStreamGraph::CreateNonRealtimeInstance() :
@ -486,6 +491,76 @@ AudioDestinationNode::CreateAudioChannelAgent()
mAudioChannelAgent->StartPlaying(&state);
SetCanPlay(state == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
}
void
AudioDestinationNode::NotifyStableState()
{
mExtraCurrentTimeUpdatedSinceLastStableState = false;
}
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
void
AudioDestinationNode::ScheduleStableStateNotification()
{
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
if (appShell) {
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &AudioDestinationNode::NotifyStableState);
appShell->RunInStableState(event);
}
}
double
AudioDestinationNode::ExtraCurrentTime()
{
if (!mStartedBlockingDueToBeingOnlyNode.IsNull() &&
!mExtraCurrentTimeUpdatedSinceLastStableState) {
mExtraCurrentTimeUpdatedSinceLastStableState = true;
mExtraCurrentTimeSinceLastStartedBlocking =
(TimeStamp::Now() - mStartedBlockingDueToBeingOnlyNode).ToSeconds();
ScheduleStableStateNotification();
}
return mExtraCurrentTime + mExtraCurrentTimeSinceLastStartedBlocking;
}
void
AudioDestinationNode::SetIsOnlyNodeForContext(bool aIsOnlyNode)
{
if (!mStartedBlockingDueToBeingOnlyNode.IsNull() == aIsOnlyNode) {
// Nothing changed.
return;
}
if (!mStream) {
// DestroyMediaStream has been called, presumably during CC Unlink().
return;
}
if (mIsOffline) {
// Don't block the destination stream for offline AudioContexts, since
// we expect the zero data produced when there are no other nodes to
// show up in its result buffer. Also, we would get confused by adding
// ExtraCurrentTime before StartRendering has even been called.
return;
}
if (aIsOnlyNode) {
mStream->ChangeExplicitBlockerCount(1);
mStartedBlockingDueToBeingOnlyNode = TimeStamp::Now();
mExtraCurrentTimeSinceLastStartedBlocking = 0;
// Don't do an update of mExtraCurrentTimeSinceLastStartedBlocking until the next stable state.
mExtraCurrentTimeUpdatedSinceLastStableState = true;
ScheduleStableStateNotification();
} else {
// Force update of mExtraCurrentTimeSinceLastStartedBlocking if necessary
ExtraCurrentTime();
mExtraCurrentTime += mExtraCurrentTimeSinceLastStartedBlocking;
mStream->ChangeExplicitBlockerCount(-1);
mStartedBlockingDueToBeingOnlyNode = TimeStamp();
}
}
}
}

Просмотреть файл

@ -70,12 +70,22 @@ public:
virtual void NotifyMainThreadStateChanged() MOZ_OVERRIDE;
void FireOfflineCompletionEvent();
// An amount that should be added to the MediaStream's current time to
// get the AudioContext.currentTime.
double ExtraCurrentTime();
// When aIsOnlyNode is true, this is the only node for the AudioContext.
void SetIsOnlyNodeForContext(bool aIsOnlyNode);
private:
bool CheckAudioChannelPermissions(AudioChannel aValue);
void CreateAudioChannelAgent();
void SetCanPlay(bool aCanPlay);
void NotifyStableState();
void ScheduleStableStateNotification();
SelfReference<AudioDestinationNode> mOfflineRenderingRef;
uint32_t mFramesToProduce;
@ -85,6 +95,11 @@ private:
AudioChannel mAudioChannel;
bool mIsOffline;
bool mHasFinished;
TimeStamp mStartedBlockingDueToBeingOnlyNode;
double mExtraCurrentTime;
double mExtraCurrentTimeSinceLastStartedBlocking;
bool mExtraCurrentTimeUpdatedSinceLastStableState;
};
}

Просмотреть файл

@ -19,6 +19,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(AudioNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(AudioNode, nsDOMEventTargetHelper)
tmp->DisconnectFromGraph();
tmp->mContext->UpdateNodeCount(-1);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputNodes)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutputParams)
@ -58,6 +59,9 @@ AudioNode::AudioNode(AudioContext* aContext,
, mChannelInterpretation(aChannelInterpretation)
{
MOZ_ASSERT(aContext);
nsDOMEventTargetHelper::BindToOwner(aContext->GetParentObject());
SetIsDOMBinding();
aContext->UpdateNodeCount(1);
}
AudioNode::~AudioNode()
@ -65,6 +69,9 @@ AudioNode::~AudioNode()
MOZ_ASSERT(mInputNodes.IsEmpty());
MOZ_ASSERT(mOutputNodes.IsEmpty());
MOZ_ASSERT(mOutputParams.IsEmpty());
if (mContext) {
mContext->UpdateNodeCount(-1);
}
}
template <class InputNode>

Просмотреть файл

@ -42,6 +42,11 @@ public:
return mNode->Context();
}
double DOMTimeToStreamTime(double aTime) const
{
return mNode->Context()->DOMTimeToStreamTime(aTime);
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
@ -54,7 +59,7 @@ public:
return;
}
AudioParamTimeline::SetValueCurveAtTime(aValues.Data(), aValues.Length(),
aStartTime, aDuration, aRv);
DOMTimeToStreamTime(aStartTime), aDuration, aRv);
mCallback(mNode);
}
@ -76,7 +81,7 @@ public:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
AudioParamTimeline::SetValueAtTime(aValue, aStartTime, aRv);
AudioParamTimeline::SetValueAtTime(aValue, DOMTimeToStreamTime(aStartTime), aRv);
mCallback(mNode);
}
void LinearRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
@ -85,7 +90,7 @@ public:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
AudioParamTimeline::LinearRampToValueAtTime(aValue, aEndTime, aRv);
AudioParamTimeline::LinearRampToValueAtTime(aValue, DOMTimeToStreamTime(aEndTime), aRv);
mCallback(mNode);
}
void ExponentialRampToValueAtTime(float aValue, double aEndTime, ErrorResult& aRv)
@ -94,7 +99,7 @@ public:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
AudioParamTimeline::ExponentialRampToValueAtTime(aValue, aEndTime, aRv);
AudioParamTimeline::ExponentialRampToValueAtTime(aValue, DOMTimeToStreamTime(aEndTime), aRv);
mCallback(mNode);
}
void SetTargetAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv)
@ -104,7 +109,7 @@ public:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
AudioParamTimeline::SetTargetAtTime(aTarget, aStartTime, aTimeConstant, aRv);
AudioParamTimeline::SetTargetAtTime(aTarget, DOMTimeToStreamTime(aStartTime), aTimeConstant, aRv);
mCallback(mNode);
}
void SetTargetValueAtTime(float aTarget, double aStartTime, double aTimeConstant, ErrorResult& aRv)
@ -117,7 +122,7 @@ public:
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return;
}
AudioParamTimeline::CancelScheduledValues(aStartTime);
AudioParamTimeline::CancelScheduledValues(DOMTimeToStreamTime(aStartTime));
mCallback(mNode);
}

Просмотреть файл

@ -578,8 +578,7 @@ OscillatorNode::Start(double aWhen, ErrorResult& aRv)
// TODO: Perhaps we need to do more here.
ns->SetStreamTimeParameter(OscillatorNodeEngine::START,
Context()->DestinationStream(),
aWhen);
Context(), aWhen);
MarkActive();
}
@ -605,8 +604,7 @@ OscillatorNode::Stop(double aWhen, ErrorResult& aRv)
// TODO: Perhaps we need to do more here.
ns->SetStreamTimeParameter(OscillatorNodeEngine::STOP,
Context()->DestinationStream(),
std::max(0.0, aWhen));
Context(), std::max(0.0, aWhen));
}
void

Просмотреть файл

@ -9,6 +9,7 @@ PARALLEL_DIRS += ['blink', 'test']
TEST_TOOL_DIRS += ['compiledtest']
EXPORTS += [
'AudioContext.h',
'AudioParamTimeline.h',
'MediaBufferDecoder.h',
'ThreeDPoint.h',

Просмотреть файл

@ -53,10 +53,11 @@ function compareChannels(buf1, buf2,
}
};
is(difference, 0, "Found " + difference + " different samples, maxDifference: " +
maxDifference + ", first bad index: " + firstBadIndex +
" with source offset " + sourceOffset + " and destination offset " +
destOffset);
is(difference, 0, "maxDifference: " + maxDifference +
", first bad index: " + firstBadIndex +
" with test-data offset " + sourceOffset + " and expected-data offset " +
destOffset + "; corresponding values " + buf1[firstBadIndex + sourceOffset] +
" and " + buf2[firstBadIndex + destOffset] + " --- differences");
}
function compareBuffers(got, expected) {

Просмотреть файл

@ -44,7 +44,7 @@ WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
MOZ_ASSERT(meta, "Cannot find vp8 encoder metadata");
mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
meta->mEncodedFrameRate);
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::HAS_VIDEO;
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::CREATE_VIDEO_TRACK;
}
if (aMetadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
@ -52,7 +52,7 @@ WebMWriter::SetMetadata(TrackMetadataBase* aMetadata)
MOZ_ASSERT(meta, "Cannot find vorbis encoder metadata");
mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels, meta->mBitDepth);
mEbmlComposer->SetAudioCodecPrivateData(meta->mData);
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::HAS_AUDIO;
mMetadataRequiredFlag = mMetadataRequiredFlag & ~ContainerWriter::CREATE_AUDIO_TRACK;
}
if (!mMetadataRequiredFlag) {

Просмотреть файл

@ -8,8 +8,25 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
* Code below is vtt.js the JS WebVTTParser.
* Current source code can be found at http://github.com/andreasgal/vtt.js
*
* Code taken from commit 33a837b1ceef138a61a3b2f6fac90d5c70bd90d9
* Code taken from commit d819872e198d051dfcebcfb7ecf260462c9a9c6f
*/
/**
* Copyright 2013 vtt.js Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function(global) {
function ParsingError(message) {
@ -130,7 +147,7 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
throw new ParsingError("Malformed time stamp.");
}
// Remove time stamp from input.
input = input.replace(/^[^\s-]+/, "");
input = input.replace(/^[^\sa-zA-Z-]+/, "");
return ts;
}
@ -632,13 +649,19 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
(cue.snapToLines || (cue.line >= 0 && cue.line <= 100))) {
return cue.line;
}
if (!cue.track) {
if (!cue.track || !cue.track.textTrackList ||
!cue.track.textTrackList.mediaElement) {
return -1;
}
// TODO: Have to figure out a way to determine what the position of the
// Track is in the Media element's list of TextTracks and return that + 1,
// negated.
return 100;
var track = cue.track,
trackList = track.textTrackList,
count = 0;
for (var i = 0; i < trackList.length && trackList[i] !== track; i++) {
if (trackList[i].mode === "showing") {
count++;
}
}
return ++count * -1;
}
function BoundingBox() {

Просмотреть файл

@ -30,6 +30,8 @@ enum StructuredCloneTags {
SCTAG_DOM_IMAGEDATA,
SCTAG_DOM_MESSAGEPORT,
SCTAG_DOM_FUNCTION,
SCTAG_DOM_MAX
};

Просмотреть файл

@ -1630,8 +1630,8 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
const nsDOMClassInfoData *ci_data,
const nsGlobalNameStruct *name_struct,
nsScriptNameSpaceManager *nameSpaceManager,
JSObject *dot_prototype, bool install, bool *did_resolve);
JSObject *dot_prototype,
JS::MutableHandle<JSPropertyDescriptor> ctorDesc);
NS_IMETHODIMP
nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
@ -1727,19 +1727,30 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto)
}
// Don't overwrite a property set by content.
bool found;
bool contentDefinedProperty;
if (!::JS_AlreadyHasOwnUCProperty(cx, global, reinterpret_cast<const jschar*>(mData->mNameUTF16),
NS_strlen(mData->mNameUTF16), &found)) {
NS_strlen(mData->mNameUTF16),
&contentDefinedProperty)) {
return NS_ERROR_FAILURE;
}
nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
NS_ENSURE_TRUE(nameSpaceManager, NS_OK);
bool unused;
return ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
mData, nullptr, nameSpaceManager, proto, !found,
&unused);
JS::Rooted<JSPropertyDescriptor> desc(cx);
nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16,
mData, nullptr, nameSpaceManager, proto,
&desc);
NS_ENSURE_SUCCESS(rv, rv);
if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() &&
!JS_DefineUCProperty(cx, global, mData->mNameUTF16,
NS_strlen(mData->mNameUTF16),
desc.value(), desc.getter(), desc.setter(),
desc.attributes())) {
return NS_ERROR_UNEXPECTED;
}
return NS_OK;
}
// static
@ -2181,20 +2192,6 @@ public:
JS::Handle<JSObject*> obj, const jsval &val, bool *bp,
bool *_retval);
nsresult Install(JSContext *cx, JS::Handle<JSObject*> target,
JS::Handle<JS::Value> aThisAsVal)
{
JS::Rooted<JS::Value> thisAsVal(cx, aThisAsVal);
// The 'attrs' argument used to be JSPROP_PERMANENT. See bug 628612.
bool ok = JS_WrapValue(cx, &thisAsVal) &&
::JS_DefineUCProperty(cx, target,
reinterpret_cast<const jschar *>(mClassName),
NS_strlen(mClassName), thisAsVal, JS_PropertyStub,
JS_StrictPropertyStub, 0);
return ok ? NS_OK : NS_ERROR_UNEXPECTED;
}
nsresult ResolveInterfaceConstants(JSContext *cx, JS::Handle<JSObject*> obj);
private:
@ -2616,7 +2613,8 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
const nsDOMClassInfoData *ci_data,
const nsGlobalNameStruct *name_struct,
nsScriptNameSpaceManager *nameSpaceManager,
JSObject* aDot_prototype, bool install, bool *did_resolve)
JSObject* aDot_prototype,
JS::MutableHandle<JSPropertyDescriptor> ctorDesc)
{
JS::Rooted<JSObject*> dot_prototype(cx, aDot_prototype);
NS_ASSERTION(ci_data ||
@ -2635,9 +2633,12 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
false, &v);
NS_ENSURE_SUCCESS(rv, rv);
if (install) {
rv = constructor->Install(cx, obj, v);
NS_ENSURE_SUCCESS(rv, rv);
FillPropertyDescriptor(ctorDesc, obj, 0, v);
// And make sure we wrap the value into the right compartment. Note that we
// do this with ctorDesc.value(), not with v, because we need v to be in the
// right compartment (that of the reflector of |constructor|) below.
if (!JS_WrapValue(cx, ctorDesc.value())) {
return NS_ERROR_UNEXPECTED;
}
JS::Rooted<JSObject*> class_obj(cx, &v.toObject());
@ -2766,8 +2767,6 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx,
return NS_ERROR_UNEXPECTED;
}
*did_resolve = true;
return NS_OK;
}
@ -2800,13 +2799,20 @@ OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct,
return true;
}
static nsresult
LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
nsPIDOMWindow *win,
JS::MutableHandle<JSPropertyDescriptor> desc);
// static
nsresult
nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
bool *did_resolve)
JS::MutableHandle<JSPropertyDescriptor> desc)
{
*did_resolve = false;
if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) {
return LookupComponentsShim(cx, obj, aWin, desc);
}
nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager();
NS_ENSURE_TRUE(nameSpaceManager, NS_ERROR_NOT_INITIALIZED);
@ -2821,6 +2827,9 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
return NS_OK;
}
// The class_name had better match our name
MOZ_ASSERT(name.Equals(class_name));
NS_ENSURE_TRUE(class_name, NS_ERROR_UNEXPECTED);
nsresult rv = NS_OK;
@ -2838,64 +2847,86 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
name_struct->mType == nsGlobalNameStruct::eTypeClassProto ||
name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
// Lookup new DOM bindings.
mozilla::dom::DefineInterface define =
DefineInterface getOrCreateInterfaceObject =
name_struct->mDefineDOMInterface;
if (define) {
if (getOrCreateInterfaceObject) {
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor &&
!OldBindingConstructorEnabled(name_struct, aWin, cx)) {
return NS_OK;
}
Maybe<JSAutoCompartment> ac;
JS::Rooted<JSObject*> global(cx);
bool defineOnXray = xpc::WrapperFactory::IsXrayWrapper(obj);
if (defineOnXray) {
// Check whether to define this property on the Xray first. This allows
// consumers to opt in to defining on the xray even if they don't want
// to define on the underlying global.
if (name_struct->mConstructorEnabled &&
!(*name_struct->mConstructorEnabled)(cx, obj)) {
return NS_OK;
}
global = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
if (!global) {
return NS_ERROR_DOM_SECURITY_ERR;
}
ac.construct(cx, global);
} else {
global = obj;
}
// Check whether to define on the global too. Note that at this point cx
// is in the compartment of global even if we were coming in via an Xray.
bool defineOnGlobal = !name_struct->mConstructorEnabled ||
(*name_struct->mConstructorEnabled)(cx, global);
if (!defineOnGlobal && !defineOnXray) {
ConstructorEnabled* checkEnabledForScope = name_struct->mConstructorEnabled;
if (checkEnabledForScope && !checkEnabledForScope(cx, obj)) {
return NS_OK;
}
JS::Rooted<JSObject*> interfaceObject(cx, define(cx, global, id,
defineOnGlobal));
if (!interfaceObject) {
return NS_ERROR_FAILURE;
}
if (defineOnXray) {
// This really should be handled by the Xray for the window.
ac.destroy();
if (!JS_WrapObject(cx, &interfaceObject) ||
!JS_DefinePropertyById(cx, obj, id,
JS::ObjectValue(*interfaceObject), JS_PropertyStub,
JS_StrictPropertyStub, 0)) {
// The DOM constructor resolve machinery interacts with Xrays in tricky
// ways, and there are some asymmetries that are important to understand.
//
// In the regular (non-Xray) case, we only want to resolve constructors
// once (so that if they're deleted, they don't reappear). We do this by
// stashing the constructor in a slot on the global, such that we can see
// during resolve whether we've created it already. This is rather
// memory-intensive, so we don't try to maintain these semantics when
// manipulating a global over Xray (so the properties just re-resolve if
// they've been deleted).
//
// Unfortunately, there's a bit of an impedance-mismatch between the Xray
// and non-Xray machinery. The Xray machinery wants an API that returns a
// JSPropertyDescriptor, so that the resolve hook doesn't have to get
// snared up with trying to define a property on the Xray holder. At the
// same time, the DefineInterface callbacks are set up to define things
// directly on the global. And re-jiggering them to return property
// descriptors is tricky, because some DefineInterface callbacks define
// multiple things (like the Image() alias for HTMLImageElement).
//
// So the setup is as-follows:
//
// * The resolve function takes a JSPropertyDescriptor, but in the
// non-Xray case, callees may define things directly on the global, and
// set the value on the property descriptor to |undefined| to indicate
// that there's nothing more for the caller to do. We assert against
// this behavior in the Xray case.
//
// * We make sure that we do a non-Xray resolve first, so that all the
// slots are set up. In the Xray case, this means unwrapping and doing
// a non-Xray resolve before doing the Xray resolve.
//
// This all could use some grand refactoring, but for now we just limp
// along.
if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
JS::Rooted<JSObject*> global(cx,
js::CheckedUnwrap(obj, /* stopAtOuter = */ false));
if (!global) {
return NS_ERROR_DOM_SECURITY_ERR;
}
JS::Rooted<JSObject*> interfaceObject(cx);
{
JSAutoCompartment ac(cx, global);
interfaceObject = getOrCreateInterfaceObject(cx, global, id, false);
}
if (NS_WARN_IF(!interfaceObject)) {
return NS_ERROR_FAILURE;
}
if (!JS_WrapObject(cx, &interfaceObject)) {
return NS_ERROR_FAILURE;
}
FillPropertyDescriptor(desc, obj, 0, JS::ObjectValue(*interfaceObject));
} else {
JS::Rooted<JSObject*> interfaceObject(cx,
getOrCreateInterfaceObject(cx, obj, id, true));
if (NS_WARN_IF(!interfaceObject)) {
return NS_ERROR_FAILURE;
}
// We've already defined the property. We indicate this to the caller
// by filling a property descriptor with JS::UndefinedValue() as the
// value. We still have to fill in a property descriptor, though, so
// that the caller knows the property is in fact on this object. It
// doesn't matter what we pass for the "readonly" argument here.
FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
}
*did_resolve = true;
return NS_OK;
}
}
@ -2916,20 +2947,22 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
false, &v);
NS_ENSURE_SUCCESS(rv, rv);
rv = constructor->Install(cx, obj, v);
NS_ENSURE_SUCCESS(rv, rv);
JS::Rooted<JSObject*> class_obj(cx, &v.toObject());
// ... and define the constants from the DOM interface on that
// constructor object.
JSAutoCompartment ac(cx, class_obj);
rv = DefineInterfaceConstants(cx, class_obj, &name_struct->mIID);
NS_ENSURE_SUCCESS(rv, rv);
{
JSAutoCompartment ac(cx, class_obj);
rv = DefineInterfaceConstants(cx, class_obj, &name_struct->mIID);
NS_ENSURE_SUCCESS(rv, rv);
}
*did_resolve = true;
if (!JS_WrapValue(cx, &v)) {
return NS_ERROR_UNEXPECTED;
}
FillPropertyDescriptor(desc, obj, 0, v);
return NS_OK;
}
@ -2940,38 +2973,42 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
}
// Create the XPConnect prototype for our classinfo, PostCreateProto will
// set up the prototype chain.
// set up the prototype chain. This will go ahead and define things on the
// actual window's global.
nsCOMPtr<nsIXPConnectJSObjectHolder> proto_holder;
rv = GetXPCProto(sXPConnect, cx, aWin, name_struct,
getter_AddRefs(proto_holder));
if (NS_SUCCEEDED(rv) && obj != aWin->GetGlobalJSObject()) {
JS::Rooted<JSObject*> dot_prototype(cx, proto_holder->GetJSObject());
NS_ENSURE_STATE(dot_prototype);
const nsDOMClassInfoData *ci_data;
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
} else {
ci_data = name_struct->mData;
}
return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data,
name_struct, nameSpaceManager, dot_prototype,
true, did_resolve);
NS_ENSURE_SUCCESS(rv, rv);
bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj);
MOZ_ASSERT_IF(obj != aWin->GetGlobalJSObject(), isXray);
if (!isXray) {
// GetXPCProto already defined the property for us
FillPropertyDescriptor(desc, obj, JS::UndefinedValue(), false);
return NS_OK;
}
*did_resolve = NS_SUCCEEDED(rv);
// This is the Xray case. Look up the constructor object for this
// prototype.
JS::Rooted<JSObject*> dot_prototype(cx, proto_holder->GetJSObject());
NS_ENSURE_STATE(dot_prototype);
return rv;
const nsDOMClassInfoData *ci_data;
if (name_struct->mType == nsGlobalNameStruct::eTypeClassConstructor) {
ci_data = &sClassInfoData[name_struct->mDOMClassInfoID];
} else {
ci_data = name_struct->mData;
}
return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data,
name_struct, nameSpaceManager, dot_prototype,
desc);
}
if (name_struct->mType == nsGlobalNameStruct::eTypeClassProto) {
// We don't have a XPConnect prototype object, let ResolvePrototype create
// one.
return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, nullptr,
name_struct, nameSpaceManager, nullptr, true,
did_resolve);
name_struct, nameSpaceManager, nullptr, desc);
}
if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructorAlias) {
@ -3000,8 +3037,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
}
return ResolvePrototype(sXPConnect, aWin, cx, obj, class_name, ci_data,
name_struct, nameSpaceManager, nullptr, true,
did_resolve);
name_struct, nameSpaceManager, nullptr, desc);
}
if (name_struct->mType == nsGlobalNameStruct::eTypeExternalConstructor) {
@ -3013,15 +3049,12 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JS::Rooted<JS::Value> val(cx);
rv = WrapNative(cx, obj, constructor, &NS_GET_IID(nsIDOMDOMConstructor),
false, &val);
NS_ENSURE_SUCCESS(rv, rv);
rv = constructor->Install(cx, obj, val);
true, &val);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(val.isObject(), "Why didn't we get a JSObject?");
*did_resolve = true;
FillPropertyDescriptor(desc, obj, 0, val);
return NS_OK;
}
@ -3070,26 +3103,9 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
return NS_ERROR_UNEXPECTED;
}
bool ok = ::JS_DefinePropertyById(cx, obj, id, prop_val,
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE);
FillPropertyDescriptor(desc, obj, prop_val, false);
*did_resolve = true;
return ok ? NS_OK : NS_ERROR_FAILURE;
}
if (name_struct->mType == nsGlobalNameStruct::eTypeDynamicNameSet) {
nsCOMPtr<nsIScriptExternalNameSet> nameset =
do_CreateInstance(name_struct->mCID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsIScriptContext *context = aWin->GetContext();
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
rv = nameset->InitializeNameSet(context);
*did_resolve = true;
return NS_OK;
}
return rv;
@ -3201,7 +3217,9 @@ const InterfaceShimEntry kInterfaceShimMap[] =
{ "nsIDOMXPathResult", "XPathResult" } };
static nsresult
DefineComponentsShim(JSContext *cx, JS::Handle<JSObject*> global, nsPIDOMWindow *win)
LookupComponentsShim(JSContext *cx, JS::Handle<JSObject*> global,
nsPIDOMWindow *win,
JS::MutableHandle<JSPropertyDescriptor> desc)
{
// Keep track of how often this happens.
Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true);
@ -3215,16 +3233,14 @@ DefineComponentsShim(JSContext *cx, JS::Handle<JSObject*> global, nsPIDOMWindow
// Create a fake Components object.
JS::Rooted<JSObject*> components(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), global));
NS_ENSURE_TRUE(components, NS_ERROR_OUT_OF_MEMORY);
bool ok = JS_DefineProperty(cx, global, "Components", JS::ObjectValue(*components),
JS_PropertyStub, JS_StrictPropertyStub, JSPROP_ENUMERATE);
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
// Create a fake interfaces object.
JS::Rooted<JSObject*> interfaces(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), global));
NS_ENSURE_TRUE(interfaces, NS_ERROR_OUT_OF_MEMORY);
ok = JS_DefineProperty(cx, components, "interfaces", JS::ObjectValue(*interfaces),
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
bool ok =
JS_DefineProperty(cx, components, "interfaces", JS::ObjectValue(*interfaces),
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY);
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
// Define a bunch of shims from the Ci.nsIDOMFoo to window.Foo for DOM
@ -3251,6 +3267,8 @@ DefineComponentsShim(JSContext *cx, JS::Handle<JSObject*> global, nsPIDOMWindow
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
}
FillPropertyDescriptor(desc, global, JS::ObjectValue(*components), false);
return NS_OK;
}
@ -3271,11 +3289,6 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
nsGlobalWindow *win = nsGlobalWindow::FromWrapper(wrapper);
MOZ_ASSERT(win->IsInnerWindow());
if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) {
*objp = obj;
return DefineComponentsShim(cx, obj, win);
}
// Don't resolve standard classes on XrayWrappers, only resolve them if we're
// resolving on the real global object.
bool isXray = xpc::WrapperFactory::IsXrayWrapper(obj);
@ -3352,11 +3365,50 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_OK;
}
bool did_resolve = false;
nsresult rv = GlobalResolve(win, cx, obj, id, &did_resolve);
NS_ENSURE_SUCCESS(rv, rv);
if (isXray) {
// We promise to resolve on the underlying object first. That will create
// the actual interface object if needed and store it in a data structure
// hanging off the global. Then our second call will wrap up in an Xray as
// needed. We do things this way because we use the existence of the
// object in that data structure as a flag that indicates that its name
// (and any relevant named constructor names) has been resolved before;
// this allows us to avoid re-resolving in the Xray case if the property is
// deleted by page script.
JS::Rooted<JSObject*> global(cx,
js::UncheckedUnwrap(obj, /* stopAtOuter = */ false));
JSAutoCompartment ac(cx, global);
JS::Rooted<JSPropertyDescriptor> desc(cx);
if (!win->DoNewResolve(cx, global, id, &desc)) {
return NS_ERROR_FAILURE;
}
// If we have an object here, that means we resolved the property.
// But if the value is undefined, that means that GlobalResolve
// also already defined it, so we don't have to.
if (desc.object() && !desc.value().isUndefined() &&
!JS_DefinePropertyById(cx, global, id, desc.value(),
desc.getter(), desc.setter(),
desc.attributes())) {
return NS_ERROR_FAILURE;
}
}
JS::Rooted<JSPropertyDescriptor> desc(cx);
if (!win->DoNewResolve(cx, obj, id, &desc)) {
return NS_ERROR_FAILURE;
}
if (desc.object()) {
// If we have an object here, that means we resolved the property.
// But if the value is undefined, that means that GlobalResolve
// also already defined it, so we don't have to. Note that in the
// Xray case we should never see undefined.
MOZ_ASSERT_IF(isXray, !desc.value().isUndefined());
if (!desc.value().isUndefined() &&
!JS_DefinePropertyById(cx, obj, id, desc.value(),
desc.getter(), desc.setter(),
desc.attributes())) {
return NS_ERROR_FAILURE;
}
if (did_resolve) {
*objp = obj;
return NS_OK;
}
@ -3364,8 +3416,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
if (!(flags & JSRESOLVE_ASSIGNING) && sDocument_id == id) {
nsCOMPtr<nsIDocument> document = win->GetDoc();
JS::Rooted<JS::Value> v(cx);
rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), document, document,
&NS_GET_IID(nsIDOMDocument), &v, false);
nsresult rv = WrapNative(cx, JS::CurrentGlobalOrNull(cx), document, document,
&NS_GET_IID(nsIDOMDocument), &v, false);
NS_ENSURE_SUCCESS(rv, rv);
// nsIDocument::WrapObject will handle defining the property.

Просмотреть файл

@ -256,8 +256,9 @@ protected:
static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx,
JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
bool *did_resolve);
JS::MutableHandle<JSPropertyDescriptor> desc);
friend class nsGlobalWindow;
public:
NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx,
JSObject *globalObj, JSObject **parentObj) MOZ_OVERRIDE;

Просмотреть файл

@ -34,6 +34,7 @@
#include "nsIScriptContext.h"
#include "nsIScriptTimeoutHandler.h"
#include "nsIController.h"
#include "nsScriptNameSpaceManager.h"
// Helper Classes
#include "nsJSUtils.h"
@ -4052,6 +4053,43 @@ nsGlobalWindow::GetSupportedNames(nsTArray<nsString>& aNames)
}
}
bool
nsGlobalWindow::DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc)
{
MOZ_ASSERT(IsInnerWindow());
if (!JSID_IS_STRING(aId)) {
return true;
}
nsresult rv = nsWindowSH::GlobalResolve(this, aCx, aObj, aId, aDesc);
if (NS_FAILED(rv)) {
return Throw(aCx, rv);
}
return true;
}
static PLDHashOperator
EnumerateGlobalName(const nsAString& aName, void* aClosure)
{
nsTArray<nsString>* arr = static_cast<nsTArray<nsString>*>(aClosure);
arr->AppendElement(aName);
return PL_DHASH_NEXT;
}
void
nsGlobalWindow::GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
ErrorResult& aRv)
{
nsScriptNameSpaceManager* nameSpaceManager = GetNameSpaceManager();
if (nameSpaceManager) {
nameSpaceManager->EnumerateGlobalNames(EnumerateGlobalName, &aNames);
}
}
nsIDOMOfflineResourceList*
nsGlobalWindow::GetApplicationCache(ErrorResult& aError)
{
@ -4130,13 +4168,6 @@ nsGlobalWindow::GetCrypto(nsIDOMCrypto** aCrypto)
return rv.ErrorCode();
}
NS_IMETHODIMP
nsGlobalWindow::GetPkcs11(nsIDOMPkcs11** aPkcs11)
{
*aPkcs11 = nullptr;
return NS_OK;
}
nsIControllers*
nsGlobalWindow::GetControllers(ErrorResult& aError)
{
@ -10491,6 +10522,11 @@ nsGlobalWindow::ShowSlowScriptDialog()
return KillSlowScript;
}
// If our document is not active, just kill the script: we've been unloaded
if (!HasActiveDocument()) {
return KillSlowScript;
}
// Get the nsIPrompt interface from the docshell
nsCOMPtr<nsIDocShell> ds = GetDocShell();
NS_ENSURE_TRUE(ds, KillSlowScript);

Просмотреть файл

@ -475,6 +475,13 @@ public:
void GetSupportedNames(nsTArray<nsString>& aNames);
bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::Handle<jsid> aId,
JS::MutableHandle<JSPropertyDescriptor> aDesc);
void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
mozilla::ErrorResult& aRv);
// Object Management
nsGlobalWindow(nsGlobalWindow *aOuterWindow);
@ -902,10 +909,6 @@ public:
int64_t GetMozAnimationStartTime(mozilla::ErrorResult& aError);
void SizeToContent(mozilla::ErrorResult& aError);
nsIDOMCrypto* GetCrypto(mozilla::ErrorResult& aError);
nsIDOMPkcs11* GetPkcs11()
{
return nullptr;
}
nsIControllers* GetControllers(mozilla::ErrorResult& aError);
float GetMozInnerScreenX(mozilla::ErrorResult& aError);
float GetMozInnerScreenY(mozilla::ErrorResult& aError);

Просмотреть файл

@ -25,9 +25,6 @@
#define JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY \
"JavaScript-global-static-nameset"
#define JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY \
"JavaScript-global-dynamic-nameset"
#define JAVASCRIPT_DOM_CLASS \
"JavaScript-DOM-class"

Просмотреть файл

@ -369,9 +369,6 @@ nsScriptNameSpaceManager::Init()
rv = FillHash(cm, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY);
NS_ENSURE_SUCCESS(rv, rv);
rv = FillHash(cm, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY);
NS_ENSURE_SUCCESS(rv, rv);
rv = FillHash(cm, JAVASCRIPT_NAVIGATOR_PROPERTY_CATEGORY);
NS_ENSURE_SUCCESS(rv, rv);
@ -626,8 +623,6 @@ nsScriptNameSpaceManager::OperateCategoryEntryHash(nsICategoryManager* aCategory
type = nsGlobalNameStruct::eTypeNavigatorProperty;
} else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_STATIC_NAMESET_CATEGORY) == 0) {
type = nsGlobalNameStruct::eTypeStaticNameSet;
} else if (strcmp(aCategory, JAVASCRIPT_GLOBAL_DYNAMIC_NAMESET_CATEGORY) == 0) {
type = nsGlobalNameStruct::eTypeDynamicNameSet;
} else {
return NS_OK;
}

Просмотреть файл

@ -50,7 +50,6 @@ struct nsGlobalNameStruct
eTypeNavigatorProperty,
eTypeExternalConstructor,
eTypeStaticNameSet,
eTypeDynamicNameSet,
eTypeClassConstructor,
eTypeClassProto,
eTypeExternalClassInfoCreator,

Просмотреть файл

@ -2168,7 +2168,7 @@ FinalizeGlobal(JSFreeOp* aFreeOp, JSObject* aObj)
bool
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::MutableHandle<jsid> aId, unsigned aFlags,
JS::Handle<jsid> aId, unsigned aFlags,
JS::MutableHandle<JSObject*> aObjp)
{
bool resolved;

Просмотреть файл

@ -2357,7 +2357,7 @@ FinalizeGlobal(JSFreeOp* aFop, JSObject* aObj);
bool
ResolveGlobal(JSContext* aCx, JS::Handle<JSObject*> aObj,
JS::MutableHandle<jsid> aId, unsigned aFlags,
JS::Handle<jsid> aId, unsigned aFlags,
JS::MutableHandle<JSObject*> aObjp);
bool

Просмотреть файл

@ -1935,7 +1935,6 @@ addExternalIface('nsIEditor', nativeType='nsIEditor', notflattened=True)
addExternalIface('nsIVariant', nativeType='nsIVariant', notflattened=True)
addExternalIface('OutputStream', nativeType='nsIOutputStream',
notflattened=True)
addExternalIface('Pkcs11')
addExternalIface('Principal', nativeType='nsIPrincipal',
headerFile='nsIPrincipal.h', notflattened=True)
addExternalIface('StackFrame', nativeType='nsIStackFrame',

Просмотреть файл

@ -2477,6 +2477,7 @@ class CGClearCachedValueMethod(CGAbstractMethod):
regetMember = ("\n"
"JS::Rooted<JS::Value> temp(aCx);\n"
"JSJitGetterCallArgs args(&temp);\n"
"JSAutoCompartment ac(aCx, obj);\n"
"if (!get_%s(aCx, obj, aObject, args)) {\n"
" js::SetReservedSlot(obj, %s, oldValue);\n"
" nsJSUtils::ReportPendingException(aCx);\n"
@ -6021,6 +6022,20 @@ class CGNewResolveHook(CGAbstractBindingMethod):
"objp.set(obj);\n"
"return true;"))
def definition_body(self):
if self.descriptor.interface.getExtendedAttribute("Global"):
# Resolve standard classes
prefix = CGIndenter(CGGeneric(
"if (!ResolveGlobal(cx, obj, id, flags, objp)) {\n"
" return false;\n"
"}\n"
"if (objp) {\n"
" return true;\n"
"}\n\n")).define()
else:
prefix = ""
return prefix + CGAbstractBindingMethod.definition_body(self)
class CGEnumerateHook(CGAbstractBindingMethod):
"""
Enumerate hook for objects with custom hooks.
@ -6052,6 +6067,17 @@ class CGEnumerateHook(CGAbstractBindingMethod):
"}\n"
"return true;"))
def definition_body(self):
if self.descriptor.interface.getExtendedAttribute("Global"):
# Enumerate standard classes
prefix = CGIndenter(CGGeneric(
"if (!EnumerateGlobal(cx, obj)) {\n"
" return false;\n"
"}\n\n")).define()
else:
prefix = ""
return prefix + CGAbstractBindingMethod.definition_body(self)
class CppKeywords():
"""
A class for checking if method names declared in webidl
@ -7732,6 +7758,29 @@ class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
callArgs="")
def generate_code(self):
return CGIndenter(CGGeneric(
"{\n"
" // Since we're dealing with an Xray, do the resolve on the\n"
" // underlying object first. That gives it a chance to\n"
" // define properties on the actual object as needed, and\n"
" // then use the fact that it created the objects as a flag\n"
" // o avoid re-resolving the properties if someone deletes\n"
" // them.\n"
" JSAutoCompartment ac(cx, obj);\n"
" JS::Rooted<JSPropertyDescriptor> objDesc(cx);\n"
" if (!self->DoNewResolve(cx, obj, id, &objDesc)) {\n"
" return false;\n"
" }\n"
" // If desc.value() is undefined, then the DoNewResolve call\n"
" // has already defined the property on the object. Don't\n"
" // try to also define it.\n"
" if (objDesc.object() &&\n"
" !objDesc.value().isUndefined() &&\n"
" !JS_DefinePropertyById(cx, obj, id, objDesc.value(),\n"
" objDesc.getter(), objDesc.setter(),\n"
" objDesc.attributes())) {\n"
" return false;\n"
" }\n"
"}\n"
"return self->DoNewResolve(cx, wrapper, id, desc);"))
class CGEnumerateOwnProperties(CGAbstractStaticMethod):

Просмотреть файл

@ -165,6 +165,18 @@ FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, JSObject* o
FillPropertyDescriptor(desc, obj, readonly);
}
inline void
FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc,
JSObject* obj, unsigned attributes, JS::Value v)
{
desc.object().set(obj);
desc.value().set(v);
desc.setAttributes(attributes);
desc.setGetter(nullptr);
desc.setSetter(nullptr);
desc.setShortId(0);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -378,10 +378,7 @@ NS_IMETHODIMP JSStackFrame::GetFilename(nsACString& aFilename)
if (!mFilenameInitialized) {
JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
if (desc.script()) {
// This cx dance is silly, since JS_GetScriptFilename ignores
// its cx argument.
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
JSAutoRequest ar(cx);
ThreadsafeAutoSafeJSContext cx;
JSAutoCompartment ac(cx, desc.script());
const char* filename = JS_GetScriptFilename(cx, desc.script());
if (filename) {
@ -407,8 +404,7 @@ NS_IMETHODIMP JSStackFrame::GetName(nsACString& aFunction)
if (!mFunnameInitialized) {
JS::FrameDescription& desc = mStackDescription->FrameAt(mIndex);
if (desc.fun() && desc.script()) {
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
JSAutoRequest ar(cx);
ThreadsafeAutoSafeJSContext cx;
JSAutoCompartment ac(cx, desc.script());
JS::Rooted<JSFunction*> fun(cx, desc.fun());
JS::Rooted<JSString*> funid(cx, JS_GetFunctionDisplayId(fun));

Просмотреть файл

@ -25,7 +25,6 @@ const MAX_REQUESTS = 25;
Cu.import("resource://gre/modules/DataStoreCursor.jsm");
Cu.import("resource://gre/modules/DataStoreDB.jsm");
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
Cu.importGlobalProperties(["indexedDB"]);
@ -142,7 +141,7 @@ this.DataStore.prototype = {
function getInternalSuccess(aEvent, aPos) {
debug("GetInternal success. Record: " + aEvent.target.result);
results[aPos] = ObjectWrapper.wrap(aEvent.target.result, self._window);
results[aPos] = Cu.cloneInto(aEvent.target.result, self._window);
if (!--pendingIds) {
aCallback(results);
return;

Просмотреть файл

@ -27,7 +27,6 @@ const REVISION_REMOVED = 'removed';
const REVISION_VOID = 'void';
const REVISION_SKIP = 'skip'
Cu.import('resource://gre/modules/ObjectWrapper.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
/**
@ -151,7 +150,7 @@ this.DataStoreCursor.prototype = {
self._revision = aEvent.target.result.value;
self._objectId = 0;
self._state = STATE_SEND_ALL;
aResolve(ObjectWrapper.wrap({ operation: 'clear' }, self._window));
aResolve(Cu.cloneInto({ operation: 'clear' }, self._window));
}
},
@ -291,7 +290,7 @@ this.DataStoreCursor.prototype = {
if (self._revision.revisionId != aEvent.target.result.value.revisionId) {
self._revision = aEvent.target.result.value;
self._objectId = 0;
aResolve(ObjectWrapper.wrap({ operation: 'clear' }, self._window));
aResolve(Cu.cloneInto({ operation: 'clear' }, self._window));
return;
}
@ -305,8 +304,8 @@ this.DataStoreCursor.prototype = {
}
self._objectId = cursor.key;
aResolve(ObjectWrapper.wrap({ operation: 'add', id: self._objectId,
data: cursor.value }, self._window));
aResolve(Cu.cloneInto({ operation: 'add', id: self._objectId,
data: cursor.value }, self._window));
};
};
},
@ -324,8 +323,8 @@ this.DataStoreCursor.prototype = {
switch (this._revision.operation) {
case REVISION_REMOVED:
aResolve(ObjectWrapper.wrap({ operation: 'remove', id: this._revision.objectId },
this._window));
aResolve(Cu.cloneInto({ operation: 'remove', id: this._revision.objectId },
this._window));
break;
case REVISION_ADDED: {
@ -337,8 +336,8 @@ this.DataStoreCursor.prototype = {
return;
}
aResolve(ObjectWrapper.wrap({ operation: 'add', id: self._revision.objectId,
data: aEvent.target.result }, self._window));
aResolve(Cu.cloneInto({ operation: 'add', id: self._revision.objectId,
data: aEvent.target.result }, self._window));
}
break;
}
@ -357,8 +356,8 @@ this.DataStoreCursor.prototype = {
return;
}
aResolve(ObjectWrapper.wrap({ operation: 'update', id: self._revision.objectId,
data: aEvent.target.result }, self._window));
aResolve(Cu.cloneInto({ operation: 'update', id: self._revision.objectId,
data: aEvent.target.result }, self._window));
}
break;
}
@ -377,8 +376,8 @@ this.DataStoreCursor.prototype = {
stateMachineDone: function(aStore, aRevisionStore, aResolve, aReject) {
this.close();
aResolve(ObjectWrapper.wrap({ revisionId: this._revision.revisionId,
operation: 'done' }, this._window));
aResolve(Cu.cloneInto({ revisionId: this._revision.revisionId,
operation: 'done' }, this._window));
},
// public interface

Просмотреть файл

@ -77,7 +77,6 @@ interface nsIDOMRange;
// Crypto
interface nsIDOMCrypto;
interface nsIDOMPkcs11;
// Used font face (for inspector)
interface nsIDOMFontFace;

Просмотреть файл

@ -23,7 +23,6 @@ XPIDL_SOURCES += [
'nsIDOMLocation.idl',
'nsIDOMModalContentWindow.idl',
'nsIDOMNavigator.idl',
'nsIDOMPkcs11.idl',
'nsIDOMScreen.idl',
'nsIDOMWindow.idl',
'nsIDOMWindowCollection.idl',

Просмотреть файл

@ -1,16 +0,0 @@
/* -*- Mode: IDL; 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 "domstubs.idl"
[scriptable, uuid(9fd42950-25e7-11d4-8a7d-006008c844c3)]
interface nsIDOMPkcs11 : nsISupports
{
long deletemodule(in DOMString moduleName);
long addmodule(in DOMString moduleName,
in DOMString libraryFullPath,
in long cryptoMechanismFlags,
in long cipherFlags);
};

Просмотреть файл

@ -24,7 +24,7 @@ interface nsIVariant;
* @see <http://www.whatwg.org/html/#window>
*/
[scriptable, uuid(f2d1d383-f7b5-46f8-aadf-b69a0ebfb16f)]
[scriptable, uuid(97b6784b-ab12-4f79-8422-d7868a4cc7dc)]
interface nsIDOMWindow : nsISupports
{
// the current browsing context
@ -374,7 +374,6 @@ interface nsIDOMWindow : nsISupports
readonly attribute boolean closed;
readonly attribute nsIDOMCrypto crypto;
readonly attribute nsIDOMPkcs11 pkcs11;
// Note: this is [ChromeOnly] scriptable via WebIDL.
[noscript] readonly attribute nsIControllers controllers;

Просмотреть файл

@ -18,11 +18,10 @@
interface ApplicationCache;
interface MozFrameRequestCallback;
interface nsIDOMCrypto;
interface Pkcs11;
typedef any Transferable;
// http://www.whatwg.org/specs/web-apps/current-work/
[Global]
[Global, NeedNewResolve]
/*sealed*/ interface Window : EventTarget {
// the current browsing context
[Unforgeable, Throws,
@ -257,8 +256,6 @@ partial interface Window {
*/
[Throws] void sizeToContent();
readonly attribute Pkcs11? pkcs11;
// XXX Shouldn't this be in nsIDOMChromeWindow?
[ChromeOnly, Replaceable, Throws] readonly attribute MozControllers controllers;

Просмотреть файл

@ -27,7 +27,6 @@ HBSOURCES = \
hb-buffer.cc \
hb-cache-private.hh \
hb-common.cc \
hb-fallback-shape.cc \
hb-face-private.hh \
hb-face.cc \
hb-font-private.hh \
@ -92,6 +91,8 @@ HBSOURCES += \
hb-ot-shape-complex-arabic-fallback.hh \
hb-ot-shape-complex-arabic-table.hh \
hb-ot-shape-complex-default.cc \
hb-ot-shape-complex-hangul.cc \
hb-ot-shape-complex-hebrew.cc \
hb-ot-shape-complex-indic.cc \
hb-ot-shape-complex-indic-machine.hh \
hb-ot-shape-complex-indic-private.hh \
@ -101,6 +102,7 @@ HBSOURCES += \
hb-ot-shape-complex-sea.cc \
hb-ot-shape-complex-sea-machine.hh \
hb-ot-shape-complex-thai.cc \
hb-ot-shape-complex-tibetan.cc \
hb-ot-shape-complex-private.hh \
hb-ot-shape-normalize-private.hh \
hb-ot-shape-normalize.cc \
@ -111,10 +113,15 @@ HBSOURCES += \
HBHEADERS += \
hb-ot.h \
hb-ot-layout.h \
hb-ot-shape.h \
hb-ot-tag.h \
$(NULL)
endif
if HAVE_FALLBACK
HBSOURCES += hb-fallback-shape.cc
endif
if HAVE_PTHREAD
HBCFLAGS += $(PTHREAD_CFLAGS)
HBLIBS += $(PTHREAD_LIBS)

Просмотреть файл

@ -29,7 +29,6 @@
#include "hb-private.hh"
#include "hb-blob.h"
#include "hb-object-private.hh"
#ifdef HAVE_SYS_MMAN_H

Просмотреть файл

@ -31,7 +31,6 @@
#define HB_BUFFER_PRIVATE_HH
#include "hb-private.hh"
#include "hb-buffer.h"
#include "hb-object-private.hh"
#include "hb-unicode-private.hh"

Просмотреть файл

@ -204,7 +204,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
*p++ = '+';
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
if (pos->y_advance)
if (pos[i].y_advance)
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
}

Просмотреть файл

@ -28,8 +28,6 @@
#include "hb-private.hh"
#include "hb-version.h"
#include "hb-mutex-private.hh"
#include "hb-object-private.hh"

Просмотреть файл

@ -94,6 +94,7 @@ typedef uint32_t hb_tag_t;
#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
#define HB_TAG_NONE HB_TAG(0,0,0,0)
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
/* len=-1 means str is NUL-terminated. */
hb_tag_t
@ -270,7 +271,12 @@ typedef enum
/*6.1*/ HB_SCRIPT_TAKRI = HB_TAG ('T','a','k','r'),
/* No script set. */
/*---*/ HB_SCRIPT_INVALID = HB_TAG_NONE
/*---*/ HB_SCRIPT_INVALID = HB_TAG_NONE,
/* Dummy value to ensure any hb_tag_t value can be passed/stored as hb_script_t
* without risking undefined behavior. */
/*---*/ _HB_SCRIPT_MAX_VALUE = HB_TAG_MAX
} hb_script_t;
/* These are moved out of hb_script_t because glib-mkenums chokes otherwise. */

Просмотреть файл

@ -591,7 +591,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
CFMutableAttributedStringRef attr_string = CFAttributedStringCreateMutable (NULL, chars_len);
CFAttributedStringReplaceString (attr_string, CFRangeMake (0, 0), string_ref);
CFRelease (string_ref);
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
kCTFontAttributeName, font_data->ct_font);
@ -671,23 +670,33 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
if (buffer->in_error)
FAIL ("Buffer resize failed");
hb_glyph_info_t *info = buffer->info + buffer->len;
buffer->len += range.length;
for (CFIndex j = 0; j < range.length; j++)
CGGlyph notdef = 0;
double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
for (CFIndex j = range.location; j < range.location + range.length; j++)
{
CGGlyph notdef = 0;
double advance = CTFontGetAdvancesForGlyphs (font_data->ct_font, kCTFontHorizontalOrientation, &notdef, NULL, 1);
UniChar ch = CFStringGetCharacterAtIndex (string_ref, j);
if (hb_in_range<UniChar> (ch, 0xDC00, 0xDFFF) && range.location < j)
{
ch = CFStringGetCharacterAtIndex (string_ref, j - 1);
if (hb_in_range<UniChar> (ch, 0xD800, 0xDBFF))
/* This is the second of a surrogate pair. Don't need .notdef
* for this one. */
continue;
}
info->codepoint = notdef;
/* TODO We have to fixup clusters later. See vis_clusters in
* hb-uniscribe.cc for example. */
info->cluster = range.location + j;
info->cluster = j;
info->mask = advance;
info->var1.u32 = 0;
info->var2.u32 = 0;
info++;
buffer->len++;
}
continue;
}
@ -796,6 +805,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
}
}
CFRelease (string_ref);
CFRelease (line);
return true;

Просмотреть файл

@ -31,7 +31,6 @@
#include "hb-private.hh"
#include "hb-font.h"
#include "hb-object-private.hh"
#include "hb-shaper-private.hh"
#include "hb-shape-plan-private.hh"

Просмотреть файл

@ -31,7 +31,6 @@
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-blob.h"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"

Просмотреть файл

@ -105,8 +105,9 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
* shaper which many people unfortunately still request.
*/
bool has_space;
hb_codepoint_t space;
font->get_glyph (' ', 0, &space);
has_space = font->get_glyph (' ', 0, &space);
buffer->clear_positions ();
@ -114,7 +115,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
for (unsigned int i = 0; i < count; i++)
{
if (buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) {
if (has_space && buffer->unicode->is_default_ignorable (buffer->info[i].codepoint)) {
buffer->info[i].codepoint = space;
buffer->pos[i].x_advance = 0;
buffer->pos[i].y_advance = 0;

Просмотреть файл

@ -31,7 +31,6 @@
#include "hb-private.hh"
#include "hb-font.h"
#include "hb-object-private.hh"
#include "hb-face-private.hh"
#include "hb-shaper-private.hh"
@ -145,6 +144,12 @@ struct hb_font_t {
/* Public getters */
inline hb_bool_t has_glyph (hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return get_glyph (unicode, 0, &glyph);
}
inline hb_bool_t get_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
hb_codepoint_t *glyph)
{

Просмотреть файл

@ -31,7 +31,6 @@
#include "hb-ot-layout-private.hh"
#include "hb-font-private.hh"
#include "hb-blob.h"
#include "hb-open-file-private.hh"
#include "hb-ot-head-table.hh"
#include "hb-ot-maxp-table.hh"

Просмотреть файл

@ -34,8 +34,6 @@
#include <graphite2/Segment.h>
#include "hb-ot-tag.h"
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, face)
HB_SHAPER_DATA_ENSURE_DECLARE(graphite2, font)
@ -109,7 +107,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
if (unlikely (!data))
hb_blob_destroy (silf_blob);
return NULL;
data->face = face;
data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);

Просмотреть файл

@ -31,8 +31,6 @@
#include "hb-private.hh"
#include "hb-blob.h"
namespace OT {
@ -594,7 +592,7 @@ struct LONGDATETIME
TRACE_SANITIZE (this);
return TRACE_RETURN (likely (c->check_struct (this)));
}
private:
protected:
LONG major;
ULONG minor;
public:

Просмотреть файл

@ -109,11 +109,13 @@ struct ValueFormat : USHORT
if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
if (format & xAdvance) {
if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
values++;
}
/* y_advance values grow downward but font-space grows upward, hence negation */
if (format & yAdvance) {
if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
values++;
}
if (!has_device ()) return;
@ -125,17 +127,21 @@ struct ValueFormat : USHORT
/* pixel -> fractional pixel */
if (format & xPlaDevice) {
if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font);
values++;
}
if (format & yPlaDevice) {
if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
values++;
}
if (format & xAdvDevice) {
if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
values++;
}
if (format & yAdvDevice) {
/* y_advance values grow downward but font-space grows upward, hence negation */
if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
values++;
}
}
@ -240,12 +246,12 @@ struct AnchorFormat2
unsigned int x_ppem = font->x_ppem;
unsigned int y_ppem = font->y_ppem;
hb_position_t cx, cy;
hb_bool_t ret = false;
hb_bool_t ret;
if (x_ppem || y_ppem)
ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
*x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
*y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
ret = (x_ppem || y_ppem) &&
font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
*x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
*y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
}
inline bool sanitize (hb_sanitize_context_t *c) {

Просмотреть файл

@ -31,8 +31,6 @@
#include "hb-private.hh"
#include "hb-ot-layout.h"
#include "hb-font-private.hh"
#include "hb-buffer-private.hh"
#include "hb-set-private.hh"

Просмотреть файл

@ -193,11 +193,6 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
const hb_tag_t *features,
hb_set_t *lookup_indexes /* OUT */);
void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
void
hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
hb_tag_t table_tag,

Просмотреть файл

@ -199,7 +199,6 @@ collect_features_arabic (hb_ot_shape_planner_t *plan)
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
map->add_gsub_pause (NULL);
map->add_global_bool_feature (HB_TAG('c','s','w','h'));
map->add_global_bool_feature (HB_TAG('m','s','e','t'));
}
@ -366,7 +365,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic =
data_create_arabic,
data_destroy_arabic,
NULL, /* preprocess_text_arabic */
NULL, /* normalization_preference */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_arabic,

Просмотреть файл

@ -27,194 +27,18 @@
#include "hb-ot-shape-complex-private.hh"
/* TODO Add kana, and other small shapers here */
/* The default shaper *only* adds additional per-script features.*/
static const hb_tag_t hangul_features[] =
{
HB_TAG('l','j','m','o'),
HB_TAG('v','j','m','o'),
HB_TAG('t','j','m','o'),
HB_TAG_NONE
};
static const hb_tag_t tibetan_features[] =
{
HB_TAG('a','b','v','s'),
HB_TAG('b','l','w','s'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
HB_TAG_NONE
};
static void
collect_features_default (hb_ot_shape_planner_t *plan)
{
const hb_tag_t *script_features = NULL;
switch ((hb_tag_t) plan->props.script)
{
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
script_features = hangul_features;
break;
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
script_features = tibetan_features;
break;
}
for (; script_features && *script_features; script_features++)
plan->map.add_global_bool_feature (*script_features);
}
static hb_ot_shape_normalization_mode_t
normalization_preference_default (const hb_segment_properties_t *props)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
}
static bool
compose_default (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866
* Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
* Note that some letters do not have a dagesh presForm encoded.
*/
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, /* ALEF */
0xFB31, /* BET */
0xFB32, /* GIMEL */
0xFB33, /* DALET */
0xFB34, /* HE */
0xFB35, /* VAV */
0xFB36, /* ZAYIN */
0x0000, /* HET */
0xFB38, /* TET */
0xFB39, /* YOD */
0xFB3A, /* FINAL KAF */
0xFB3B, /* KAF */
0xFB3C, /* LAMED */
0x0000, /* FINAL MEM */
0xFB3E, /* MEM */
0x0000, /* FINAL NUN */
0xFB40, /* NUN */
0xFB41, /* SAMEKH */
0x0000, /* AYIN */
0xFB43, /* FINAL PE */
0xFB44, /* PE */
0x0000, /* FINAL TSADI */
0xFB46, /* TSADI */
0xFB47, /* QOF */
0xFB48, /* RESH */
0xFB49, /* SHIN */
0xFB4A /* TAV */
};
bool found = c->unicode->compose (a, b, ab);
if (!found && (b & ~0x7F) == 0x0580) {
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */
switch (b) {
case 0x05B4: /* HIRIQ */
if (a == 0x05D9) { /* YOD */
*ab = 0xFB1D;
found = true;
}
break;
case 0x05B7: /* patah */
if (a == 0x05F2) { /* YIDDISH YOD YOD */
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2E;
found = true;
}
break;
case 0x05B8: /* QAMATS */
if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2F;
found = true;
}
break;
case 0x05B9: /* HOLAM */
if (a == 0x05D5) { /* VAV */
*ab = 0xFB4B;
found = true;
}
break;
case 0x05BC: /* DAGESH */
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */
*ab = 0xFB2D;
found = true;
}
break;
case 0x05BF: /* RAFE */
switch (a) {
case 0x05D1: /* BET */
*ab = 0xFB4C;
found = true;
break;
case 0x05DB: /* KAF */
*ab = 0xFB4D;
found = true;
break;
case 0x05E4: /* PE */
*ab = 0xFB4E;
found = true;
break;
}
break;
case 0x05C1: /* SHIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2C;
found = true;
}
break;
case 0x05C2: /* SIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2D;
found = true;
}
break;
}
}
return found;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default =
{
"default",
collect_features_default,
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_default,
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_default,
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
true, /* fallback_position */
};

Просмотреть файл

@ -0,0 +1,417 @@
/*
* Copyright © 2013 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-private.hh"
/* Hangul shaper */
/* Same order as the feature array below */
enum {
NONE,
LJMO,
VJMO,
TJMO,
FIRST_HANGUL_FEATURE = LJMO,
HANGUL_FEATURE_COUNT = TJMO + 1
};
static const hb_tag_t hangul_features[HANGUL_FEATURE_COUNT] =
{
HB_TAG_NONE,
HB_TAG('l','j','m','o'),
HB_TAG('v','j','m','o'),
HB_TAG('t','j','m','o')
};
static void
collect_features_hangul (hb_ot_shape_planner_t *plan)
{
hb_ot_map_builder_t *map = &plan->map;
for (unsigned int i = FIRST_HANGUL_FEATURE; i < HANGUL_FEATURE_COUNT; i++)
map->add_feature (hangul_features[i], 1, F_NONE);
}
struct hangul_shape_plan_t
{
ASSERT_POD ();
hb_mask_t mask_array[HANGUL_FEATURE_COUNT];
};
static void *
data_create_hangul (const hb_ot_shape_plan_t *plan)
{
hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
if (unlikely (!hangul_plan))
return NULL;
for (unsigned int i = 0; i < HANGUL_FEATURE_COUNT; i++)
hangul_plan->mask_array[i] = plan->map.get_1_mask (hangul_features[i]);
return hangul_plan;
}
static void
data_destroy_hangul (void *data)
{
free (data);
}
/* Constants for algorithmic hangul syllable [de]composition. */
#define LBase 0x1100
#define VBase 0x1161
#define TBase 0x11A7
#define LCount 19
#define VCount 21
#define TCount 28
#define SBase 0xAC00
#define NCount (VCount * TCount)
#define SCount (LCount * NCount)
#define isCombiningL(u) (hb_in_range<hb_codepoint_t> ((u), LBase, LBase+LCount-1))
#define isCombiningV(u) (hb_in_range<hb_codepoint_t> ((u), VBase, VBase+VCount-1))
#define isCombiningT(u) (hb_in_range<hb_codepoint_t> ((u), TBase+1, TBase+TCount-1))
#define isCombinedS(u) (hb_in_range<hb_codepoint_t> ((u), SBase, SBase+SCount-1))
#define isL(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1100, 0x115F, 0xA960, 0xA97C))
#define isV(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x1160, 0x11A7, 0xD7B0, 0xD7C6))
#define isT(u) (hb_in_ranges<hb_codepoint_t> ((u), 0x11A8, 0x11FF, 0xD7CB, 0xD7FB))
#define isHangulTone(u) (hb_in_range<hb_codepoint_t> ((u), 0x302e, 0x302f))
/* buffer var allocations */
#define hangul_shaping_feature() complex_var_u8_0() /* hangul jamo shaping feature */
static bool
is_zero_width_char (hb_font_t *font,
hb_codepoint_t unicode)
{
hb_codepoint_t glyph;
return hb_font_get_glyph (font, unicode, 0, &glyph) && hb_font_get_glyph_h_advance (font, glyph) == 0;
}
static void
preprocess_text_hangul (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
HB_BUFFER_ALLOCATE_VAR (buffer, hangul_shaping_feature);
/* Hangul syllables come in two shapes: LV, and LVT. Of those:
*
* - LV can be precomposed, or decomposed. Lets call those
* <LV> and <L,V>,
* - LVT can be fully precomposed, partically precomposed, or
* fully decomposed. Ie. <LVT>, <LV,T>, or <L,V,T>.
*
* The composition / decomposition is mechanical. However, not
* all <L,V> sequences compose, and not all <LV,T> sequences
* compose.
*
* Here are the specifics:
*
* - <L>: U+1100..115F, U+A960..A97F
* - <V>: U+1160..11A7, U+D7B0..D7C7
* - <T>: U+11A8..11FF, U+D7CB..D7FB
*
* - Only the <L,V> sequences for the 11xx ranges combine.
* - Only <LV,T> sequences for T in U+11A8..11C3 combine.
*
* Here is what we want to accomplish in this shaper:
*
* - If the whole syllable can be precomposed, do that,
* - Otherwise, fully decompose and apply ljmo/vjmo/tjmo features.
* - If a valid syllable is followed by a Hangul tone mark, reorder the tone
* mark to precede the whole syllable - unless it is a zero-width glyph, in
* which case we leave it untouched, assuming it's designed to overstrike.
*
* That is, of the different possible syllables:
*
* <L>
* <L,V>
* <L,V,T>
* <LV>
* <LVT>
* <LV, T>
*
* - <L> needs no work.
*
* - <LV> and <LVT> can stay the way they are if the font supports them, otherwise we
* should fully decompose them if font supports.
*
* - <L,V> and <L,V,T> we should compose if the whole thing can be composed.
*
* - <LV,T> we should compose if the whole thing can be composed, otherwise we should
* decompose.
*/
buffer->clear_output ();
unsigned int start = 0, end = 0; /* Extent of most recently seen syllable;
* valid only if start < end
*/
unsigned int count = buffer->len;
for (buffer->idx = 0; buffer->idx < count;)
{
hb_codepoint_t u = buffer->cur().codepoint;
if (isHangulTone (u))
{
/*
* We could cache the width of the tone marks and the existence of dotted-circle,
* but the use of the Hangul tone mark characters seems to be rare enough that
* I didn't bother for now.
*/
if (start < end && end == buffer->out_len)
{
/* Tone mark follows a valid syllable; move it in front, unless it's zero width. */
buffer->next_glyph ();
if (!is_zero_width_char (font, u))
{
hb_glyph_info_t *info = buffer->out_info;
hb_glyph_info_t tone = info[end];
memmove (&info[start + 1], &info[start], (end - start) * sizeof (hb_glyph_info_t));
info[start] = tone;
}
/* Merge clusters across the (possibly reordered) syllable+tone.
* We want to merge even in the zero-width tone mark case here,
* so that clustering behavior isn't dependent on how the tone mark
* is handled by the font.
*/
buffer->merge_out_clusters (start, end + 1);
}
else
{
/* No valid syllable as base for tone mark; try to insert dotted circle. */
if (font->has_glyph (0x25cc))
{
hb_codepoint_t chars[2];
if (!is_zero_width_char (font, u)) {
chars[0] = u;
chars[1] = 0x25cc;
} else {
chars[0] = 0x25cc;
chars[1] = u;
}
buffer->replace_glyphs (1, 2, chars);
}
else
{
/* No dotted circle available in the font; just leave tone mark untouched. */
buffer->next_glyph ();
}
}
start = end = buffer->out_len;
continue;
}
start = buffer->out_len; /* Remember current position as a potential syllable start;
* will only be used if we set end to a later position.
*/
if (isL (u) && buffer->idx + 1 < count)
{
hb_codepoint_t l = u;
hb_codepoint_t v = buffer->cur(+1).codepoint;
if (isV (v))
{
/* Have <L,V> or <L,V,T>. */
hb_codepoint_t t = 0;
unsigned int tindex = 0;
if (buffer->idx + 2 < count)
{
t = buffer->cur(+2).codepoint;
if (isT (t))
tindex = t - TBase; /* Only used if isCombiningT (t); otherwise invalid. */
else
t = 0; /* The next character was not a trailing jamo. */
}
/* We've got a syllable <L,V,T?>; see if it can potentially be composed. */
if (isCombiningL (l) && isCombiningV (v) && (t == 0 || isCombiningT (t)))
{
/* Try to compose; if this succeeds, end is set to start+1. */
hb_codepoint_t s = SBase + (l - LBase) * NCount + (v - VBase) * TCount + tindex;
if (font->has_glyph (s))
{
buffer->replace_glyphs (t ? 3 : 2, 1, &s);
if (unlikely (buffer->in_error))
return;
end = start + 1;
continue;
}
}
/* We didn't compose, either because it's an Old Hangul syllable without a
* precomposed character in Unicode, or because the font didn't support the
* necessary precomposed glyph.
* Set jamo features on the individual glyphs, and advance past them.
*/
buffer->cur().hangul_shaping_feature() = LJMO;
buffer->next_glyph ();
buffer->cur().hangul_shaping_feature() = VJMO;
buffer->next_glyph ();
if (t)
{
buffer->cur().hangul_shaping_feature() = TJMO;
buffer->next_glyph ();
end = start + 3;
}
else
end = start + 2;
buffer->merge_out_clusters (start, end);
continue;
}
}
else if (isCombinedS (u))
{
/* Have <LV>, <LVT>, or <LV,T> */
hb_codepoint_t s = u;
bool has_glyph = font->has_glyph (s);
unsigned int lindex = (s - SBase) / NCount;
unsigned int nindex = (s - SBase) % NCount;
unsigned int vindex = nindex / TCount;
unsigned int tindex = nindex % TCount;
if (!tindex &&
buffer->idx + 1 < count &&
isCombiningT (buffer->cur(+1).codepoint))
{
/* <LV,T>, try to combine. */
unsigned int new_tindex = buffer->cur(+1).codepoint - TBase;
hb_codepoint_t new_s = s + new_tindex;
if (font->has_glyph (new_s))
{
buffer->replace_glyphs (2, 1, &new_s);
if (unlikely (buffer->in_error))
return;
end = start + 1;
continue;
}
}
/* Otherwise, decompose if font doesn't support <LV> or <LVT>,
* or if having non-combining <LV,T>. Note that we already handled
* combining <LV,T> above. */
if (!has_glyph ||
(!tindex &&
buffer->idx + 1 < count &&
isT (buffer->cur(+1).codepoint)))
{
hb_codepoint_t decomposed[3] = {LBase + lindex,
VBase + vindex,
TBase + tindex};
if (font->has_glyph (decomposed[0]) &&
font->has_glyph (decomposed[1]) &&
(!tindex || font->has_glyph (decomposed[2])))
{
unsigned int s_len = tindex ? 3 : 2;
buffer->replace_glyphs (1, s_len, decomposed);
if (unlikely (buffer->in_error))
return;
/* We decomposed S: apply jamo features to the individual glyphs
* that are now in buffer->out_info.
*/
hb_glyph_info_t *info = buffer->out_info;
/* If we decomposed an LV because of a non-combining T following,
* we want to include this T in the syllable.
*/
if (has_glyph && !tindex)
{
buffer->next_glyph ();
s_len++;
}
end = start + s_len;
unsigned int i = start;
info[i++].hangul_shaping_feature() = LJMO;
info[i++].hangul_shaping_feature() = VJMO;
if (i < end)
info[i++].hangul_shaping_feature() = TJMO;
buffer->merge_out_clusters (start, end);
continue;
}
}
if (has_glyph)
{
/* We didn't decompose the S, so just advance past it. */
end = start + 1;
buffer->next_glyph ();
continue;
}
}
/* Didn't find a recognizable syllable, so we leave end <= start;
* this will prevent tone-mark reordering happening.
*/
buffer->next_glyph ();
}
buffer->swap_buffers ();
}
static void
setup_masks_hangul (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font HB_UNUSED)
{
const hangul_shape_plan_t *hangul_plan = (const hangul_shape_plan_t *) plan->data;
if (likely (hangul_plan))
{
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++, info++)
info->mask |= hangul_plan->mask_array[info->hangul_shaping_feature()];
}
HB_BUFFER_DEALLOCATE_VAR (buffer, hangul_shaping_feature);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul =
{
"hangul",
collect_features_hangul,
NULL, /* override_features */
data_create_hangul, /* data_create */
data_destroy_hangul, /* data_destroy */
preprocess_text_hangul,
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
NULL, /* decompose */
NULL, /* compose */
setup_masks_hangul, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
false, /* fallback_position */
};

Просмотреть файл

@ -0,0 +1,172 @@
/*
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-private.hh"
static bool
compose_hebrew (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
/* Hebrew presentation-form shaping.
* https://bugzilla.mozilla.org/show_bug.cgi?id=728866
* Hebrew presentation forms with dagesh, for characters 0x05D0..0x05EA;
* Note that some letters do not have a dagesh presForm encoded.
*/
static const hb_codepoint_t sDageshForms[0x05EA - 0x05D0 + 1] = {
0xFB30, /* ALEF */
0xFB31, /* BET */
0xFB32, /* GIMEL */
0xFB33, /* DALET */
0xFB34, /* HE */
0xFB35, /* VAV */
0xFB36, /* ZAYIN */
0x0000, /* HET */
0xFB38, /* TET */
0xFB39, /* YOD */
0xFB3A, /* FINAL KAF */
0xFB3B, /* KAF */
0xFB3C, /* LAMED */
0x0000, /* FINAL MEM */
0xFB3E, /* MEM */
0x0000, /* FINAL NUN */
0xFB40, /* NUN */
0xFB41, /* SAMEKH */
0x0000, /* AYIN */
0xFB43, /* FINAL PE */
0xFB44, /* PE */
0x0000, /* FINAL TSADI */
0xFB46, /* TSADI */
0xFB47, /* QOF */
0xFB48, /* RESH */
0xFB49, /* SHIN */
0xFB4A /* TAV */
};
bool found = c->unicode->compose (a, b, ab);
if (!found)
{
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */
switch (b) {
case 0x05B4: /* HIRIQ */
if (a == 0x05D9) { /* YOD */
*ab = 0xFB1D;
found = true;
}
break;
case 0x05B7: /* patah */
if (a == 0x05F2) { /* YIDDISH YOD YOD */
*ab = 0xFB1F;
found = true;
} else if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2E;
found = true;
}
break;
case 0x05B8: /* QAMATS */
if (a == 0x05D0) { /* ALEF */
*ab = 0xFB2F;
found = true;
}
break;
case 0x05B9: /* HOLAM */
if (a == 0x05D5) { /* VAV */
*ab = 0xFB4B;
found = true;
}
break;
case 0x05BC: /* DAGESH */
if (a >= 0x05D0 && a <= 0x05EA) {
*ab = sDageshForms[a - 0x05D0];
found = (*ab != 0);
} else if (a == 0xFB2A) { /* SHIN WITH SHIN DOT */
*ab = 0xFB2C;
found = true;
} else if (a == 0xFB2B) { /* SHIN WITH SIN DOT */
*ab = 0xFB2D;
found = true;
}
break;
case 0x05BF: /* RAFE */
switch (a) {
case 0x05D1: /* BET */
*ab = 0xFB4C;
found = true;
break;
case 0x05DB: /* KAF */
*ab = 0xFB4D;
found = true;
break;
case 0x05E4: /* PE */
*ab = 0xFB4E;
found = true;
break;
}
break;
case 0x05C1: /* SHIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2A;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2C;
found = true;
}
break;
case 0x05C2: /* SIN DOT */
if (a == 0x05E9) { /* SHIN */
*ab = 0xFB2B;
found = true;
} else if (a == 0xFB49) { /* SHIN WITH DAGESH */
*ab = 0xFB2D;
found = true;
}
break;
}
}
return found;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew =
{
"hebrew",
NULL, /* collect_features */
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
compose_hebrew,
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
true, /* fallback_position */
};

Просмотреть файл

@ -1690,12 +1690,6 @@ clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
}
static hb_ot_shape_normalization_mode_t
normalization_preference_indic (const hb_segment_properties_t *props HB_UNUSED)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
static bool
decompose_indic (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
@ -1806,7 +1800,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
data_create_indic,
data_destroy_indic,
NULL, /* preprocess_text */
normalization_preference_indic,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
decompose_indic,
compose_indic,
setup_masks_indic,

Просмотреть файл

@ -541,13 +541,6 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
static hb_ot_shape_normalization_mode_t
normalization_preference_myanmar (const hb_segment_properties_t *props HB_UNUSED)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
{
"myanmar",
@ -556,7 +549,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_myanmar,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_myanmar,

Просмотреть файл

@ -44,7 +44,9 @@ enum hb_ot_shape_zero_width_marks_type_t {
// HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE
};
@ -52,10 +54,13 @@ enum hb_ot_shape_zero_width_marks_type_t {
#define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \
HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \
HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \
HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \
HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \
HB_COMPLEX_SHAPER_IMPLEMENT (indic) \
HB_COMPLEX_SHAPER_IMPLEMENT (myanmar) \
HB_COMPLEX_SHAPER_IMPLEMENT (sea) \
HB_COMPLEX_SHAPER_IMPLEMENT (thai) \
HB_COMPLEX_SHAPER_IMPLEMENT (tibetan) \
/* ^--- Add new shapers here */
@ -105,12 +110,7 @@ struct hb_ot_complex_shaper_t
hb_font_t *font);
/* normalization_preference()
* Called during shape().
* May be NULL.
*/
hb_ot_shape_normalization_mode_t
(*normalization_preference) (const hb_segment_properties_t *props);
hb_ot_shape_normalization_mode_t normalization_preference;
/* decompose()
* Called during shape()'s normalization.
@ -189,19 +189,22 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
return &_hb_ot_complex_shaper_thai;
#if 0
/* Note:
* Currently we don't have a separate Hangul shaper. The default shaper handles
* Hangul by enabling jamo features. We may want to implement a separate shaper
* in the future. See this thread for details of what such a shaper would do:
*
* http://lists.freedesktop.org/archives/harfbuzz/2013-April/003070.html
*/
/* Unicode-1.1 additions */
case HB_SCRIPT_HANGUL:
return &_hb_ot_complex_shaper_hangul;
#endif
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
return &_hb_ot_complex_shaper_tibetan;
/* Unicode-1.1 additions */
case HB_SCRIPT_HEBREW:
return &_hb_ot_complex_shaper_hebrew;
/* ^--- Add new shapers here */
@ -241,9 +244,6 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
case HB_SCRIPT_LAO:
case HB_SCRIPT_THAI:
/* Unicode-2.0 additions */
case HB_SCRIPT_TIBETAN:
/* Unicode-3.2 additions */
case HB_SCRIPT_TAGALOG:
case HB_SCRIPT_TAGBANWA:

Просмотреть файл

@ -360,13 +360,6 @@ final_reordering (const hb_ot_shape_plan_t *plan,
}
static hb_ot_shape_normalization_mode_t
normalization_preference_sea (const hb_segment_properties_t *props HB_UNUSED)
{
return HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
{
"sea",
@ -375,7 +368,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_sea =
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
normalization_preference_sea,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
NULL, /* decompose */
NULL, /* compose */
setup_masks_sea,

Просмотреть файл

@ -369,10 +369,10 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai =
NULL, /* data_create */
NULL, /* data_destroy */
preprocess_text_thai,
NULL, /* normalization_preference */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE,
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
false,/* fallback_position */
};

Просмотреть файл

@ -0,0 +1,61 @@
/*
* Copyright © 2010,2012 Google, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ot-shape-complex-private.hh"
static const hb_tag_t tibetan_features[] =
{
HB_TAG('a','b','v','s'),
HB_TAG('b','l','w','s'),
HB_TAG('a','b','v','m'),
HB_TAG('b','l','w','m'),
HB_TAG_NONE
};
static void
collect_features_tibetan (hb_ot_shape_planner_t *plan)
{
for (const hb_tag_t *script_features = tibetan_features; script_features && *script_features; script_features++)
plan->map.add_global_bool_feature (*script_features);
}
const hb_ot_complex_shaper_t _hb_ot_complex_shaper_tibetan =
{
"default",
collect_features_tibetan,
NULL, /* override_features */
NULL, /* data_create */
NULL, /* data_destroy */
NULL, /* preprocess_text */
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT,
NULL, /* decompose */
NULL, /* compose */
NULL, /* setup_masks */
HB_OT_SHAPE_ZERO_WIDTH_MARKS_DEFAULT,
true, /* fallback_position */
};

Просмотреть файл

@ -430,14 +430,12 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
hb_font_t *font,
hb_buffer_t *buffer)
{
hb_mask_t kern_mask = plan->map.get_1_mask (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ?
HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
if (!kern_mask) return;
if (!plan->has_kern) return;
unsigned int count = buffer->len;
OT::hb_apply_context_t c (1, font, buffer);
c.set_lookup_mask (kern_mask);
c.set_lookup_mask (plan->kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
hb_glyph_info_t *info = buffer->info;

Просмотреть файл

@ -29,8 +29,6 @@
#include "hb-private.hh"
#include "hb-font.h"
#include "hb-buffer.h"
/* buffer var allocations, used during the normalization process */
#define glyph_index() var1.u32
@ -38,6 +36,7 @@
struct hb_ot_shape_plan_t;
enum hb_ot_shape_normalization_mode_t {
HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED,
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS, /* never composes base-to-base */
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, /* always fully decomposes and then recompose back */

Просмотреть файл

@ -213,8 +213,9 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor
}
static inline void
handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
hb_buffer_t * const buffer = c->buffer;
hb_font_t * const font = c->font;
for (; buffer->idx < end - 1;) {
@ -250,27 +251,26 @@ handle_variation_selector_cluster (const hb_ot_shape_normalize_context_t *c, uns
}
static inline void
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end)
decompose_multi_char_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool short_circuit)
{
hb_buffer_t * const buffer = c->buffer;
/* TODO Currently if there's a variation-selector we give-up, it's just too hard. */
for (unsigned int i = buffer->idx; i < end; i++)
if (unlikely (buffer->unicode->is_variation_selector (buffer->info[i].codepoint))) {
handle_variation_selector_cluster (c, end);
handle_variation_selector_cluster (c, end, short_circuit);
return;
}
while (buffer->idx < end)
decompose_current_character (c, false);
decompose_current_character (c, short_circuit);
}
static inline void
decompose_cluster (const hb_ot_shape_normalize_context_t *c, bool short_circuit, unsigned int end)
decompose_cluster (const hb_ot_shape_normalize_context_t *c, unsigned int end, bool might_short_circuit, bool always_short_circuit)
{
if (likely (c->buffer->idx + 1 == end))
decompose_current_character (c, short_circuit);
decompose_current_character (c, might_short_circuit);
else
decompose_multi_char_cluster (c, end);
decompose_multi_char_cluster (c, end, always_short_circuit);
}
@ -289,9 +289,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
hb_buffer_t *buffer,
hb_font_t *font)
{
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference ?
plan->shaper->normalization_preference (&buffer->props) :
HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT;
hb_ot_shape_normalization_mode_t mode = plan->shaper->normalization_preference;
const hb_ot_shape_normalize_context_t c = {
plan,
buffer,
@ -301,8 +299,10 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};
bool short_circuit = mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT;
bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
bool might_short_circuit = always_short_circuit ||
(mode != HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED &&
mode != HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT);
unsigned int count;
/* We do a fairly straightforward yet custom normalization process in three
@ -323,7 +323,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
if (buffer->cur().cluster != buffer->info[end].cluster)
break;
decompose_cluster (&c, short_circuit, end);
decompose_cluster (&c, end, might_short_circuit, always_short_circuit);
}
buffer->swap_buffers ();
@ -355,7 +355,8 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
}
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
if (mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE ||
mode == HB_OT_SHAPE_NORMALIZATION_MODE_DECOMPOSED)
return;
/* Third round, recompose */
@ -393,8 +394,9 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
return;
buffer->merge_out_clusters (starter, buffer->out_len);
buffer->out_len--; /* Remove the second composable. */
buffer->out_info[starter].codepoint = composed; /* Modify starter and carry on. */
set_glyph (buffer->out_info[starter], font);
/* Modify starter and carry on. */
buffer->out_info[starter].codepoint = composed;
buffer->out_info[starter].glyph_index() = glyph;
_hb_glyph_info_set_unicode_props (&buffer->out_info[starter], buffer->unicode);
continue;

Просмотреть файл

@ -40,6 +40,10 @@ struct hb_ot_shape_plan_t
const struct hb_ot_complex_shaper_t *shaper;
hb_ot_map_t map;
const void *data;
hb_mask_t rtlm_mask, frac_mask, numr_mask, dnom_mask;
hb_mask_t kern_mask;
unsigned int has_frac : 1;
unsigned int has_kern : 1;
inline void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const
{
@ -77,6 +81,17 @@ struct hb_ot_shape_planner_t
plan.props = props;
plan.shaper = shaper;
map.compile (plan.map);
plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m'));
plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c'));
plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r'));
plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m'));
plan.kern_mask = plan.map.get_mask (HB_DIRECTION_IS_HORIZONTAL (plan.props.direction) ?
HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'));
plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask);
plan.has_kern = !!plan.kern_mask;
}
private:

Просмотреть файл

@ -88,6 +88,10 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
break;
}
map->add_feature (HB_TAG ('f','r','a','c'), 1, F_NONE);
map->add_feature (HB_TAG ('n','u','m','r'), 1, F_NONE);
map->add_feature (HB_TAG ('d','n','o','m'), 1, F_NONE);
if (planner->shaper->collect_features)
planner->shaper->collect_features (planner);
@ -234,8 +238,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font)
HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
return;
hb_codepoint_t dottedcircle_glyph;
if (!font->get_glyph (0x25CC, 0, &dottedcircle_glyph))
if (!font->has_glyph (0x25CC))
return;
hb_glyph_info_t dottedcircle;
@ -292,7 +295,7 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
hb_buffer_t *buffer = c->buffer;
hb_unicode_funcs_t *unicode = buffer->unicode;
hb_mask_t rtlm_mask = c->plan->map.get_1_mask (HB_TAG ('r','t','l','m'));
hb_mask_t rtlm_mask = c->plan->rtlm_mask;
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
@ -306,13 +309,58 @@ hb_ot_mirror_chars (hb_ot_shape_context_t *c)
}
static inline void
hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
hb_ot_shape_setup_masks_fraction (hb_ot_shape_context_t *c)
{
if (!c->plan->has_frac)
return;
hb_buffer_t *buffer = c->buffer;
/* TODO look in pre/post context text also. */
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
for (unsigned int i = 0; i < count; i++)
{
if (info[i].codepoint == 0x2044) /* FRACTION SLASH */
{
unsigned int start = i, end = i + 1;
while (start &&
_hb_glyph_info_get_general_category (&info[start - 1]) ==
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
start--;
while (end < count &&
_hb_glyph_info_get_general_category (&info[end]) ==
HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER)
end++;
for (unsigned int j = start; j < i; j++)
info[j].mask |= c->plan->numr_mask | c->plan->frac_mask;
info[i].mask |= c->plan->frac_mask;
for (unsigned int j = i + 1; j < end; j++)
info[j].mask |= c->plan->frac_mask | c->plan->dnom_mask;
i = end - 1;
}
}
}
static inline void
hb_ot_shape_initialize_masks (hb_ot_shape_context_t *c)
{
hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
hb_mask_t global_mask = map->get_global_mask ();
buffer->reset_masks (global_mask);
}
static inline void
hb_ot_shape_setup_masks (hb_ot_shape_context_t *c)
{
hb_ot_map_t *map = &c->plan->map;
hb_buffer_t *buffer = c->buffer;
hb_ot_shape_setup_masks_fraction (c);
if (c->plan->shaper->setup_masks)
c->plan->shaper->setup_masks (c->plan, buffer, c->font);
@ -358,6 +406,8 @@ hb_ot_substitute_default (hb_ot_shape_context_t *c)
if (c->plan->shaper->preprocess_text)
c->plan->shaper->preprocess_text (c->plan, buffer, c->font);
hb_ot_shape_initialize_masks (c);
hb_ot_mirror_chars (c);
HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index);

Просмотреть файл

@ -0,0 +1,54 @@
/*
* Copyright © 2013 Red Hat, Inc.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Red Hat Author(s): Behdad Esfahbod
*/
#ifndef HB_OT_SHAPE_H
#define HB_OT_SHAPE_H
#define HB_OT_SHAPE_H_IN
#include "hb.h"
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
HB_BEGIN_DECLS
/* TODO port to shape-plan / set. */
void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
hb_set_t *glyphs);
void
hb_ot_shape_plan_collect_lookups (hb_shape_plan_t *shape_plan,
hb_tag_t table_tag,
hb_set_t *lookup_indexes /* OUT */);
HB_END_DECLS
#undef HB_OT_SHAPE_H_IN
#endif /* HB_OT_SHAPE_H */

Просмотреть файл

@ -27,7 +27,6 @@
*/
#include "hb-private.hh"
#include "hb-ot.h"
#include <string.h>

Просмотреть файл

@ -32,17 +32,10 @@
#include "hb-ot-layout.h"
#include "hb-ot-tag.h"
#include "hb-ot-shape.h"
HB_BEGIN_DECLS
/* TODO remove */
void
hb_ot_shape_glyphs_closure (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
hb_set_t *glyphs);
HB_END_DECLS
#undef HB_OT_H_IN

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше