This commit is contained in:
Phil Ringnalda 2015-09-12 08:56:45 -07:00
Родитель 0621f5bc81 99e730c642
Коммит 43c1e6ab4d
217 изменённых файлов: 7103 добавлений и 4308 удалений

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

@ -1,13 +1,13 @@
[
{
"clang_version": "r183744"
"clang_version": "r241406"
},
{
"size": 70350828,
"digest": "6cd04e8ec44c6fef159349c22bd0476891e4a2d46479f9586283eaf3305e42f79c720d40dfec0e78d8899c1651189b12e285de60862ffd0612b0dac7a0c336c6",
"size": 100307285,
"digest": "4d147d0072a928945fc1e938f39a5d0a9d3c676399c09e092c8750b2f973cdbbebda8d94d4d05805fae74a5c49c54263dc22b8b443c23c9a0ae830a261d3cf30",
"algorithm": "sha512",
"unpack": true,
"filename": "clang.tar.bz2"
"filename": "clang.tar.bz2",
"unpack": true
},
{
"size": 80458572,

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

@ -1936,7 +1936,7 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType,
message = eQueryCaretRect;
break;
case QUERY_TEXT_RECT:
message = NS_QUERY_TEXT_RECT;
message = eQueryTextRect;
break;
case QUERY_EDITOR_RECT:
message = eQueryEditorRect;
@ -1991,7 +1991,7 @@ nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType,
case eQueryCaretRect:
queryEvent.InitForQueryCaretRect(aOffset, useNativeLineBreak);
break;
case NS_QUERY_TEXT_RECT:
case eQueryTextRect:
queryEvent.InitForQueryTextRect(aOffset, aLength, useNativeLineBreak);
break;
default:

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

@ -3886,7 +3886,7 @@ void
nsDocument::DeleteShell()
{
mExternalResourceMap.HideViewers();
if (IsEventHandlingEnabled()) {
if (IsEventHandlingEnabled() && !AnimationsPaused()) {
RevokeAnimationFrameNotifications();
}
if (nsPresContext* presContext = mPresShell->GetPresContext()) {
@ -4632,7 +4632,7 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
// our layout history state now.
mLayoutHistoryState = GetLayoutHistoryState();
if (mPresShell && !EventHandlingSuppressed()) {
if (mPresShell && !EventHandlingSuppressed() && !AnimationsPaused()) {
RevokeAnimationFrameNotifications();
}
@ -10318,7 +10318,8 @@ nsIDocument::ScheduleFrameRequestCallback(FrameRequestCallback& aCallback,
DebugOnly<FrameRequest*> request =
mFrameRequestCallbacks.AppendElement(FrameRequest(aCallback, newHandle));
NS_ASSERTION(request, "This is supposed to be infallible!");
if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled()) {
if (!alreadyRegistered && mPresShell && IsEventHandlingEnabled() &&
!AnimationsPaused()) {
mPresShell->GetPresContext()->RefreshDriver()->
ScheduleFrameRequestCallbacks(this);
}

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

@ -1449,8 +1449,8 @@ nsGlobalWindow::CleanUp()
}
#ifdef MOZ_B2G
DisableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
DisableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
DisableNetworkEvent(eNetworkUpload);
DisableNetworkEvent(eNetworkDownload);
#endif // MOZ_B2G
if (mIdleService) {
@ -14601,13 +14601,13 @@ nsGlobalWindow::EnableNetworkEvent(EventMessage aEventMessage)
}
switch (aEventMessage) {
case NS_NETWORK_UPLOAD_EVENT:
case eNetworkUpload:
if (!mNetworkUploadObserverEnabled) {
mNetworkUploadObserverEnabled = true;
os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC, false);
}
break;
case NS_NETWORK_DOWNLOAD_EVENT:
case eNetworkDownload:
if (!mNetworkDownloadObserverEnabled) {
mNetworkDownloadObserverEnabled = true;
os->AddObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC, false);
@ -14629,13 +14629,13 @@ nsGlobalWindow::DisableNetworkEvent(EventMessage aEventMessage)
}
switch (aEventMessage) {
case NS_NETWORK_UPLOAD_EVENT:
case eNetworkUpload:
if (mNetworkUploadObserverEnabled) {
mNetworkUploadObserverEnabled = false;
os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_UPLOAD_TOPIC);
}
break;
case NS_NETWORK_DOWNLOAD_EVENT:
case eNetworkDownload:
if (mNetworkDownloadObserverEnabled) {
mNetworkDownloadObserverEnabled = false;
os->RemoveObserver(mObserver, NS_NETWORK_ACTIVITY_BLIP_DOWNLOAD_TOPIC);

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

@ -58,7 +58,7 @@ nsQueryContentEventResult::GetTentativeCaretOffset(uint32_t* aOffset)
static bool IsRectEnabled(EventMessage aEventMessage)
{
return aEventMessage == eQueryCaretRect ||
aEventMessage == NS_QUERY_TEXT_RECT ||
aEventMessage == eQueryTextRect ||
aEventMessage == eQueryEditorRect ||
aEventMessage == eQueryCharacterAtPoint;
}

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

@ -13,6 +13,7 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/dom/BlobSet.h"
#include "mozilla/dom/File.h"
#include "mozilla/dom/FetchUtil.h"
#include "mozilla/dom/XMLHttpRequestUploadBinding.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventListenerManager.h"
@ -1617,31 +1618,10 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
// Disallow HTTP/1.1 TRACE method (see bug 302489)
// and MS IIS equivalent TRACK (see bug 381264)
// and CONNECT
if (inMethod.LowerCaseEqualsLiteral("trace") ||
inMethod.LowerCaseEqualsLiteral("connect") ||
inMethod.LowerCaseEqualsLiteral("track")) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsAutoCString method;
// GET, POST, DELETE, HEAD, OPTIONS, PUT methods normalized to upper case
if (inMethod.LowerCaseEqualsLiteral("get")) {
method.AssignLiteral("GET");
} else if (inMethod.LowerCaseEqualsLiteral("post")) {
method.AssignLiteral("POST");
} else if (inMethod.LowerCaseEqualsLiteral("delete")) {
method.AssignLiteral("DELETE");
} else if (inMethod.LowerCaseEqualsLiteral("head")) {
method.AssignLiteral("HEAD");
} else if (inMethod.LowerCaseEqualsLiteral("options")) {
method.AssignLiteral("OPTIONS");
} else if (inMethod.LowerCaseEqualsLiteral("put")) {
method.AssignLiteral("PUT");
} else {
method = inMethod; // other methods are not normalized
nsresult rv = FetchUtil::GetValidRequestMethod(inMethod, method);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// sync request is not allowed using withCredential or responseType
@ -1662,7 +1642,6 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url,
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
}
nsresult rv;
nsCOMPtr<nsIURI> uri;
if (mState & (XML_HTTP_REQUEST_OPENED |

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

@ -802,7 +802,7 @@ ContentEventHandler::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
return OnQueryTextContent(aEvent);
case eQueryCaretRect:
return OnQueryCaretRect(aEvent);
case NS_QUERY_TEXT_RECT:
case eQueryTextRect:
return OnQueryTextRect(aEvent);
case eQueryEditorRect:
return OnQueryEditorRect(aEvent);
@ -1330,7 +1330,7 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent)
GetLineBreakType(aEvent));
NS_ENSURE_SUCCESS(rv, rv);
WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, aEvent->widget);
WidgetQueryContentEvent textRect(true, eQueryTextRect, aEvent->widget);
textRect.InitForQueryTextRect(offset, 1, aEvent->mUseNativeLineBreak);
rv = OnQueryTextRect(&textRect);
NS_ENSURE_SUCCESS(rv, rv);

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

@ -48,7 +48,7 @@ public:
nsresult OnQueryTextContent(WidgetQueryContentEvent* aEvent);
// eQueryCaretRect event handler
nsresult OnQueryCaretRect(WidgetQueryContentEvent* aEvent);
// NS_QUERY_TEXT_RECT event handler
// eQueryTextRect event handler
nsresult OnQueryTextRect(WidgetQueryContentEvent* aEvent);
// eQueryEditorRect event handler
nsresult OnQueryEditorRect(WidgetQueryContentEvent* aEvent);

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

@ -318,13 +318,13 @@ EventListenerManager::AddEventListenerInternal(
kAllMutationBits : MutationBitForEventType(aEventMessage));
}
} else if (aTypeAtom == nsGkAtoms::ondeviceorientation) {
EnableDevice(NS_DEVICE_ORIENTATION);
EnableDevice(eDeviceOrientation);
} else if (aTypeAtom == nsGkAtoms::ondeviceproximity || aTypeAtom == nsGkAtoms::onuserproximity) {
EnableDevice(NS_DEVICE_PROXIMITY);
EnableDevice(eDeviceProximity);
} else if (aTypeAtom == nsGkAtoms::ondevicelight) {
EnableDevice(NS_DEVICE_LIGHT);
EnableDevice(eDeviceLight);
} else if (aTypeAtom == nsGkAtoms::ondevicemotion) {
EnableDevice(NS_DEVICE_MOTION);
EnableDevice(eDeviceMotion);
#ifdef MOZ_B2G
} else if (aTypeAtom == nsGkAtoms::onmoztimechange) {
nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
@ -334,12 +334,12 @@ EventListenerManager::AddEventListenerInternal(
} else if (aTypeAtom == nsGkAtoms::onmoznetworkupload) {
nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
if (window) {
window->EnableNetworkEvent(NS_NETWORK_UPLOAD_EVENT);
window->EnableNetworkEvent(eNetworkUpload);
}
} else if (aTypeAtom == nsGkAtoms::onmoznetworkdownload) {
nsCOMPtr<nsPIDOMWindow> window = GetTargetAsInnerWindow();
if (window) {
window->EnableNetworkEvent(NS_NETWORK_DOWNLOAD_EVENT);
window->EnableNetworkEvent(eNetworkDownload);
}
#endif // MOZ_B2G
} else if (aTypeAtom == nsGkAtoms::ontouchstart ||
@ -383,8 +383,8 @@ EventListenerManager::AddEventListenerInternal(
window->SetHasMouseEnterLeaveEventListeners();
}
#ifdef MOZ_GAMEPAD
} else if (aEventMessage >= NS_GAMEPAD_START &&
aEventMessage <= NS_GAMEPAD_END) {
} else if (aEventMessage >= eGamepadEventFirst &&
aEventMessage <= eGamepadEventLast) {
nsPIDOMWindow* window = GetInnerWindowForTarget();
if (window) {
window->SetHasGamepadEventListener();
@ -419,11 +419,11 @@ bool
EventListenerManager::IsDeviceType(EventMessage aEventMessage)
{
switch (aEventMessage) {
case NS_DEVICE_ORIENTATION:
case NS_DEVICE_MOTION:
case NS_DEVICE_LIGHT:
case NS_DEVICE_PROXIMITY:
case NS_USER_PROXIMITY:
case eDeviceOrientation:
case eDeviceMotion:
case eDeviceLight:
case eDeviceProximity:
case eUserProximity:
return true;
default:
break;
@ -440,17 +440,17 @@ EventListenerManager::EnableDevice(EventMessage aEventMessage)
}
switch (aEventMessage) {
case NS_DEVICE_ORIENTATION:
case eDeviceOrientation:
window->EnableDeviceSensor(SENSOR_ORIENTATION);
break;
case NS_DEVICE_PROXIMITY:
case NS_USER_PROXIMITY:
case eDeviceProximity:
case eUserProximity:
window->EnableDeviceSensor(SENSOR_PROXIMITY);
break;
case NS_DEVICE_LIGHT:
case eDeviceLight:
window->EnableDeviceSensor(SENSOR_LIGHT);
break;
case NS_DEVICE_MOTION:
case eDeviceMotion:
window->EnableDeviceSensor(SENSOR_ACCELERATION);
window->EnableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
window->EnableDeviceSensor(SENSOR_GYROSCOPE);
@ -470,19 +470,19 @@ EventListenerManager::DisableDevice(EventMessage aEventMessage)
}
switch (aEventMessage) {
case NS_DEVICE_ORIENTATION:
case eDeviceOrientation:
window->DisableDeviceSensor(SENSOR_ORIENTATION);
break;
case NS_DEVICE_MOTION:
case eDeviceMotion:
window->DisableDeviceSensor(SENSOR_ACCELERATION);
window->DisableDeviceSensor(SENSOR_LINEAR_ACCELERATION);
window->DisableDeviceSensor(SENSOR_GYROSCOPE);
break;
case NS_DEVICE_PROXIMITY:
case NS_USER_PROXIMITY:
case eDeviceProximity:
case eUserProximity:
window->DisableDeviceSensor(SENSOR_PROXIMITY);
break;
case NS_DEVICE_LIGHT:
case eDeviceLight:
window->DisableDeviceSensor(SENSOR_LIGHT);
break;
default:
@ -510,9 +510,9 @@ EventListenerManager::RemoveEventListenerInternal(
uint32_t typeCount = 0;
bool deviceType = IsDeviceType(aEventMessage);
#ifdef MOZ_B2G
bool timeChangeEvent = (aEventMessage == NS_MOZ_TIME_CHANGE_EVENT);
bool networkEvent = (aEventMessage == NS_NETWORK_UPLOAD_EVENT ||
aEventMessage == NS_NETWORK_DOWNLOAD_EVENT);
bool timeChangeEvent = (aEventMessage == eTimeChange);
bool networkEvent = (aEventMessage == eNetworkUpload ||
aEventMessage == eNetworkDownload);
#endif // MOZ_B2G
for (uint32_t i = 0; i < count; ++i) {

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

@ -303,11 +303,11 @@ EVENT(mozfullscreenerror,
EventNameType_HTML,
eBasicEventClass)
EVENT(mozpointerlockchange,
NS_POINTERLOCKCHANGE,
ePointerLockChange,
EventNameType_HTML,
eBasicEventClass)
EVENT(mozpointerlockerror,
NS_POINTERLOCKERROR,
ePointerLockError,
EventNameType_HTML,
eBasicEventClass)
EVENT(pointerdown,
@ -469,11 +469,11 @@ FORWARDED_EVENT(scroll,
eBasicEventClass)
WINDOW_EVENT(afterprint,
NS_AFTERPRINT,
eAfterPrint,
EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
eBasicEventClass)
WINDOW_EVENT(beforeprint,
NS_BEFOREPRINT,
eBeforePrint,
EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
eBasicEventClass)
BEFOREUNLOAD_EVENT(beforeunload,
@ -528,37 +528,37 @@ WINDOW_EVENT(unload,
eBasicEventClass)
WINDOW_ONLY_EVENT(devicemotion,
NS_DEVICE_MOTION,
eDeviceMotion,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(deviceorientation,
NS_DEVICE_ORIENTATION,
eDeviceOrientation,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(deviceproximity,
NS_DEVICE_PROXIMITY,
eDeviceProximity,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(userproximity,
NS_USER_PROXIMITY,
eUserProximity,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(devicelight,
NS_DEVICE_LIGHT,
eDeviceLight,
EventNameType_None,
eBasicEventClass)
#ifdef MOZ_B2G
WINDOW_ONLY_EVENT(moztimechange,
NS_MOZ_TIME_CHANGE_EVENT,
eTimeChange,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(moznetworkupload,
NS_NETWORK_UPLOAD_EVENT,
eNetworkUpload,
EventNameType_None,
eBasicEventClass)
WINDOW_ONLY_EVENT(moznetworkdownload,
NS_NETWORK_DOWNLOAD_EVENT,
eNetworkDownload,
EventNameType_None,
eBasicEventClass)
#endif // MOZ_B2G
@ -672,19 +672,19 @@ NON_IDL_EVENT(speakerforcedchange,
// This shouldn't be used by web/xul apps. "compositionupdate" should be
// used instead.
NON_IDL_EVENT(text,
NS_COMPOSITION_CHANGE,
eCompositionChange,
EventNameType_XUL,
eCompositionEventClass)
NON_IDL_EVENT(compositionstart,
NS_COMPOSITION_START,
eCompositionStart,
EventNameType_XUL,
eCompositionEventClass)
NON_IDL_EVENT(compositionupdate,
NS_COMPOSITION_UPDATE,
eCompositionUpdate,
EventNameType_XUL,
eCompositionEventClass)
NON_IDL_EVENT(compositionend,
NS_COMPOSITION_END,
eCompositionEnd,
EventNameType_XUL,
eCompositionEventClass)
NON_IDL_EVENT(command,
@ -732,11 +732,11 @@ NON_IDL_EVENT(draggesture,
EventNameType_XUL,
eDragEventClass)
NON_IDL_EVENT(overflow,
NS_SCROLLPORT_OVERFLOW,
eScrollPortOverflow,
EventNameType_XUL,
eBasicEventClass)
NON_IDL_EVENT(underflow,
NS_SCROLLPORT_UNDERFLOW,
eScrollPortUnderflow,
EventNameType_XUL,
eBasicEventClass)
@ -774,34 +774,34 @@ NON_IDL_EVENT(zoom,
// Only map the ID to the real event name when MESSAGE_TO_EVENT is defined.
#ifndef MESSAGE_TO_EVENT
NON_IDL_EVENT(begin,
NS_SMIL_BEGIN,
eSMILBeginEvent,
EventNameType_SMIL,
eBasicEventClass)
#endif
NON_IDL_EVENT(beginEvent,
NS_SMIL_BEGIN,
eSMILBeginEvent,
EventNameType_None,
eSMILTimeEventClass)
// Only map the ID to the real event name when MESSAGE_TO_EVENT is defined.
#ifndef MESSAGE_TO_EVENT
NON_IDL_EVENT(end,
NS_SMIL_END,
eSMILEndEvent,
EventNameType_SMIL,
eBasicEventClass)
#endif
NON_IDL_EVENT(endEvent,
NS_SMIL_END,
eSMILEndEvent,
EventNameType_None,
eSMILTimeEventClass)
// Only map the ID to the real event name when MESSAGE_TO_EVENT is defined.
#ifndef MESSAGE_TO_EVENT
NON_IDL_EVENT(repeat,
NS_SMIL_REPEAT,
eSMILRepeatEvent,
EventNameType_SMIL,
eBasicEventClass)
#endif
NON_IDL_EVENT(repeatEvent,
NS_SMIL_REPEAT,
eSMILRepeatEvent,
EventNameType_None,
eSMILTimeEventClass)
@ -811,29 +811,29 @@ NON_IDL_EVENT(MozAfterPaint,
eBasicEventClass)
NON_IDL_EVENT(MozScrolledAreaChanged,
NS_SCROLLEDAREACHANGED,
eScrolledAreaChanged,
EventNameType_None,
eScrollAreaEventClass)
#ifdef MOZ_GAMEPAD
NON_IDL_EVENT(gamepadbuttondown,
NS_GAMEPAD_BUTTONDOWN,
eGamepadButtonDown,
EventNameType_None,
eBasicEventClass)
NON_IDL_EVENT(gamepadbuttonup,
NS_GAMEPAD_BUTTONUP,
eGamepadButtonUp,
EventNameType_None,
eBasicEventClass)
NON_IDL_EVENT(gamepadaxismove,
NS_GAMEPAD_AXISMOVE,
eGamepadAxisMove,
EventNameType_None,
eBasicEventClass)
NON_IDL_EVENT(gamepadconnected,
NS_GAMEPAD_CONNECTED,
eGamepadConnected,
EventNameType_None,
eBasicEventClass)
NON_IDL_EVENT(gamepaddisconnected,
NS_GAMEPAD_DISCONNECTED,
eGamepadDisconnected,
EventNameType_None,
eBasicEventClass)
#endif

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

@ -759,7 +759,7 @@ EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
case eContentCommandScroll:
DoContentCommandScrollEvent(aEvent->AsContentCommandEvent());
break;
case NS_COMPOSITION_START:
case eCompositionStart:
if (aEvent->mFlags.mIsTrusted) {
// If the event is trusted event, set the selected text to data of
// composition event.
@ -784,7 +784,7 @@ EventStateManager::HandleQueryContentEvent(WidgetQueryContentEvent* aEvent)
case eQuerySelectedText:
case eQueryTextContent:
case eQueryCaretRect:
case NS_QUERY_TEXT_RECT:
case eQueryTextRect:
case eQueryEditorRect:
if (!IsTargetCrossProcess(aEvent)) {
break;
@ -2563,7 +2563,7 @@ EventStateManager::DecideGestureEvent(WidgetGestureNotifyEvent* aEvent,
nsIFrame* targetFrame)
{
NS_ASSERTION(aEvent->mMessage == NS_GESTURENOTIFY_EVENT_START,
NS_ASSERTION(aEvent->mMessage == eGestureNotify,
"DecideGestureEvent called with a non-gesture event");
/* Check the ancestor tree to decide if any frame is willing* to receive
@ -3133,7 +3133,7 @@ EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
break;
case NS_GESTURENOTIFY_EVENT_START:
case eGestureNotify:
{
if (nsEventStatus_eConsumeNoDefault != *aStatus) {
DecideGestureEvent(aEvent->AsGestureNotifyEvent(), mCurrentTarget);

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

@ -57,8 +57,8 @@ ToChar(EventMessage aEventMessage)
return "eQueryTextContent";
case eQueryCaretRect:
return "eQueryCaretRect";
case NS_QUERY_TEXT_RECT:
return "NS_QUERY_TEXT_RECT";
case eQueryTextRect:
return "eQueryTextRect";
case eQueryEditorRect:
return "eQueryEditorRect";
case eQueryContentState:

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

@ -137,18 +137,18 @@ static const char*
GetEventMessageName(EventMessage aMessage)
{
switch (aMessage) {
case NS_COMPOSITION_START:
return "NS_COMPOSITION_START";
case NS_COMPOSITION_END:
return "NS_COMPOSITION_END";
case NS_COMPOSITION_UPDATE:
return "NS_COMPOSITION_UPDATE";
case NS_COMPOSITION_CHANGE:
return "NS_COMPOSITION_CHANGE";
case NS_COMPOSITION_COMMIT_AS_IS:
return "NS_COMPOSITION_COMMIT_AS_IS";
case NS_COMPOSITION_COMMIT:
return "NS_COMPOSITION_COMMIT";
case eCompositionStart:
return "eCompositionStart";
case eCompositionEnd:
return "eCompositionEnd";
case eCompositionUpdate:
return "eCompositionUpdate";
case eCompositionChange:
return "eCompositionChange";
case eCompositionCommitAsIs:
return "eCompositionCommitAsIs";
case eCompositionCommit:
return "eCompositionCommit";
case eSetSelection:
return "eSetSelection";
default:
@ -1147,7 +1147,7 @@ IMEStateManager::DispatchCompositionEvent(
return;
}
MOZ_ASSERT(aCompositionEvent->mMessage != NS_COMPOSITION_UPDATE,
MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionUpdate,
"compositionupdate event shouldn't be dispatched manually");
EnsureTextCompositionArray();
@ -1163,7 +1163,7 @@ IMEStateManager::DispatchCompositionEvent(
MOZ_LOG(sISMLog, LogLevel::Debug,
("ISM: IMEStateManager::DispatchCompositionEvent(), "
"adding new TextComposition to the array"));
MOZ_ASSERT(aCompositionEvent->mMessage == NS_COMPOSITION_START);
MOZ_ASSERT(aCompositionEvent->mMessage == eCompositionStart);
composition =
new TextComposition(aPresContext, aEventTargetNode, tabParent,
aCompositionEvent);
@ -1171,7 +1171,7 @@ IMEStateManager::DispatchCompositionEvent(
}
#ifdef DEBUG
else {
MOZ_ASSERT(aCompositionEvent->mMessage != NS_COMPOSITION_START);
MOZ_ASSERT(aCompositionEvent->mMessage != eCompositionStart);
}
#endif // #ifdef DEBUG
@ -1277,7 +1277,7 @@ IMEStateManager::OnCompositionEventDiscarded(
// Ignore compositionstart for now because sTextCompositions may not have
// been created yet.
if (aCompositionEvent->mMessage == NS_COMPOSITION_START) {
if (aCompositionEvent->mMessage == eCompositionStart) {
return;
}

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

@ -93,7 +93,7 @@ TextComposition::MaybeDispatchCompositionUpdate(
if (mLastData == aCompositionEvent->mData) {
return true;
}
CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_UPDATE);
CloneAndDispatchAs(aCompositionEvent, eCompositionUpdate);
return IsValidStateForComposition(aCompositionEvent->widget);
}
@ -120,7 +120,7 @@ TextComposition::CloneAndDispatchAs(
nsEventStatus dummyStatus = nsEventStatus_eConsumeNoDefault;
nsEventStatus* status = aStatus ? aStatus : &dummyStatus;
if (aMessage == NS_COMPOSITION_UPDATE) {
if (aMessage == eCompositionUpdate) {
mLastData = compositionEvent.mData;
}
EventDispatcher::Dispatch(mNode, mPresContext,
@ -234,12 +234,12 @@ TextComposition::DispatchCompositionEvent(
RemoveControlCharactersFrom(aCompositionEvent->mData,
aCompositionEvent->mRanges);
}
if (aCompositionEvent->mMessage == NS_COMPOSITION_COMMIT_AS_IS) {
if (aCompositionEvent->mMessage == eCompositionCommitAsIs) {
NS_ASSERTION(!aCompositionEvent->mRanges,
"mRanges of NS_COMPOSITION_COMMIT_AS_IS should be null");
"mRanges of eCompositionCommitAsIs should be null");
aCompositionEvent->mRanges = nullptr;
NS_ASSERTION(aCompositionEvent->mData.IsEmpty(),
"mData of NS_COMPOSITION_COMMIT_AS_IS should be empty string");
"mData of eCompositionCommitAsIs should be empty string");
if (mLastData == IDEOGRAPHIC_SPACE) {
// If the last data is an ideographic space (FullWidth space), it must be
// a placeholder character of some Chinese IME. So, committing with
@ -248,9 +248,9 @@ TextComposition::DispatchCompositionEvent(
} else {
aCompositionEvent->mData = mLastData;
}
} else if (aCompositionEvent->mMessage == NS_COMPOSITION_COMMIT) {
} else if (aCompositionEvent->mMessage == eCompositionCommit) {
NS_ASSERTION(!aCompositionEvent->mRanges,
"mRanges of NS_COMPOSITION_COMMIT should be null");
"mRanges of eCompositionCommit should be null");
aCompositionEvent->mRanges = nullptr;
}
@ -284,10 +284,10 @@ TextComposition::DispatchCompositionEvent(
if (!aIsSynthesized && (mIsRequestingCommit || mIsRequestingCancel)) {
nsString* committingData = nullptr;
switch (aCompositionEvent->mMessage) {
case NS_COMPOSITION_END:
case NS_COMPOSITION_CHANGE:
case NS_COMPOSITION_COMMIT_AS_IS:
case NS_COMPOSITION_COMMIT:
case eCompositionEnd:
case eCompositionChange:
case eCompositionCommitAsIs:
case eCompositionCommit:
committingData = &aCompositionEvent->mData;
break;
default:
@ -309,20 +309,20 @@ TextComposition::DispatchCompositionEvent(
bool dispatchDOMTextEvent = aCompositionEvent->CausesDOMTextEvent();
// When mIsComposing is false but the committing string is different from
// the last data (E.g., previous NS_COMPOSITION_CHANGE event made the
// the last data (E.g., previous eCompositionChange event made the
// composition string empty or didn't have clause information), we don't
// need to dispatch redundant DOM text event.
if (dispatchDOMTextEvent &&
aCompositionEvent->mMessage != NS_COMPOSITION_CHANGE &&
aCompositionEvent->mMessage != eCompositionChange &&
!mIsComposing && mLastData == aCompositionEvent->mData) {
dispatchEvent = dispatchDOMTextEvent = false;
}
// widget may dispatch redundant NS_COMPOSITION_CHANGE event
// widget may dispatch redundant eCompositionChange event
// which modifies neither composition string, clauses nor caret
// position. In such case, we shouldn't dispatch DOM events.
if (dispatchDOMTextEvent &&
aCompositionEvent->mMessage == NS_COMPOSITION_CHANGE &&
aCompositionEvent->mMessage == eCompositionChange &&
mLastData == aCompositionEvent->mData &&
mRanges && aCompositionEvent->mRanges &&
mRanges->Equals(*aCompositionEvent->mRanges)) {
@ -337,13 +337,13 @@ TextComposition::DispatchCompositionEvent(
if (dispatchEvent) {
// If the composition event should cause a DOM text event, we should
// overwrite the event message as NS_COMPOSITION_CHANGE because due to
// overwrite the event message as eCompositionChange because due to
// the limitation of mapping between event messages and DOM event types,
// we cannot map multiple event messages to a DOM event type.
if (dispatchDOMTextEvent &&
aCompositionEvent->mMessage != NS_COMPOSITION_CHANGE) {
aCompositionEvent->mMessage != eCompositionChange) {
aCompositionEvent->mFlags =
CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_CHANGE,
CloneAndDispatchAs(aCompositionEvent, eCompositionChange,
aStatus, aCallBack);
} else {
EventDispatcher::Dispatch(mNode, mPresContext,
@ -366,8 +366,8 @@ TextComposition::DispatchCompositionEvent(
if (aCompositionEvent->CausesDOMCompositionEndEvent()) {
// Dispatch a compositionend event if it's necessary.
if (aCompositionEvent->mMessage != NS_COMPOSITION_END) {
CloneAndDispatchAs(aCompositionEvent, NS_COMPOSITION_END);
if (aCompositionEvent->mMessage != eCompositionEnd) {
CloneAndDispatchAs(aCompositionEvent, eCompositionEnd);
}
MOZ_ASSERT(!mIsComposing, "Why is the editor still composing?");
MOZ_ASSERT(!HasEditor(), "Why does the editor still keep to hold this?");
@ -412,7 +412,7 @@ TextComposition::NotityUpdateComposition(
// When compositon start, notify the rect of first offset character.
// When not compositon start, notify the rect of selected composition
// string if compositionchange event.
if (aCompositionEvent->mMessage == NS_COMPOSITION_START) {
if (aCompositionEvent->mMessage == eCompositionStart) {
nsCOMPtr<nsIWidget> widget = mPresContext->GetRootWidget();
// Update composition start offset
WidgetQueryContentEvent selectedTextEvent(true, eQuerySelectedText, widget);
@ -490,10 +490,10 @@ TextComposition::RequestToCommit(nsIWidget* aWidget, bool aDiscard)
// Otherwise, synthesize the commit in content.
nsAutoString data(aDiscard ? EmptyString() : lastData);
if (data == mLastData) {
DispatchCompositionEventRunnable(NS_COMPOSITION_COMMIT_AS_IS, EmptyString(),
DispatchCompositionEventRunnable(eCompositionCommitAsIs, EmptyString(),
true);
} else {
DispatchCompositionEventRunnable(NS_COMPOSITION_COMMIT, data, true);
DispatchCompositionEventRunnable(eCompositionCommit, data, true);
}
return NS_OK;
}
@ -611,8 +611,8 @@ TextComposition::CompositionEventDispatcher::Run()
nsRefPtr<nsPresContext> presContext = mTextComposition->mPresContext;
nsEventStatus status = nsEventStatus_eIgnore;
switch (mEventMessage) {
case NS_COMPOSITION_START: {
WidgetCompositionEvent compStart(true, NS_COMPOSITION_START, widget);
case eCompositionStart: {
WidgetCompositionEvent compStart(true, eCompositionStart, widget);
WidgetQueryContentEvent selectedText(true, eQuerySelectedText, widget);
ContentEventHandler handler(presContext);
handler.OnQuerySelectedText(&selectedText);
@ -625,11 +625,11 @@ TextComposition::CompositionEventDispatcher::Run()
mIsSynthesizedEvent);
break;
}
case NS_COMPOSITION_CHANGE:
case NS_COMPOSITION_COMMIT_AS_IS:
case NS_COMPOSITION_COMMIT: {
case eCompositionChange:
case eCompositionCommitAsIs:
case eCompositionCommit: {
WidgetCompositionEvent compEvent(true, mEventMessage, widget);
if (mEventMessage != NS_COMPOSITION_COMMIT_AS_IS) {
if (mEventMessage != eCompositionCommitAsIs) {
compEvent.mData = mData;
}
compEvent.mFlags.mIsSynthesizedForTests =

37
dom/fetch/FetchUtil.cpp Normal file
Просмотреть файл

@ -0,0 +1,37 @@
#include "FetchUtil.h"
#include "nsError.h"
#include "nsString.h"
namespace mozilla {
namespace dom {
// static
nsresult
FetchUtil::GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod)
{
nsAutoCString upperCaseMethod(aMethod);
ToUpperCase(upperCaseMethod);
if (upperCaseMethod.EqualsLiteral("CONNECT") ||
upperCaseMethod.EqualsLiteral("TRACE") ||
upperCaseMethod.EqualsLiteral("TRACK") ||
!NS_IsValidHTTPToken(aMethod)) {
outMethod.SetIsVoid(true);
return NS_ERROR_DOM_SECURITY_ERR;
}
if (upperCaseMethod.EqualsLiteral("DELETE") ||
upperCaseMethod.EqualsLiteral("GET") ||
upperCaseMethod.EqualsLiteral("HEAD") ||
upperCaseMethod.EqualsLiteral("OPTIONS") ||
upperCaseMethod.EqualsLiteral("POST") ||
upperCaseMethod.EqualsLiteral("PUT")) {
outMethod = upperCaseMethod;
}
else {
outMethod = aMethod; // Case unchanged for non-standard methods
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

28
dom/fetch/FetchUtil.h Normal file
Просмотреть файл

@ -0,0 +1,28 @@
#ifndef mozilla_dom_FetchUtil_h
#define mozilla_dom_FetchUtil_h
#include "nsString.h"
#include "nsError.h"
namespace mozilla {
namespace dom {
class FetchUtil final
{
private:
FetchUtil() = delete;
public:
/**
* Sets outMethod to a valid HTTP request method string based on an input method.
* Implements checks and normalization as specified by the Fetch specification.
* Returns NS_ERROR_DOM_SECURITY_ERR if the method is invalid.
* Otherwise returns NS_OK and the normalized method via outMethod.
*/
static nsresult
GetValidRequestMethod(const nsACString& aMethod, nsCString& outMethod);
};
} // namespace dom
} // namespace mozilla
#endif

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

@ -12,6 +12,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/Headers.h"
#include "mozilla/dom/Fetch.h"
#include "mozilla/dom/FetchUtil.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/URL.h"
#include "mozilla/dom/WorkerPrivate.h"
@ -298,34 +299,21 @@ Request::Constructor(const GlobalObject& aGlobal,
// Request constructor step 14.
if (aInit.mMethod.WasPassed()) {
nsAutoCString method(aInit.mMethod.Value());
nsAutoCString upperCaseMethod = method;
ToUpperCase(upperCaseMethod);
// Step 14.1. Disallow forbidden methods, and anything that is not a HTTP
// token, since HTTP states that Method may be any of the defined values or
// a token (extension method).
if (upperCaseMethod.EqualsLiteral("CONNECT") ||
upperCaseMethod.EqualsLiteral("TRACE") ||
upperCaseMethod.EqualsLiteral("TRACK") ||
!NS_IsValidHTTPToken(method)) {
nsAutoCString outMethod;
nsresult rv = FetchUtil::GetValidRequestMethod(method, outMethod);
if (NS_FAILED(rv)) {
NS_ConvertUTF8toUTF16 label(method);
aRv.ThrowTypeError(MSG_INVALID_REQUEST_METHOD, &label);
return nullptr;
}
// Step 14.2
if (upperCaseMethod.EqualsLiteral("DELETE") ||
upperCaseMethod.EqualsLiteral("GET") ||
upperCaseMethod.EqualsLiteral("HEAD") ||
upperCaseMethod.EqualsLiteral("POST") ||
upperCaseMethod.EqualsLiteral("PUT") ||
upperCaseMethod.EqualsLiteral("OPTIONS")) {
request->ClearCreatedByFetchEvent();
request->SetMethod(upperCaseMethod);
} else {
request->ClearCreatedByFetchEvent();
request->SetMethod(method);
}
request->ClearCreatedByFetchEvent();
request->SetMethod(outMethod);
}
nsRefPtr<InternalHeaders> requestHeaders = request->Headers();

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

@ -8,6 +8,7 @@ EXPORTS.mozilla.dom += [
'ChannelInfo.h',
'Fetch.h',
'FetchDriver.h',
'FetchUtil.h',
'Headers.h',
'InternalHeaders.h',
'InternalRequest.h',
@ -20,6 +21,7 @@ UNIFIED_SOURCES += [
'ChannelInfo.cpp',
'Fetch.cpp',
'FetchDriver.cpp',
'FetchUtil.cpp',
'Headers.cpp',
'InternalHeaders.cpp',
'InternalRequest.cpp',

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

@ -3034,8 +3034,8 @@ HTMLInputElement::NeedToInitializeEditorForEvent(
case eMouseExitFromWidget:
case eMouseOver:
case eMouseOut:
case NS_SCROLLPORT_UNDERFLOW:
case NS_SCROLLPORT_OVERFLOW:
case eScrollPortUnderflow:
case eScrollPortOverflow:
return false;
default:
return true;

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

@ -17,10 +17,13 @@ interface nsIPrincipal;
* endpoint.
*/
[scriptable, uuid(0bcac389-a3ac-44a4-97fb-b50e41a46146)]
[scriptable, uuid(dc201064-8e5c-4a26-bd37-d1e33558a903)]
interface nsIPushEndpointCallback : nsISupports
{
void onPushEndpoint(in nsresult status, in DOMString endpoint);
void onPushEndpoint(in nsresult status,
in DOMString endpoint,
in uint32_t keyLen,
[array, size_is(keyLen)] in octet key);
};
/**

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

@ -37,6 +37,7 @@
#include "mozilla/layout/RenderFrameChild.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Move.h"
#include "mozilla/PWebBrowserPersistDocumentChild.h"
#include "mozilla/Services.h"
#include "mozilla/StaticPtr.h"
@ -599,37 +600,6 @@ TabChild::Create(nsIContentChild* aManager,
return NS_SUCCEEDED(iframe->Init()) ? iframe.forget() : nullptr;
}
class TabChildSetAllowedTouchBehaviorCallback : public SetAllowedTouchBehaviorCallback {
public:
explicit TabChildSetAllowedTouchBehaviorCallback(TabChild* aTabChild)
: mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
{}
void Run(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) const override {
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild)) {
static_cast<TabChild*>(tabChild.get())->SendSetAllowedTouchBehavior(aInputBlockId, aFlags);
}
}
private:
nsWeakPtr mTabChild;
};
class TabChildContentReceivedInputBlockCallback : public ContentReceivedInputBlockCallback {
public:
explicit TabChildContentReceivedInputBlockCallback(TabChild* aTabChild)
: mTabChild(do_GetWeakReference(static_cast<nsITabChild*>(aTabChild)))
{}
void Run(const ScrollableLayerGuid& aGuid, uint64_t aInputBlockId, bool aPreventDefault) const override {
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(mTabChild)) {
static_cast<TabChild*>(tabChild.get())->SendContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
}
}
private:
nsWeakPtr mTabChild;
};
TabChild::TabChild(nsIContentChild* aManager,
const TabId& aTabId,
const TabContext& aContext,
@ -649,7 +619,6 @@ TabChild::TabChild(nsIContentChild* aManager,
, mOrientation(eScreenOrientation_PortraitPrimary)
, mUpdateHitRegion(false)
, mIgnoreKeyPressEvent(false)
, mSetAllowedTouchBehaviorCallback(new TabChildSetAllowedTouchBehaviorCallback(this))
, mHasValidInnerSize(false)
, mDestroyed(false)
, mUniqueId(aTabId)
@ -665,6 +634,15 @@ TabChild::TabChild(nsIContentChild* aManager,
// check the other conditions necessary for enabling APZ.
mAsyncPanZoomEnabled = gfxPlatform::AsyncPanZoomEnabled();
nsWeakPtr weakPtrThis(do_GetWeakReference(static_cast<nsITabChild*>(this))); // for capture by the lambda
mSetAllowedTouchBehaviorCallback = [weakPtrThis](uint64_t aInputBlockId,
const nsTArray<TouchBehaviorFlags>& aFlags)
{
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
static_cast<TabChild*>(tabChild.get())->SendSetAllowedTouchBehavior(aInputBlockId, aFlags);
}
};
// preloaded TabChild should not be added to child map
if (mUniqueId) {
MOZ_ASSERT(NestedTabChildMap().find(mUniqueId) == NestedTabChildMap().end());
@ -860,8 +838,17 @@ TabChild::Init()
do_QueryInterface(window->GetChromeEventHandler());
docShell->SetChromeEventHandler(chromeHandler);
mAPZEventState = new APZEventState(mPuppetWidget,
new TabChildContentReceivedInputBlockCallback(this));
nsWeakPtr weakPtrThis = do_GetWeakReference(static_cast<nsITabChild*>(this)); // for capture by the lambda
ContentReceivedInputBlockCallback callback(
[weakPtrThis](const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
bool aPreventDefault)
{
if (nsCOMPtr<nsITabChild> tabChild = do_QueryReferent(weakPtrThis)) {
static_cast<TabChild*>(tabChild.get())->SendContentReceivedInputBlock(aGuid, aInputBlockId, aPreventDefault);
}
});
mAPZEventState = new APZEventState(mPuppetWidget, Move(callback));
return NS_OK;
}

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

@ -32,6 +32,7 @@
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventForwards.h"
#include "mozilla/layers/CompositorTypes.h"
#include "mozilla/layers/APZCCallbackHelper.h"
#include "nsIWebBrowserChrome3.h"
#include "mozilla/dom/ipc/IdType.h"
#include "AudioChannelService.h"
@ -48,8 +49,6 @@ class RenderFrameChild;
namespace layers {
class APZEventState;
class ImageCompositeNotification;
struct SetTargetAPZCCallback;
struct SetAllowedTouchBehaviorCallback;
} // namespace layers
namespace widget {
@ -230,7 +229,6 @@ class TabChild final : public TabChildBase,
typedef mozilla::dom::ClonedMessageData ClonedMessageData;
typedef mozilla::layout::RenderFrameChild RenderFrameChild;
typedef mozilla::layers::APZEventState APZEventState;
typedef mozilla::layers::SetTargetAPZCCallback SetTargetAPZCCallback;
typedef mozilla::layers::SetAllowedTouchBehaviorCallback SetAllowedTouchBehaviorCallback;
public:
@ -635,7 +633,7 @@ private:
bool mIgnoreKeyPressEvent;
nsRefPtr<APZEventState> mAPZEventState;
nsRefPtr<SetAllowedTouchBehaviorCallback> mSetAllowedTouchBehaviorCallback;
SetAllowedTouchBehaviorCallback mSetAllowedTouchBehaviorCallback;
bool mHasValidInnerSize;
bool mDestroyed;
// Position of tab, relative to parent widget (typically the window)

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

@ -2369,7 +2369,7 @@ TabParent::HandleQueryContentEvent(WidgetQueryContentEvent& aEvent)
return true;
}
switch (aEvent.mMessage) {
case NS_QUERY_TEXT_RECT:
case eQueryTextRect:
case eQueryCaretRect:
case eQueryEditorRect:
aEvent.mReply.mRect -= GetChildProcessOffset();

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

@ -124,9 +124,12 @@ AudioBlock::ClearDownstreamMark() {
}
}
void
AudioBlock::AssertNoLastingShares() {
MOZ_ASSERT(!mBuffer->AsAudioBlockBuffer()->HasLastingShares());
bool
AudioBlock::CanWrite() {
// If mBufferIsDownstreamRef is set then the buffer is not ours to use.
// It may be in use by another node which is not downstream.
return !mBufferIsDownstreamRef &&
!mBuffer->AsAudioBlockBuffer()->HasLastingShares();
}
void

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

@ -24,9 +24,16 @@ public:
AudioBlock() {
mDuration = WEBAUDIO_BLOCK_SIZE;
}
MOZ_IMPLICIT AudioBlock(const AudioChunk& aChunk) {
mDuration = WEBAUDIO_BLOCK_SIZE;
operator=(aChunk);
// No effort is made in constructors to ensure that mBufferIsDownstreamRef
// is set because the block is expected to be a temporary and so the
// reference will be released before the next iteration.
// The custom copy constructor is required so as not to set
// mBufferIsDownstreamRef without notifying AudioBlockBuffer.
AudioBlock(const AudioBlock& aBlock) : AudioChunk(aBlock.AsAudioChunk()) {}
explicit AudioBlock(const AudioChunk& aChunk)
: AudioChunk(aChunk)
{
MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE);
}
~AudioBlock();
@ -44,7 +51,7 @@ public:
const AudioChunk& AsAudioChunk() const { return *this; }
AudioChunk* AsMutableChunk() {
void ClearDownstreamMark();
ClearDownstreamMark();
return this;
}
@ -54,12 +61,14 @@ public:
*/
void AllocateChannels(uint32_t aChannelCount);
/**
* ChannelFloatsForWrite() should only be used when the buffers have been
* created with AllocateChannels().
*/
float* ChannelFloatsForWrite(size_t aChannel)
{
MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32);
#if DEBUG
AssertNoLastingShares();
#endif
MOZ_ASSERT(CanWrite());
return static_cast<float*>(const_cast<void*>(mChannelData[aChannel]));
}
@ -72,6 +81,12 @@ public:
mBufferFormat = AUDIO_FORMAT_SILENCE;
}
AudioBlock& operator=(const AudioBlock& aBlock) {
// Instead of just copying, mBufferIsDownstreamRef must be first cleared
// if set. It is set again for the new mBuffer if possible. This happens
// in SetBuffer().
return *this = aBlock.AsAudioChunk();
}
AudioBlock& operator=(const AudioChunk& aChunk) {
MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE);
SetBuffer(aChunk.mBuffer);
@ -103,7 +118,7 @@ public:
private:
void ClearDownstreamMark();
void AssertNoLastingShares();
bool CanWrite();
// mBufferIsDownstreamRef is set only when mBuffer references an
// AudioBlockBuffer created in a different AudioBlock. That can happen when

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

@ -53,6 +53,16 @@ AudioNodeStream::~AudioNodeStream()
MOZ_COUNT_DTOR(AudioNodeStream);
}
void
AudioNodeStream::DestroyImpl()
{
// These are graph thread objects, so clean up on graph thread.
mInputChunks.Clear();
mLastChunks.Clear();
ProcessedMediaStream::DestroyImpl();
}
/* static */ already_AddRefed<AudioNodeStream>
AudioNodeStream::Create(MediaStreamGraph* aGraph, AudioNodeEngine* aEngine,
Flags aFlags)

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

@ -169,6 +169,8 @@ public:
protected:
virtual void DestroyImpl() override;
void AdvanceOutputSegment();
void FinishOutput();
void AccumulateInputChunk(uint32_t aInputIndex, const AudioBlock& aChunk,

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

@ -1368,7 +1368,7 @@ Promise::Settle(JS::Handle<JS::Value> aValue, PromiseState aState)
}
#endif
if (mGlobal->IsDying()) {
if (!mGlobal || mGlobal->IsDying()) {
return;
}

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

@ -121,10 +121,22 @@ Push.prototype = {
() => {
fn(that._scope, that._principal, {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPushEndpointCallback]),
onPushEndpoint: function(ok, endpoint) {
onPushEndpoint: function(ok, endpoint, keyLen, key) {
if (ok === Cr.NS_OK) {
if (endpoint) {
let sub = new that._window.PushSubscription(endpoint, that._scope);
let sub;
if (keyLen) {
let publicKey = new ArrayBuffer(keyLen);
let keyView = new Uint8Array(publicKey);
keyView.set(key);
sub = new that._window.PushSubscription(endpoint,
that._scope,
publicKey);
} else {
sub = new that._window.PushSubscription(endpoint,
that._scope,
null);
}
sub.setPrincipal(that._principal);
resolve(sub);
} else {

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

@ -100,6 +100,19 @@ PushClient.prototype = {
}, null, principal);
},
_deliverPushEndpoint: function(request, registration) {
if (registration.p256dhKey) {
let key = new Uint8Array(registration.p256dhKey);
request.onPushEndpoint(Cr.NS_OK,
registration.pushEndpoint,
key.length,
key);
return;
}
request.onPushEndpoint(Cr.NS_OK, registration.pushEndpoint, 0, null);
},
receiveMessage: function(aMessage) {
let json = aMessage.data;
@ -112,23 +125,23 @@ PushClient.prototype = {
debug("receiveMessage(): " + JSON.stringify(aMessage))
switch (aMessage.name) {
case "PushService:Register:OK":
{
request.onPushEndpoint(Cr.NS_OK, json.pushEndpoint);
this._deliverPushEndpoint(request, json);
break;
}
case "PushService:Register:KO":
request.onPushEndpoint(Cr.NS_ERROR_FAILURE, "");
request.onPushEndpoint(Cr.NS_ERROR_FAILURE, "", 0, null);
break;
case "PushService:Registration:OK":
{
let endpoint = "";
if (json.registration)
endpoint = json.registration.pushEndpoint;
request.onPushEndpoint(Cr.NS_OK, endpoint);
if (!json.registration) {
request.onPushEndpoint(Cr.NS_OK, "", 0, null);
} else {
this._deliverPushEndpoint(request, json.registration);
}
break;
}
case "PushService:Registration:KO":
request.onPushEndpoint(Cr.NS_ERROR_FAILURE, "");
request.onPushEndpoint(Cr.NS_ERROR_FAILURE, "", 0, null);
break;
case "PushService:Unregister:OK":
if (typeof json.result !== "boolean") {

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

@ -90,13 +90,18 @@ PushSubscription::Unsubscribe(ErrorResult& aRv)
PushSubscription::PushSubscription(nsIGlobalObject* aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope)
: mGlobal(aGlobal), mEndpoint(aEndpoint), mScope(aScope)
const nsAString& aScope,
const nsTArray<uint8_t>& aRawP256dhKey)
: mGlobal(aGlobal)
, mEndpoint(aEndpoint)
, mScope(aScope)
, mRawP256dhKey(aRawP256dhKey)
{
}
PushSubscription::~PushSubscription()
{}
{
}
JSObject*
PushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
@ -104,6 +109,20 @@ PushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return PushSubscriptionBinding::Wrap(aCx, this, aGivenProto);
}
void
PushSubscription::GetKey(JSContext* aCx,
PushEncryptionKeyName aType,
JS::MutableHandle<JSObject*> aP256dhKey)
{
if (aType == PushEncryptionKeyName::P256dh && !mRawP256dhKey.IsEmpty()) {
aP256dhKey.set(ArrayBuffer::Create(aCx,
mRawP256dhKey.Length(),
mRawP256dhKey.Elements()));
} else {
aP256dhKey.set(nullptr);
}
}
void
PushSubscription::SetPrincipal(nsIPrincipal* aPrincipal)
{
@ -113,16 +132,34 @@ PushSubscription::SetPrincipal(nsIPrincipal* aPrincipal)
// static
already_AddRefed<PushSubscription>
PushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv)
PushSubscription::Constructor(GlobalObject& aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope,
const Nullable<ArrayBuffer>& aP256dhKey,
ErrorResult& aRv)
{
MOZ_ASSERT(!aEndpoint.IsEmpty());
MOZ_ASSERT(!aScope.IsEmpty());
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
nsRefPtr<PushSubscription> sub = new PushSubscription(global, aEndpoint, aScope);
nsTArray<uint8_t> rawKey;
if (!aP256dhKey.IsNull()) {
const ArrayBuffer& key = aP256dhKey.Value();
key.ComputeLengthAndData();
rawKey.SetLength(key.Length());
rawKey.ReplaceElementsAt(0, key.Length(), key.Data(), key.Length());
}
nsRefPtr<PushSubscription> sub = new PushSubscription(global,
aEndpoint,
aScope,
rawKey);
return sub.forget();
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PushSubscription, mGlobal, mPrincipal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PushSubscription)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PushSubscription)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PushSubscription)
@ -188,8 +225,9 @@ NS_INTERFACE_MAP_END
// WorkerPushSubscription
WorkerPushSubscription::WorkerPushSubscription(const nsAString& aEndpoint,
const nsAString& aScope)
: mEndpoint(aEndpoint), mScope(aScope)
const nsAString& aScope,
const nsTArray<uint8_t>& aRawP256dhKey)
: mEndpoint(aEndpoint), mScope(aScope), mRawP256dhKey(aRawP256dhKey)
{
MOZ_ASSERT(!aScope.IsEmpty());
MOZ_ASSERT(!aEndpoint.IsEmpty());
@ -206,16 +244,45 @@ WorkerPushSubscription::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenP
// static
already_AddRefed<WorkerPushSubscription>
WorkerPushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv)
WorkerPushSubscription::Constructor(GlobalObject& aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope,
const Nullable<ArrayBuffer>& aP256dhKey,
ErrorResult& aRv)
{
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(worker);
worker->AssertIsOnWorkerThread();
nsRefPtr<WorkerPushSubscription> sub = new WorkerPushSubscription(aEndpoint, aScope);
nsTArray<uint8_t> rawKey;
if (!aP256dhKey.IsNull()) {
const ArrayBuffer& key = aP256dhKey.Value();
key.ComputeLengthAndData();
rawKey.SetLength(key.Length());
rawKey.ReplaceElementsAt(0, key.Length(), key.Data(), key.Length());
}
nsRefPtr<WorkerPushSubscription> sub = new WorkerPushSubscription(aEndpoint,
aScope,
rawKey);
return sub.forget();
}
void
WorkerPushSubscription::GetKey(JSContext* aCx,
PushEncryptionKeyName aType,
JS::MutableHandle<JSObject*> aP256dhKey)
{
if (aType == mozilla::dom::PushEncryptionKeyName::P256dh &&
!mRawP256dhKey.IsEmpty()) {
aP256dhKey.set(ArrayBuffer::Create(aCx,
mRawP256dhKey.Length(),
mRawP256dhKey.Elements()));
} else {
aP256dhKey.set(nullptr);
}
}
class UnsubscribeResultRunnable final : public WorkerRunnable
{
public:
@ -371,6 +438,7 @@ WorkerPushSubscription::Unsubscribe(ErrorResult &aRv)
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerPushSubscription)
NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerPushSubscription)
NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerPushSubscription)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerPushSubscription)
@ -397,12 +465,14 @@ public:
GetSubscriptionResultRunnable(PromiseWorkerProxy* aProxy,
nsresult aStatus,
const nsAString& aEndpoint,
const nsAString& aScope)
const nsAString& aScope,
const nsTArray<uint8_t>& aRawP256dhKey)
: WorkerRunnable(aProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
, mProxy(aProxy)
, mStatus(aStatus)
, mEndpoint(aEndpoint)
, mScope(aScope)
, mRawP256dhKey(aRawP256dhKey)
{ }
bool
@ -414,7 +484,7 @@ public:
promise->MaybeResolve(JS::NullHandleValue);
} else {
nsRefPtr<WorkerPushSubscription> sub =
new WorkerPushSubscription(mEndpoint, mScope);
new WorkerPushSubscription(mEndpoint, mScope, mRawP256dhKey);
promise->MaybeResolve(sub);
}
} else {
@ -432,6 +502,7 @@ private:
nsresult mStatus;
nsString mEndpoint;
nsString mScope;
nsTArray<uint8_t> mRawP256dhKey;
};
class GetSubscriptionCallback final : public nsIPushEndpointCallback
@ -446,7 +517,10 @@ public:
{}
NS_IMETHOD
OnPushEndpoint(nsresult aStatus, const nsAString& aEndpoint) override
OnPushEndpoint(nsresult aStatus,
const nsAString& aEndpoint,
uint32_t aKeyLen,
uint8_t* aKey) override
{
AssertIsOnMainThread();
MOZ_ASSERT(mProxy, "OnPushEndpoint() called twice?");
@ -461,8 +535,15 @@ public:
AutoJSAPI jsapi;
jsapi.Init();
nsTArray<uint8_t> rawP256dhKey(aKeyLen);
rawP256dhKey.ReplaceElementsAt(0, aKeyLen, aKey, aKeyLen);
nsRefPtr<GetSubscriptionResultRunnable> r =
new GetSubscriptionResultRunnable(proxy, aStatus, aEndpoint, mScope);
new GetSubscriptionResultRunnable(proxy,
aStatus,
aEndpoint,
mScope,
rawP256dhKey);
r->Dispatch(jsapi.cx());
return NS_OK;
}
@ -502,7 +583,7 @@ public:
nsCOMPtr<nsIPermissionManager> permManager =
mozilla::services::GetPermissionManager();
if (!permManager) {
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString());
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr);
return NS_OK;
}
@ -515,14 +596,14 @@ public:
&permission);
if (NS_WARN_IF(NS_FAILED(rv)) || permission != nsIPermissionManager::ALLOW_ACTION) {
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString());
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr);
return NS_OK;
}
nsCOMPtr<nsIPushClient> client =
do_CreateInstance("@mozilla.org/push/PushClient;1");
if (!client) {
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString());
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr);
return NS_OK;
}
@ -534,7 +615,7 @@ public:
}
if (NS_WARN_IF(NS_FAILED(rv))) {
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString());
callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr);
return rv;
}

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

@ -36,6 +36,7 @@
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/TypedArray.h"
#include "nsCOMPtr.h"
#include "mozilla/nsRefPtr.h"
@ -44,6 +45,8 @@
class nsIGlobalObject;
class nsIPrincipal;
#include "mozilla/dom/PushSubscriptionBinding.h"
namespace mozilla {
namespace dom {
@ -63,7 +66,8 @@ public:
explicit PushSubscription(nsIGlobalObject* aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope);
const nsAString& aScope,
const nsTArray<uint8_t>& aP256dhKey);
JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@ -80,8 +84,17 @@ public:
aEndpoint = mEndpoint;
}
void
GetKey(JSContext* cx,
PushEncryptionKeyName aType,
JS::MutableHandle<JSObject*> aP256dhKey);
static already_AddRefed<PushSubscription>
Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv);
Constructor(GlobalObject& aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope,
const Nullable<ArrayBuffer>& aP256dhKey,
ErrorResult& aRv);
void
SetPrincipal(nsIPrincipal* aPrincipal);
@ -97,6 +110,7 @@ private:
nsCOMPtr<nsIPrincipal> mPrincipal;
nsString mEndpoint;
nsString mScope;
nsTArray<uint8_t> mRawP256dhKey;
};
class PushManager final : public nsISupports
@ -146,7 +160,8 @@ public:
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(WorkerPushSubscription)
explicit WorkerPushSubscription(const nsAString& aEndpoint,
const nsAString& aScope);
const nsAString& aScope,
const nsTArray<uint8_t>& aRawP256dhKey);
nsIGlobalObject*
GetParentObject() const
@ -158,7 +173,11 @@ public:
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
static already_AddRefed<WorkerPushSubscription>
Constructor(GlobalObject& aGlobal, const nsAString& aEndpoint, const nsAString& aScope, ErrorResult& aRv);
Constructor(GlobalObject& aGlobal,
const nsAString& aEndpoint,
const nsAString& aScope,
const Nullable<ArrayBuffer>& aP256dhKey,
ErrorResult& aRv);
void
GetEndpoint(nsAString& aEndpoint) const
@ -166,6 +185,10 @@ public:
aEndpoint = mEndpoint;
}
void
GetKey(JSContext* cx, PushEncryptionKeyName aType,
JS::MutableHandle<JSObject*> aP256dhKey);
already_AddRefed<Promise>
Unsubscribe(ErrorResult& aRv);
@ -175,6 +198,7 @@ protected:
private:
nsString mEndpoint;
nsString mScope;
nsTArray<uint8_t> mRawP256dhKey;
};
class WorkerPushManager final : public nsISupports

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

@ -719,6 +719,11 @@ this.PushService = {
.then(record => this._notifySubscriptionChangeObservers(record));
},
updateRecordAndNotifyApp: function(aKeyID, aUpdateFunc) {
return this._db.update(aKeyID, aUpdateFunc)
.then(record => this._notifySubscriptionChangeObservers(record));
},
/**
* Dispatches an incoming message to a service worker, recalculating the
* quota for the associated push registration. If the quota is exceeded,
@ -737,7 +742,7 @@ this.PushService = {
debug("receivedPushMessage()");
let shouldNotify = false;
this.getByKeyID(keyID).then(record => {
return this.getByKeyID(keyID).then(record => {
if (!record) {
throw new Error("No record for key ID " + keyID);
}
@ -761,11 +766,13 @@ this.PushService = {
return newRecord;
});
}).then(record => {
var notified = false;
if (!record) {
return null;
return notified;
}
if (shouldNotify) {
this._notifyApp(record, message);
notified = this._notifyApp(record, message);
}
if (record.isExpired()) {
// Drop the registration in the background. If the user returns to the
@ -775,6 +782,7 @@ this.PushService = {
debug("receivedPushMessage: Unregister error: " + error);
});
}
return notified;
}).catch(error => {
debug("receivedPushMessage: Error notifying app: " + error);
});
@ -785,7 +793,7 @@ this.PushService = {
aPushRecord.originAttributes === undefined) {
debug("notifyApp() something is undefined. Dropping notification: " +
JSON.stringify(aPushRecord) );
return;
return false;
}
debug("notifyApp() " + aPushRecord.scope);
@ -807,7 +815,7 @@ this.PushService = {
// If permission has been revoked, trash the message.
if (!aPushRecord.hasPermission()) {
debug("Does not have permission for push.");
return;
return false;
}
// TODO data.
@ -818,6 +826,7 @@ this.PushService = {
};
this._notifyListeners('push', data);
return true;
},
getByKeyID: function(aKeyID) {

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

@ -19,6 +19,9 @@ Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
const {PushServiceHttp2Crypto, concatArray} =
Cu.import("resource://gre/modules/PushServiceHttp2Crypto.jsm");
this.EXPORTED_SYMBOLS = ["PushServiceHttp2"];
const prefs = new Preferences("dom.push.");
@ -34,7 +37,7 @@ function debug(s) {
}
const kPUSHHTTP2DB_DB_NAME = "pushHttp2";
const kPUSHHTTP2DB_DB_VERSION = 4; // Change this if the IndexedDB format changes
const kPUSHHTTP2DB_DB_VERSION = 5; // Change this if the IndexedDB format changes
const kPUSHHTTP2DB_STORE_NAME = "pushHttp2";
/**
@ -114,13 +117,12 @@ PushSubscriptionListener.prototype = {
var PushChannelListener = function(pushSubscriptionListener) {
debug("Creating a new push channel listener.");
this._mainListener = pushSubscriptionListener;
this._message = [];
this._ackUri = null;
};
PushChannelListener.prototype = {
_message: null,
_ackUri: null,
onStartRequest: function(aRequest, aContext) {
this._ackUri = aRequest.URI.spec;
},
@ -132,15 +134,13 @@ PushChannelListener.prototype = {
return;
}
let inputStream = Cc["@mozilla.org/scriptableinputstream;1"]
.createInstance(Ci.nsIScriptableInputStream);
let inputStream = Cc["@mozilla.org/binaryinputstream;1"]
.createInstance(Ci.nsIBinaryInputStream);
inputStream.init(aStream);
if (!this._message) {
this._message = inputStream.read(aCount);
} else {
this._message.concat(inputStream.read(aCount));
}
inputStream.setInputStream(aStream);
let chunk = new ArrayBuffer(aCount);
inputStream.readArrayBuffer(aCount, chunk);
this._message.push(chunk);
},
onStopRequest: function(aRequest, aContext, aStatusCode) {
@ -148,13 +148,76 @@ PushChannelListener.prototype = {
if (Components.isSuccessCode(aStatusCode) &&
this._mainListener &&
this._mainListener._pushService) {
var keymap = encryptKeyFieldParser(aRequest);
if (!keymap) {
return;
}
var enc = encryptFieldParser(aRequest);
if (!enc || !enc.keyid) {
return;
}
var dh = keymap[enc.keyid];
var salt = enc.salt;
var rs = (enc.rs)? parseInt(enc.rs, 10) : 4096;
if (!dh || !salt || isNaN(rs) || (rs <= 1)) {
return;
}
var msg = concatArray(this._message);
this._mainListener._pushService._pushChannelOnStop(this._mainListener.uri,
this._ackUri,
this._message);
msg,
dh,
salt,
rs);
}
}
};
var parseHeaderFieldParams = (m, v) => {
var i = v.indexOf('=');
if (i >= 0) {
// A quoted string with internal quotes is invalid for all the possible
// values of this header field.
m[v.substring(0, i).trim()] = v.substring(i + 1).trim()
.replace(/^"(.*)"$/, '$1');
}
return m;
};
function encryptKeyFieldParser(aRequest) {
try {
var encryptKeyField = aRequest.getRequestHeader("Encryption-Key");
var params = encryptKeyField.split(',');
return params.reduce((m, p) => {
var pmap = p.split(';').reduce(parseHeaderFieldParams, {});
if (pmap.keyid && pmap.dh) {
m[pmap.keyid] = pmap.dh;
}
return m;
}, {});
} catch(e) {
// getRequestHeader can throw.
return null;
}
}
function encryptFieldParser(aRequest) {
try {
return aRequest.getRequestHeader("Encryption")
.split(',', 1)[0]
.split(';')
.reduce(parseHeaderFieldParams, {});
} catch(e) {
// getRequestHeader can throw.
return null;
}
}
var PushServiceDelete = function(resolve, reject) {
this._resolve = resolve;
this._reject = reject;
@ -188,9 +251,12 @@ PushServiceDelete.prototype = {
}
};
var SubscriptionListener = function(aSubInfo, aServerURI, aPushServiceHttp2) {
var SubscriptionListener = function(aSubInfo, aResolve, aReject,
aServerURI, aPushServiceHttp2) {
debug("Creating a new subscription listener.");
this._subInfo = aSubInfo;
this._resolve = aResolve;
this._reject = aReject;
this._data = '';
this._serverURI = aServerURI;
this._service = aPushServiceHttp2;
@ -221,12 +287,12 @@ SubscriptionListener.prototype = {
// Check if pushService is still active.
if (!this._service.hasmainPushService()) {
this._subInfo.reject({error: "Service deactivated"});
this._reject({error: "Service deactivated"});
return;
}
if (!Components.isSuccessCode(aStatus)) {
this._subInfo.reject({error: "Error status" + aStatus});
this._reject({error: "Error status" + aStatus});
return;
}
@ -236,15 +302,18 @@ SubscriptionListener.prototype = {
if (this._subInfo.retries < prefs.get("http2.maxRetries")) {
this._subInfo.retries++;
var retryAfter = retryAfterParser(aRequest);
setTimeout(this._service.retrySubscription.bind(this._service,
this._subInfo),
retryAfter);
setTimeout(_ => this._reject(
{
retry: true,
subInfo: this._subInfo
}),
retryAfter);
} else {
this._subInfo.reject({error: "Error response code: " + statusCode });
this._reject({error: "Error response code: " + statusCode });
}
return;
} else if (statusCode != 201) {
this._subInfo.reject({error: "Error response code: " + statusCode });
this._reject({error: "Error response code: " + statusCode });
return;
}
@ -252,7 +321,7 @@ SubscriptionListener.prototype = {
try {
subscriptionUri = aRequest.getResponseHeader("location");
} catch (err) {
this._subInfo.reject({error: "Return code 201, but the answer is bogus"});
this._reject({error: "Return code 201, but the answer is bogus"});
return;
}
@ -262,27 +331,27 @@ SubscriptionListener.prototype = {
try {
linkList = aRequest.getResponseHeader("link");
} catch (err) {
this._subInfo.reject({error: "Return code 201, but the answer is bogus"});
this._reject({error: "Return code 201, but the answer is bogus"});
return;
}
var linkParserResult = linkParser(linkList, this._serverURI);
if (linkParserResult.error) {
this._subInfo.reject(linkParserResult);
this._reject(linkParserResult);
return;
}
if (!subscriptionUri) {
this._subInfo.reject({error: "Return code 201, but the answer is bogus," +
" missing subscriptionUri"});
this._reject({error: "Return code 201, but the answer is bogus," +
" missing subscriptionUri"});
return;
}
try {
let uriTry = Services.io.newURI(subscriptionUri, null, null);
} catch (e) {
debug("Invalid URI " + subscriptionUri);
this._subInfo.reject({error: "Return code 201, but URI is bogus. " +
subscriptionUri});
this._reject({error: "Return code 201, but URI is bogus. " +
subscriptionUri});
return;
}
@ -295,7 +364,7 @@ SubscriptionListener.prototype = {
quota: this._subInfo.record.maxQuota,
});
this._subInfo.resolve(reply);
this._resolve(reply);
},
};
@ -456,41 +525,53 @@ this.PushServiceHttp2 = {
_subscribeResource: function(aRecord) {
debug("subscribeResource()");
return new Promise((resolve, reject) => {
this._subscribeResourceInternal({record: aRecord,
resolve,
reject,
retries: 0});
return this._subscribeResourceInternal({
record: aRecord,
retries: 0
})
.then(result => {
this._conns[result.subscriptionUri] = {channel: null,
listener: null,
countUnableToConnect: 0,
lastStartListening: 0,
waitingForAlarm: false};
this._listenForMsgs(result.subscriptionUri);
return result;
});
.then(result =>
PushServiceHttp2Crypto.generateKeys()
.then(exportedKeys => {
result.p256dhPublicKey = exportedKeys[0];
result.p256dhPrivateKey = exportedKeys[1];
this._conns[result.subscriptionUri] = {
channel: null,
listener: null,
countUnableToConnect: 0,
lastStartListening: 0,
waitingForAlarm: false
};
this._listenForMsgs(result.subscriptionUri);
return result;
})
);
},
_subscribeResourceInternal: function(aSubInfo) {
debug("subscribeResource()");
debug("subscribeResourceInternal()");
var listener = new SubscriptionListener(aSubInfo,
this._serverURI,
this);
return new Promise((resolve, reject) => {
var listener = new SubscriptionListener(aSubInfo,
resolve,
reject,
this._serverURI,
this);
var chan = this._makeChannel(this._serverURI.spec);
chan.requestMethod = "POST";
try{
chan.asyncOpen(listener, null);
} catch(e) {
aSubInfo.reject({status: 0, error: "NetworkError"});
}
},
retrySubscription: function(aSubInfo) {
this._subscribeResourceInternal(aSubInfo);
var chan = this._makeChannel(this._serverURI.spec);
chan.requestMethod = "POST";
try {
chan.asyncOpen(listener, null);
} catch(e) {
reject({status: 0, error: "NetworkError"});
}
})
.catch(err => {
if ("retry" in err) {
return this._subscribeResourceInternal(err.subInfo);
} else {
throw err;
}
})
},
_deleteResource: function(aUri) {
@ -640,19 +721,51 @@ this.PushServiceHttp2 = {
for (let i = 0; i < aSubscriptions.length; i++) {
let record = aSubscriptions[i];
if (typeof this._conns[record.subscriptionUri] != "object") {
this._conns[record.subscriptionUri] = {channel: null,
listener: null,
countUnableToConnect: 0,
waitingForAlarm: false};
}
if (!this._conns[record.subscriptionUri].conn) {
this._conns[record.subscriptionUri].waitingForAlarm = false;
this._listenForMsgs(record.subscriptionUri);
if (record.p256dhPublicKey && record.p256dhPrivateKey) {
this._startSingleConnection(record);
} else {
// We do not have a encryption key. so we need to generate it. This
// is only going to happen on db upgrade from version 4 to higher.
PushServiceHttp2Crypto.generateKeys()
.then(exportedKeys => {
if (this._mainPushService) {
return this._mainPushService
.updateRecordAndNotifyApp(record.subscriptionUri, record => {
record.p256dhPublicKey = exportedKeys[0];
record.p256dhPrivateKey = exportedKeys[1];
return record;
});
}
}, error => {
record = null;
if (this._mainPushService) {
this._mainPushService
.dropRegistrationAndNotifyApp(record.subscriptionUri);
}
})
.then(_ => {
if (record) {
this._startSingleConnection(record);
}
});
}
}
},
_startSingleConnection: function(record) {
debug("_startSingleConnection()");
if (typeof this._conns[record.subscriptionUri] != "object") {
this._conns[record.subscriptionUri] = {channel: null,
listener: null,
countUnableToConnect: 0,
waitingForAlarm: false};
}
if (!this._conns[record.subscriptionUri].conn) {
this._conns[record.subscriptionUri].waitingForAlarm = false;
this._listenForMsgs(record.subscriptionUri);
}
},
// Start listening if subscriptions present.
_startConnectionsWaitingForAlarm: function() {
debug("startConnectionsWaitingForAlarm()");
@ -756,19 +869,33 @@ this.PushServiceHttp2 = {
}
},
_pushChannelOnStop: function(aUri, aAckUri, aMessage) {
_pushChannelOnStop: function(aUri, aAckUri, aMessage, dh, salt, rs) {
debug("pushChannelOnStop() ");
this._mainPushService.receivedPushMessage(aUri, aMessage, record => {
// Always update the stored record.
return record;
this._mainPushService.getByKeyID(aUri)
.then(aPushRecord =>
PushServiceHttp2Crypto.decodeMsg(aMessage, aPushRecord.p256dhPrivateKey,
dh, salt, rs)
.then(msg => {
var msgString = '';
for (var i=0; i<msg.length; i++) {
msgString += String.fromCharCode(msg[i]);
}
return this._mainPushService.receivedPushMessage(aUri,
msgString,
record => {
// Always update the stored record.
return record;
});
})
)
.then(_ => this._ackMsgRecv(aAckUri))
.catch(err => {
debug("Error receiving message: " + err);
});
this._ackMsgRecv(aAckUri);
},
onAlarmFired: function() {
// Conditions are arranged in decreasing specificity.
// i.e. when _waitingForPong is true, other conditions are also true.
this._startConnectionsWaitingForAlarm();
},
};
@ -777,6 +904,8 @@ function PushRecordHttp2(record) {
PushRecord.call(this, record);
this.subscriptionUri = record.subscriptionUri;
this.pushReceiptEndpoint = record.pushReceiptEndpoint;
this.p256dhPublicKey = record.p256dhPublicKey;
this.p256dhPrivateKey = record.p256dhPrivateKey;
}
PushRecordHttp2.prototype = Object.create(PushRecord.prototype, {
@ -790,11 +919,13 @@ PushRecordHttp2.prototype = Object.create(PushRecord.prototype, {
PushRecordHttp2.prototype.toRegistration = function() {
let registration = PushRecord.prototype.toRegistration.call(this);
registration.pushReceiptEndpoint = this.pushReceiptEndpoint;
registration.p256dhKey = this.p256dhPublicKey;
return registration;
};
PushRecordHttp2.prototype.toRegister = function() {
let register = PushRecord.prototype.toRegister.call(this);
register.pushReceiptEndpoint = this.pushReceiptEndpoint;
register.p256dhKey = this.p256dhPublicKey;
return register;
};

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

@ -0,0 +1,189 @@
/* jshint moz: true, esnext: true */
/* 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/. */
'use strict';
const Cu = Components.utils;
Cu.importGlobalProperties(['crypto']);
this.EXPORTED_SYMBOLS = ['PushServiceHttp2Crypto', 'concatArray'];
var ENCRYPT_INFO = new TextEncoder('utf-8').encode('Content-Encoding: aesgcm128');
var NONCE_INFO = new TextEncoder('utf-8').encode('Content-Encoding: nonce');
function chunkArray(array, size) {
var start = array.byteOffset || 0;
array = array.buffer || array;
var index = 0;
var result = [];
while(index + size <= array.byteLength) {
result.push(new Uint8Array(array, start + index, size));
index += size;
}
if (index < array.byteLength) {
result.push(new Uint8Array(array, start + index));
}
return result;
}
function base64UrlDecode(s) {
s = s.replace(/-/g, '+').replace(/_/g, '/');
// Replace padding if it was stripped by the sender.
// See http://tools.ietf.org/html/rfc4648#section-4
switch (s.length % 4) {
case 0:
break; // No pad chars in this case
case 2:
s += '==';
break; // Two pad chars
case 3:
s += '=';
break; // One pad char
default:
throw new Error('Illegal base64url string!');
}
// With correct padding restored, apply the standard base64 decoder
var decoded = atob(s);
var array = new Uint8Array(new ArrayBuffer(decoded.length));
for (var i = 0; i < decoded.length; i++) {
array[i] = decoded.charCodeAt(i);
}
return array;
}
this.concatArray = function(arrays) {
var size = arrays.reduce((total, a) => total + a.byteLength, 0);
var index = 0;
return arrays.reduce((result, a) => {
result.set(new Uint8Array(a), index);
index += a.byteLength;
return result;
}, new Uint8Array(size));
};
var HMAC_SHA256 = { name: 'HMAC', hash: 'SHA-256' };
function hmac(key) {
this.keyPromise = crypto.subtle.importKey('raw', key, HMAC_SHA256,
false, ['sign']);
}
hmac.prototype.hash = function(input) {
return this.keyPromise.then(k => crypto.subtle.sign('HMAC', k, input));
};
function hkdf(salt, ikm) {
this.prkhPromise = new hmac(salt).hash(ikm)
.then(prk => new hmac(prk));
}
hkdf.prototype.generate = function(info, len) {
var input = concatArray([info, new Uint8Array([1])]);
return this.prkhPromise
.then(prkh => prkh.hash(input))
.then(h => {
if (h.byteLength < len) {
throw new Error('Length is too long');
}
return h.slice(0, len);
});
};
/* generate a 96-bit IV for use in GCM, 48-bits of which are populated */
function generateNonce(base, index) {
if (index >= Math.pow(2, 48)) {
throw new Error('Error generating IV - index is too large.');
}
var nonce = base.slice(0, 12);
nonce = new Uint8Array(nonce);
for (var i = 0; i < 6; ++i) {
nonce[nonce.byteLength - 1 - i] ^= (index / Math.pow(256, i)) & 0xff;
}
return nonce;
}
this.PushServiceHttp2Crypto = {
generateKeys: function() {
return crypto.subtle.generateKey({ name: 'ECDH', namedCurve: 'P-256'},
true,
['deriveBits'])
.then(cryptoKey =>
Promise.all([
crypto.subtle.exportKey('raw', cryptoKey.publicKey),
// TODO: change this when bug 1048931 lands.
crypto.subtle.exportKey('jwk', cryptoKey.privateKey)
]));
},
decodeMsg: function(aData, aPrivateKey, aRemotePublicKey, aSalt, aRs) {
if (aData.byteLength === 0) {
// Zero length messages will be passed as null.
return Promise.resolve(null);
}
// The last chunk of data must be less than aRs, if it is not return an
// error.
if (aData.byteLength % (aRs + 16) === 0) {
return Promise.reject(new Error('Data truncated'));
}
return Promise.all([
crypto.subtle.importKey('raw', base64UrlDecode(aRemotePublicKey),
{ name: 'ECDH', namedCurve: 'P-256' },
false,
['deriveBits']),
crypto.subtle.importKey('jwk', aPrivateKey,
{ name: 'ECDH', namedCurve: 'P-256' },
false,
['deriveBits'])
])
.then(keys =>
crypto.subtle.deriveBits({ name: 'ECDH', public: keys[0] }, keys[1], 256))
.then(rawKey => {
var kdf = new hkdf(base64UrlDecode(aSalt), new Uint8Array(rawKey));
return Promise.all([
kdf.generate(ENCRYPT_INFO, 16)
.then(gcmBits =>
crypto.subtle.importKey('raw', gcmBits, 'AES-GCM', false,
['decrypt'])),
kdf.generate(NONCE_INFO, 12)
])
})
.then(r =>
// AEAD_AES_128_GCM expands ciphertext to be 16 octets longer.
Promise.all(chunkArray(aData, aRs + 16).map((slice, index) =>
this._decodeChunk(slice, index, r[1], r[0]))))
.then(r => concatArray(r));
},
_decodeChunk: function(aSlice, aIndex, aNonce, aKey) {
return crypto.subtle.decrypt({name: 'AES-GCM',
iv: generateNonce(aNonce, aIndex)
},
aKey, aSlice)
.then(decoded => {
decoded = new Uint8Array(decoded);
if (decoded.length == 0) {
return Promise.reject(new Error('Decoded array is too short!'));
} else if (decoded[0] > decoded.length) {
return Promise.reject(new Error ('Padding is wrong!'));
} else {
// All padded bytes must be zero except the first one.
for (var i = 1; i <= decoded[0]; i++) {
if (decoded[i] != 0) {
return Promise.reject(new Error('Padding is wrong!'));
}
}
return decoded.slice(decoded[0] + 1);
}
});
}
};

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

@ -20,6 +20,7 @@ EXTRA_JS_MODULES += [
'PushService.jsm',
'PushServiceChildPreload.jsm',
'PushServiceHttp2.jsm',
'PushServiceHttp2Crypto.jsm',
]
MOCHITEST_MANIFESTS += [

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

@ -46,6 +46,13 @@ function run_test() {
add_task(function* test_pushNotifications() {
// /pushNotifications/subscription1 will send a message with no rs and padding
// length 1.
// /pushNotifications/subscription2 will send a message with no rs and padding
// length 16.
// /pushNotifications/subscription3 will send a message with rs equal 24 and
// padding length 16.
let db = PushServiceHttp2.newPushDB();
do_register_cleanup(() => {
return db.drop().then(_ => db.close());
@ -58,6 +65,16 @@ add_task(function* test_pushNotifications() {
pushEndpoint: serverURL + '/pushEndpoint1',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint1',
scope: 'https://example.com/page/1',
p256dhPublicKey: 'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA',
p256dhPrivateKey: {
crv: 'P-256',
d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM',
ext: true,
key_ops: ["deriveBits"],
kty: "EC",
x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
},
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
quota: Infinity,
}, {
@ -65,6 +82,16 @@ add_task(function* test_pushNotifications() {
pushEndpoint: serverURL + '/pushEndpoint2',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint2',
scope: 'https://example.com/page/2',
p256dhPublicKey: 'BPnWyUo7yMnuMlyKtERuLfWE8a09dtdjHSW2lpC9_BqR5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E',
p256dhPrivateKey: {
crv: 'P-256',
d: 'lFm4nPsUKYgNGBJb5nXXKxl8bspCSp0bAhCYxbveqT4',
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: '-dbJSjvIye4yXIq0RG4t9YTxrT1212MdJbaWkL38GpE',
y: '5TZ1rK8Ldih6ljyxVwnBA-nygQHGRpEmu1jV5K8437E'
},
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
quota: Infinity,
}, {
@ -72,6 +99,16 @@ add_task(function* test_pushNotifications() {
pushEndpoint: serverURL + '/pushEndpoint3',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint3',
scope: 'https://example.com/page/3',
p256dhPublicKey: 'BDhUHITSeVrWYybFnb7ylVTCDDLPdQWMpf8gXhcWwvaaJa6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI',
p256dhPrivateKey: {
crv: 'P-256',
d: 'Q1_SE1NySTYzjbqgWwPgrYh7XRg3adqZLkQPsy319G8',
ext: true,
key_ops: ["deriveBits"],
kty: 'EC',
x: 'OFQchNJ5WtZjJsWdvvKVVMIMMs91BYyl_yBeFxbC9po',
y: 'Ja6n3YH8TOcH8narDF6t8mKVvg2ioLW-8MH5O4dzGcI'
},
originAttributes: ChromeUtils.originAttributesToSuffix({ appId: Ci.nsIScriptSecurityManager.NO_APP_ID, inBrowser: false }),
quota: Infinity,
}];
@ -81,9 +118,27 @@ add_task(function* test_pushNotifications() {
}
let notifyPromise = Promise.all([
promiseObserverNotification('push-notification'),
promiseObserverNotification('push-notification'),
promiseObserverNotification('push-notification')
promiseObserverNotification('push-notification', function(subject, data) {
var notification = subject.QueryInterface(Ci.nsIPushObserverNotification);
if (notification && (data == "https://example.com/page/1")){
equal(subject.data, "Some message", "decoded message is incorrect");
return true;
}
}),
promiseObserverNotification('push-notification', function(subject, data) {
var notification = subject.QueryInterface(Ci.nsIPushObserverNotification);
if (notification && (data == "https://example.com/page/2")){
equal(subject.data, "Some message", "decoded message is incorrect");
return true;
}
}),
promiseObserverNotification('push-notification', function(subject, data) {
var notification = subject.QueryInterface(Ci.nsIPushObserverNotification);
if (notification && (data == "https://example.com/page/3")){
equal(subject.data, "Some message", "decoded message is incorrect");
return true;
}
})
]);
PushService.init({

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

@ -68,6 +68,16 @@ add_task(function* test1() {
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
p256dhPublicKey: 'BPCd4gNQkjwRah61LpdALdzZKLLnU5UAwDztQ5_h0QsT26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA',
p256dhPrivateKey: {
crv: 'P-256',
d: '1jUPhzVsRkzV0vIzwL4ZEsOlKdNOWm7TmaTfzitJkgM',
ext: true,
key_ops: ["deriveBits"],
kty: "EC",
x: '8J3iA1CSPBFqHrUul0At3NkosudTlQDAPO1Dn-HRCxM',
y: '26jk0IFbqcK6-JxhHAm-rsHEwy0CyVJjtnfOcqc1tgA'
},
originAttributes: '',
quota: Infinity,
}];

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

@ -0,0 +1,80 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
'use strict';
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://testing-common/httpd.js");
const {PushDB, PushService, PushServiceHttp2} = serviceExports;
var httpServer = null;
XPCOMUtils.defineLazyGetter(this, "serverPort", function() {
return httpServer.identity.primaryPort;
});
function listenHandler(metadata, response) {
do_check_true(true, "Start listening");
httpServer.stop(do_test_finished);
response.setHeader("Retry-After", "10");
response.setStatusLine(metadata.httpVersion, 500, "Retry");
}
httpServer = new HttpServer();
httpServer.registerPathHandler("/subscriptionNoKey", listenHandler);
httpServer.start(-1);
function run_test() {
do_get_profile();
setPrefs({
'http2.retryInterval': 1000,
'http2.maxRetries': 2
});
disableServiceWorkerEvents(
'https://example.com/page'
);
run_next_test();
}
add_task(function* test1() {
let db = PushServiceHttp2.newPushDB();
do_register_cleanup(_ => {
return db.drop().then(_ => db.close());
});
do_test_pending();
var serverURL = "http://localhost:" + httpServer.identity.primaryPort;
let record = {
subscriptionUri: serverURL + '/subscriptionNoKey',
pushEndpoint: serverURL + '/pushEndpoint',
pushReceiptEndpoint: serverURL + '/pushReceiptEndpoint',
scope: 'https://example.com/page',
originAttributes: '',
quota: Infinity,
};
yield db.put(record);
let notifyPromise = promiseObserverNotification('push-subscription-change',
_ => true);
PushService.init({
serverURI: serverURL + "/subscribe",
service: PushServiceHttp2,
db
});
yield waitForPromise(notifyPromise, DEFAULT_TIMEOUT,
'Timed out waiting for notifications');
let aRecord = yield db.getByKeyID(serverURL + '/subscriptionNoKey');
ok(aRecord, 'The record should still be there');
ok(aRecord.p256dhPublicKey, 'There should be a public key');
ok(aRecord.p256dhPrivateKey, 'There should be a private key');
});

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

@ -38,6 +38,7 @@ skip-if = toolkit == 'android'
[test_resubscribe_5xxCode_http2.js]
[test_resubscribe_listening_for_msg_error_http2.js]
[test_register_5xxCode_http2.js]
[test_updateRecordNoEncryptionKeys.js]
[test_register_success_http2.js]
skip-if = !hasNode
run-sequentially = node server exceptions dont replay well

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

@ -191,3 +191,5 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolk
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
[test_upgrade_insecure_cors.html]
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'gonk' || toolkit == 'android'
[test_blocked_uri_in_reports.html]
skip-if = e10s || buildapp == 'b2g' # http-on-opening-request observer not supported in child process (bug 1009632)

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

@ -0,0 +1,118 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Bug 1069762 - Check blocked-uri in csp-reports after redirect</title>
<!-- Including SimpleTest.js so we can use waitForExplicitFinish !-->
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
/* Description of the test:
* We try to load a script from:
* http://example.com/tests/dom/security/test/csp/file_path_matching_redirect_server.sjs
* which gets redirected to:
* http://test1.example.com/tests/dom/security//test/csp/file_path_matching.js
*
* The blocked-uri in the csp-report should be:
* test1.example.com
* instead of:
* http://test1.example.com/tests/com/security/test/csp/file_path_matching.js
*
* see also: http://www.w3.org/TR/CSP/#violation-reports
*
* Note, that we reuse the test-setup from
* test_path_matching_redirect.html
*/
const reportURI = "http://mochi.test:8888/foo.sjs";
const policy = "script-src http://example.com; report-uri " + reportURI;
const testfile = "tests/dom/security/test/csp/file_path_matching_redirect.html";
// This is used to watch requests go out so we can see if the report is
// sent correctly
function examiner() {
SpecialPowers.addObserver(this, "http-on-opening-request", false);
}
examiner.prototype = {
observe: function(subject, topic, data) {
// subject should be an nsURI
if (!SpecialPowers.can_QI(subject))
return;
if (topic === "http-on-opening-request") {
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
if (asciiSpec !== reportURI) return;
try {
// Verify that the report was properly formatted.
// We'll parse the report text as JSON and verify that the properties
// have expected values.
var reportText = "{}";
var uploadStream = SpecialPowers.wrap(SpecialPowers.do_QueryInterface(subject, "nsIUploadChannel")).uploadStream;
if (uploadStream) {
// get the bytes from the request body
var binstream = SpecialPowers.Cc["@mozilla.org/binaryinputstream;1"]
.createInstance(SpecialPowers.Ci.nsIBinaryInputStream);
binstream.setInputStream(uploadStream);
var segments = [];
for (var count = uploadStream.available(); count; count = uploadStream.available()) {
var data = binstream.readBytes(count);
segments.push(data);
}
var reportText = segments.join("");
// rewind stream as we are supposed to - there will be an assertion later if we don't.
SpecialPowers.do_QueryInterface(uploadStream, "nsISeekableStream").seek(SpecialPowers.Ci.nsISeekableStream.NS_SEEK_SET, 0);
}
try {
var reportObj = JSON.parse(reportText);
}
catch (e) {
ok(false, "Could not parse JSON (exception: " + e + ")");
}
var cspReport = reportObj["csp-report"];
// blocked-uri should only be the asciiHost instead of:
// http://test1.example.com/tests/dom/security/test/csp/file_path_matching.js
is(cspReport["blocked-uri"], "http://test1.example.com", "Incorrect blocked-uri");
}
catch (e) {
ok(false, "Could not query report (exception: " + e + ")");
}
// finish up
window.examiner.remove();
SimpleTest.finish();
}
},
// remove the listener
remove: function() {
SpecialPowers.removeObserver(this, "http-on-opening-request");
}
}
window.examiner = new examiner();
SimpleTest.waitForExplicitFinish();
function runTest() {
var src = "file_testserver.sjs";
// append the file that should be served
src += "?file=" + escape(testfile);
// append the CSP that should be used to serve the file
src += "&csp=" + escape(policy);
document.getElementById("cspframe").src = src;
}
runTest();
</script>
</body>
</html>

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

@ -643,7 +643,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly)
mClient->Activate(mCurrentInterval->Begin()->Time().GetMillis());
}
if (mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_BEGIN, 0);
FireTimeEventAsync(eSMILBeginEvent, 0);
}
if (HasPlayed()) {
Reset(); // Apply restart behaviour
@ -679,7 +679,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly)
}
mCurrentInterval->FixEnd();
if (mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_END, 0);
FireTimeEventAsync(eSMILEndEvent, 0);
}
mCurrentRepeatIteration = 0;
mOldIntervals.AppendElement(mCurrentInterval.forget());
@ -727,7 +727,7 @@ nsSMILTimedElement::DoSampleAt(nsSMILTime aContainerTime, bool aEndOnly)
mCurrentRepeatIteration != prevRepeatIteration &&
mCurrentRepeatIteration &&
mSeekState == SEEK_NOT_SEEKING) {
FireTimeEventAsync(NS_SMIL_REPEAT,
FireTimeEventAsync(eSMILRepeatEvent,
static_cast<int32_t>(mCurrentRepeatIteration));
}
}
@ -1518,14 +1518,14 @@ nsSMILTimedElement::DoPostSeek()
case SEEK_FORWARD_FROM_ACTIVE:
case SEEK_BACKWARD_FROM_ACTIVE:
if (mElementState != STATE_ACTIVE) {
FireTimeEventAsync(NS_SMIL_END, 0);
FireTimeEventAsync(eSMILEndEvent, 0);
}
break;
case SEEK_FORWARD_FROM_INACTIVE:
case SEEK_BACKWARD_FROM_INACTIVE:
if (mElementState == STATE_ACTIVE) {
FireTimeEventAsync(NS_SMIL_BEGIN, 0);
FireTimeEventAsync(eSMILBeginEvent, 0);
}
break;

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

@ -9,11 +9,17 @@
interface Principal;
enum PushEncryptionKeyName
{
"p256dh"
};
[Exposed=(Window,Worker), Func="nsContentUtils::PushEnabled",
ChromeConstructor(DOMString pushEndpoint, DOMString scope)]
ChromeConstructor(DOMString pushEndpoint, DOMString scope, ArrayBuffer? key)]
interface PushSubscription
{
readonly attribute USVString endpoint;
ArrayBuffer? getKey(PushEncryptionKeyName name);
[Throws, UseCounter]
Promise<boolean> unsubscribe();
jsonifier;

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

@ -1103,11 +1103,11 @@ private:
class DebuggerImmediateRunnable : public WorkerRunnable
{
nsRefPtr<Function> mHandler;
nsRefPtr<dom::Function> mHandler;
public:
explicit DebuggerImmediateRunnable(WorkerPrivate* aWorkerPrivate,
Function& aHandler)
dom::Function& aHandler)
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
mHandler(&aHandler)
{ }
@ -5666,7 +5666,7 @@ WorkerPrivate::PostMessageToDebugger(const nsAString& aMessage)
}
void
WorkerPrivate::SetDebuggerImmediate(JSContext* aCx, Function& aHandler,
WorkerPrivate::SetDebuggerImmediate(JSContext* aCx, dom::Function& aHandler,
ErrorResult& aRv)
{
AssertIsOnWorkerThread();
@ -5904,7 +5904,7 @@ WorkerPrivate::ReportError(JSContext* aCx, const char* aMessage,
int32_t
WorkerPrivate::SetTimeout(JSContext* aCx,
Function* aHandler,
dom::Function* aHandler,
const nsAString& aStringHandler,
int32_t aTimeout,
const Sequence<JS::Value>& aArguments,

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

@ -254,7 +254,7 @@ nsEditor::Init(nsIDOMDocument *aDoc, nsIContent *aRoot,
// recreated with same content. Therefore, we need to forget mIMETextNode,
// but we need to keep storing mIMETextOffset and mIMETextLength becuase
// they are necessary to restore IME selection and replacing composing string
// when this receives NS_COMPOSITION_CHANGE event next time.
// when this receives eCompositionChange event next time.
if (mIMETextNode && !mIMETextNode->IsInComposedDoc()) {
mIMETextNode = nullptr;
}
@ -5159,11 +5159,11 @@ nsEditor::IsAcceptableInputEvent(nsIDOMEvent* aEvent)
// If events are not created with proper event interface, their message
// are initialized with eUnidentifiedEvent. Let's ignore such event.
return false;
case NS_COMPOSITION_START:
case NS_COMPOSITION_END:
case NS_COMPOSITION_UPDATE:
case NS_COMPOSITION_CHANGE:
case NS_COMPOSITION_COMMIT_AS_IS:
case eCompositionStart:
case eCompositionEnd:
case eCompositionUpdate:
case eCompositionChange:
case eCompositionCommitAsIs:
// Don't allow composition events whose internal event are not
// WidgetCompositionEvent.
widgetGUIEvent = aEvent->GetInternalNSEvent()->AsCompositionEvent();

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

@ -460,13 +460,13 @@ nsEditorEventListener::HandleEvent(nsIDOMEvent* aEvent)
case eBlur:
return Blur(aEvent);
// text
case NS_COMPOSITION_CHANGE:
case eCompositionChange:
return HandleText(aEvent);
// compositionstart
case NS_COMPOSITION_START:
case eCompositionStart:
return HandleStartComposition(aEvent);
// compositionend
case NS_COMPOSITION_END:
case eCompositionEnd:
HandleEndComposition(aEvent);
return NS_OK;
default:

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

@ -845,8 +845,8 @@ nsPlaintextEditor::UpdateIMEComposition(nsIDOMEvent* aDOMTextEvent)
WidgetCompositionEvent* compositionChangeEvent =
aDOMTextEvent->GetInternalNSEvent()->AsCompositionEvent();
NS_ENSURE_TRUE(compositionChangeEvent, NS_ERROR_INVALID_ARG);
MOZ_ASSERT(compositionChangeEvent->mMessage == NS_COMPOSITION_CHANGE,
"The internal event should be NS_COMPOSITION_CHANGE");
MOZ_ASSERT(compositionChangeEvent->mMessage == eCompositionChange,
"The internal event should be eCompositionChange");
EnsureComposition(compositionChangeEvent);

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

@ -1,6 +1,6 @@
This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev
Current version derived from upstream changeset e6539b6769cf
Current version derived from upstream changeset 0f9edca71849
See gfx/graphite2/moz-gr-update.sh for update procedure.

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

@ -30,7 +30,7 @@
#define GR2_VERSION_MAJOR 1
#define GR2_VERSION_MINOR 3
#define GR2_VERSION_BUGFIX 0
#define GR2_VERSION_BUGFIX 2
#ifdef __cplusplus
extern "C"

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

@ -170,7 +170,8 @@ enum gr_bidirtl {
/// Underlying paragraph direction is RTL
gr_rtl = 1,
/// Set this to not run the bidi pass internally, even if the font asks for it.
/// This presumes that the segment is in a single direction.
/// This presumes that the segment is in a single direction. Most of the time
/// this bit should be set unless you know you are passing full paragraphs of text.
gr_nobidi = 2,
/// Disable auto mirroring for rtl text
gr_nomirror = 4

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

@ -747,7 +747,7 @@ void resolveWhitespace(int baseLevel, Slot *s)
for ( ; s; s = s->prev())
{
int8 cls = s->getBidiClass();
if (cls == WS || cls & WSflag)
if (cls == WS || (cls & WSflag))
s->setBidiLevel(baseLevel);
else if (cls != BN)
break;

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

@ -74,7 +74,6 @@ add_library(graphite2 SHARED
gr_logging.cpp
gr_segment.cpp
gr_slot.cpp
Bidi.cpp
CachedFace.cpp
CmapCache.cpp
Code.cpp
@ -107,17 +106,14 @@ set_target_properties(graphite2 PROPERTIES PUBLIC_HEADER "${GRAPHITE_HEADERS}"
LT_VERSION_REVISION ${GRAPHITE_API_REVISION}
LT_VERSION_AGE ${GRAPHITE_API_AGE})
if (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
set(GRAPHITE_LINK_FLAGS "-fsanitize=address")
else (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
set(GRAPHITE_LINK_FLAGS "")
endif (${CMAKE_BUILD_TYPE} STREQUAL "ClangASN")
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set_target_properties(graphite2 PROPERTIES
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector -Wdouble-promotion"
COMPILE_FLAGS "-Wall -Wextra -Wno-unknown-pragmas -Wendif-labels -Wshadow -Wctor-dtor-privacy -Wnon-virtual-dtor -fno-rtti -fno-exceptions -fvisibility=hidden -fvisibility-inlines-hidden -fno-stack-protector"
LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}"
LINKER_LANGUAGE C)
if (CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-Wdouble-promotion)
endif (CMAKE_COMPILER_IS_GNUCXX)
if (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
target_link_libraries(graphite2 kernel32 msvcr90 mingw32 gcc user32)
else (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")

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

@ -38,11 +38,11 @@ const void * bmp_subtable(const Face::Table & cmap)
{
const void * stbl;
if (!cmap.size()) return 0;
if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()))
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()))
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()))
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()))
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size())))
if (TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 1, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 3, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 2, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 1, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable4(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 0, cmap.size()), cmap.size()))
return stbl;
return 0;
}
@ -51,8 +51,8 @@ const void * smp_subtable(const Face::Table & cmap)
{
const void * stbl;
if (!cmap.size()) return 0;
if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()))
|| TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size())))
if (TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 3, 10, cmap.size()), cmap.size())
|| TtfUtil::CheckCmapSubtable12(stbl = TtfUtil::FindCmapSubtable(cmap, 0, 4, cmap.size()), cmap.size()))
return stbl;
return 0;
}

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

@ -77,7 +77,6 @@ struct context
} // end namespace
byte * Machine::Code::local_memory = 0;
class Machine::Code::decoder
{
@ -90,7 +89,8 @@ public:
byte max_ref;
analysis() : slotref(0), max_ref(0) {};
void set_ref(int index) throw();
void set_ref(int index, bool incinsert=false) throw();
void set_noref(int index) throw();
void set_changed(int index) throw();
};
@ -146,7 +146,7 @@ inline Machine::Code::decoder::decoder(limits & lims, Code &code, enum passtype
Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
uint8 pre_context, uint16 rule_length, const Silf & silf, const Face & face,
enum passtype pt, byte * & _out)
enum passtype pt, byte * * const _out)
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0), _status(loaded),
_constraint(is_constraint), _modify(false), _delete(false), _own(_out==0)
{
@ -162,11 +162,10 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
assert(bytecode_end > bytecode_begin);
const opcode_t * op_to_fn = Machine::getOpcodeTable();
// Allocate code and dat target buffers, these sizes are a worst case
// Allocate code and data target buffers, these sizes are a worst case
// estimate. Once we know their real sizes the we'll shrink them.
if (_out) _code = reinterpret_cast<instr *>(_out);
else _code = static_cast<instr *>(malloc((bytecode_end - bytecode_begin)
* (sizeof(instr)+sizeof(byte))));
if (_out) _code = reinterpret_cast<instr *>(*_out);
else _code = static_cast<instr *>(malloc(estimateCodeDataOut(bytecode_end-bytecode_begin)));
_data = reinterpret_cast<byte *>(_code + (bytecode_end - bytecode_begin));
if (!_code || !_data) {
@ -220,7 +219,7 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
memmove(_code + (_instr_count+1), _data, _data_size*sizeof(byte));
size_t const total_sz = ((_instr_count+1) + (_data_size + sizeof(instr)-1)/sizeof(instr))*sizeof(instr);
if (_out)
_out += total_sz;
*_out += total_sz;
else
_code = static_cast<instr *>(realloc(_code, total_sz));
_data = reinterpret_cast<byte *>(_code + (_instr_count+1));
@ -418,9 +417,11 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
break;
case PUSH_IGLYPH_ATTR :// not implemented
++_stack_depth;
break;
case POP_RET :
if (--_stack_depth < 0)
failure(underfull_stack);
// no break
case RET_ZERO :
case RET_TRUE :
break;
@ -477,14 +478,23 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg)
case PUT_GLYPH_8BIT_OBS :
case PUT_GLYPH :
_code._modify = true;
_analysis.set_changed(_analysis.slotref);
_analysis.set_changed(0);
break;
case ATTR_SET :
case ATTR_ADD :
case ATTR_SET_SLOT :
case IATTR_SET_SLOT :
case IATTR_SET :
case IATTR_ADD :
case IATTR_SUB :
_analysis.set_noref(0);
break;
case NEXT :
case COPY_NEXT :
if (!_analysis.contexts[_analysis.slotref].flags.inserted)
++_analysis.slotref;
_analysis.contexts[_analysis.slotref] = context(_code._instr_count+1);
if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
// if (_analysis.slotref > _analysis.max_ref) _analysis.max_ref = _analysis.slotref;
break;
case INSERT :
_analysis.contexts[_analysis.slotref].flags.inserted = true;
@ -493,14 +503,15 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg)
case PUT_SUBS_8BIT_OBS : // slotref on 1st parameter
case PUT_SUBS :
_code._modify = true;
_analysis.set_changed(_analysis.slotref);
_analysis.set_changed(0);
// no break
case PUT_COPY :
{
if (arg[0] != 0) { _analysis.set_changed(_analysis.slotref); _code._modify = true; }
if (arg[0] != 0) { _analysis.set_changed(0); _code._modify = true; }
if (arg[0] <= 0 && -arg[0] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
_analysis.set_ref(_analysis.slotref + arg[0] - _analysis.contexts[_analysis.slotref].flags.inserted);
else if (_analysis.slotref + arg[0] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[0];
_analysis.set_ref(arg[0], true);
else if (arg[0] > 0)
_analysis.set_ref(arg[0], true);
break;
}
case PUSH_ATT_TO_GATTR_OBS : // slotref on 2nd parameter
@ -513,16 +524,18 @@ void Machine::Code::decoder::analyse_opcode(const opcode opc, const int8 * arg)
case PUSH_ISLOT_ATTR :
case PUSH_FEAT :
if (arg[1] <= 0 && -arg[1] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
_analysis.set_ref(_analysis.slotref + arg[1] - _analysis.contexts[_analysis.slotref].flags.inserted);
else if (_analysis.slotref + arg[1] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[1];
_analysis.set_ref(arg[1], true);
else if (arg[1] > 0)
_analysis.set_ref(arg[1], true);
break;
case PUSH_ATT_TO_GLYPH_ATTR :
if (_code._constraint) return;
// no break
case PUSH_GLYPH_ATTR :
if (arg[2] <= 0 && -arg[2] <= _analysis.slotref - _analysis.contexts[_analysis.slotref].flags.inserted)
_analysis.set_ref(_analysis.slotref + arg[2] - _analysis.contexts[_analysis.slotref].flags.inserted);
else if (_analysis.slotref + arg[2] > _analysis.max_ref) _analysis.max_ref = _analysis.slotref + arg[2];
_analysis.set_ref(arg[2], true);
else if (arg[2] > 0)
_analysis.set_ref(arg[2], true);
break;
case ASSOC : // slotrefs in varargs
break;
@ -604,6 +617,7 @@ void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end
*tip = temp_copy;
++code_end;
++tempcount;
_code._delete = true;
}
_code._instr_count = code_end - code;
@ -619,8 +633,13 @@ bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * cons
return false;
}
const opcode_t & op = Machine::getOpcodeTable()[opc];
if (op.param_sz == VARARGS && bc >= _max.bytecode)
{
failure(arguments_exhausted);
return false;
}
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
if (bc - 1 + param_sz > _max.bytecode)
if (bc - 1 + param_sz >= _max.bytecode)
{
failure(arguments_exhausted);
return false;
@ -654,16 +673,28 @@ void Machine::Code::failure(const status_t s) throw() {
inline
void Machine::Code::decoder::analysis::set_ref(const int index) throw() {
contexts[index].flags.referenced = true;
if (index > max_ref) max_ref = index;
void Machine::Code::decoder::analysis::set_ref(int index, bool incinsert) throw() {
if (incinsert && contexts[slotref].flags.inserted) --index;
if (index + slotref < 0) return;
contexts[index + slotref].flags.referenced = true;
if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
}
inline
void Machine::Code::decoder::analysis::set_changed(const int index) throw() {
contexts[index].flags.changed = true;
if (index > max_ref) max_ref = index;
void Machine::Code::decoder::analysis::set_noref(int index) throw() {
if (contexts[slotref].flags.inserted) --index;
if (index + slotref < 0) return;
if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
}
inline
void Machine::Code::decoder::analysis::set_changed(int index) throw() {
if (contexts[slotref].flags.inserted) --index;
if (index + slotref < 0) return;
contexts[index + slotref].flags.changed = true;
if ((index > 0 || !contexts[index + slotref].flags.inserted) && index + slotref > max_ref) max_ref = index + slotref;
}
@ -682,10 +713,12 @@ int32 Machine::Code::run(Machine & m, slotref * & map) const
// assert(_own);
assert(*this); // Check we are actually runnable
if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context()))
if (m.slotMap().size() <= size_t(_max_ref + m.slotMap().context())
|| m.slotMap()[_max_ref + m.slotMap().context()] == 0)
{
m._status = Machine::slot_offset_out_bounds;
return 1;
// return m.run(_code, _data, map);
}
return m.run(_code, _data, map);

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

@ -39,7 +39,7 @@ of the License or (at your option) any later version.
// Possible rounding error for subbox boundaries: 0.016 = 1/64 = 1/256 * 4
// (values in font range from 0..256)
#define SUBBOX_RND_ERR 0.016
// #define SUBBOX_RND_ERR 0.016
using namespace graphite2;
@ -543,7 +543,7 @@ bool ShiftCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShif
}
}
bool res = true;
if (cslot && cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
if (cslot->exclGlyph() > 0 && gc.check(cslot->exclGlyph()) && !isExclusion)
{
// Set up the bogus slot representing the exclusion glyph.
Slot *exclSlot = seg->newSlot();
@ -925,6 +925,8 @@ bool KernCollider::initSlot(Segment *seg, Slot *aSlot, const Rect &limit, float
bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift, float currSpace, int dir, GR_MAYBE_UNUSED json * const dbgout)
{
int rtl = (dir & 1) * 2 - 1;
if (!seg->getFace()->glyphs().check(slot->gid()))
return false;
const Rect &bb = seg->theGlyphBBoxTemporary(slot->gid());
const float sx = slot->origin().x + currShift.x;
float x = sx + (rtl > 0 ? bb.tr.x : bb.bl.x);
@ -971,7 +973,6 @@ bool KernCollider::mergeSlot(Segment *seg, Slot *slot, const Position &currShift
// Return the amount to kern by.
// TODO: do we need to make use of marginMin here? Probably not.
Position KernCollider::resolve(GR_MAYBE_UNUSED Segment *seg, GR_MAYBE_UNUSED Slot *slot,
int dir, float margin, GR_MAYBE_UNUSED json * const dbgout)
{

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

@ -1,75 +1,75 @@
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
Copyright (c) 2015, SIL International
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#include <cassert>
#include "inc/Decompressor.h"
#include "inc/Shrinker.h"
#include "inc/Compression.h"
using namespace shrinker;
using namespace lz4;
namespace {
u8 const LONG_DIST = 0x10;
u8 const MATCH_LEN = 0x0f;
template <int M>
inline
u32 read_literal(u8 const * &s, u8 const * const e, u32 l) {
if (unlikely(l == M))
if (unlikely(l == 15) && likely(s != e))
{
u8 b = 0;
u8 b = 0;
do { l += b = *s++; } while(b==0xff && s != e);
}
return l;
}
bool read_directive(u8 const * &src, u8 const * const end, u32 & literal_len, u32 & match_len, u32 & match_dist)
bool read_sequence(u8 const * &src, u8 const * const end, u8 const * &literal, u32 & literal_len, u32 & match_len, u32 & match_dist)
{
u8 const flag = *src++;
u8 const token = *src++;
literal_len = read_literal<7>(src, end, flag >> 5);
match_len = read_literal<15>(src, end, flag & MATCH_LEN);
literal_len = read_literal(src, end, token >> 4);
literal = src;
src += literal_len;
match_dist = *src++;
if (flag & LONG_DIST)
match_dist |= ((*src++) << 8);
if (unlikely(src > end - 2))
return false;
return match_dist != 0xffff;
match_dist = *src++;
match_dist |= *src++ << 8;
match_len = read_literal(src, end, token & 0xf);
return true;
}
}
int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_size)
int lz4::decompress(void const *in, size_t in_size, void *out, size_t out_size)
{
if (out_size <= in_size)
return -1;
u8 const * src = static_cast<u8 const *>(in),
* literal = 0,
* const src_end = src + in_size;
u8 * dst = static_cast<u8*>(out),
@ -78,24 +78,29 @@ int shrinker::decompress(void const *in, size_t in_size, void *out, size_t out_s
u32 literal_len = 0,
match_len = 0,
match_dist = 0;
while (read_directive(src, src_end, literal_len, match_len, match_dist))
while (read_sequence(src, src_end, literal, literal_len, match_len, match_dist))
{
// Copy in literal
if (unlikely(dst + literal_len + sizeof(unsigned long) > dst_end)) return -1;
dst = memcpy_nooverlap(dst, src, literal_len);
src += literal_len;
// Copy in literal. At this point the last full sequence must be at
// least MINMATCH + 5 from the end of the output buffer.
if (unlikely(literal + align(literal_len) > src_end
|| dst + align(literal_len) > dst_end - MINMATCH+5))
return -1;
dst = overrun_copy(dst, literal, literal_len);
// Copy, possibly repeating, match from earlier in the
// decoded output.
u8 const * const pcpy = dst - match_dist - 1;
if (unlikely(pcpy < static_cast<u8*>(out)
|| dst + match_len + MINMATCH + sizeof(unsigned long) > dst_end)) return -1;
dst = memcpy_(dst, pcpy, match_len + MINMATCH);
u8 const * const pcpy = dst - match_dist;
if (unlikely(pcpy < static_cast<u8*>(out)
|| dst + align(match_len + MINMATCH) > dst_end))
return -1;
dst = copy(dst, pcpy, match_len + MINMATCH);
}
if (unlikely(dst + literal_len > dst_end)) return -1;
dst = memcpy_nooverlap_surpass(dst, src, literal_len);
if (unlikely(literal + literal_len > src_end
|| dst + literal_len > dst_end))
return -1;
dst = fast_copy(dst, literal, literal_len);
return dst - (u8*)out;
}

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

@ -46,7 +46,7 @@ namespace
enum compression
{
NONE,
SHRINKER
LZ4
};
}
@ -125,7 +125,7 @@ bool Face::readGraphite(const Table & silf)
Error e;
error_context(EC_READSILF);
const byte * p = silf;
if (e.test(!p, E_NOSILF)) return error(e);
if (e.test(!p, E_NOSILF) || e.test(silf.size() < 20, E_BADSIZE)) return error(e);
const uint32 version = be::read<uint32>(p);
if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
@ -173,6 +173,10 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
}
#endif
// if ((seg->dir() & 1) != aSilf->dir())
// seg->reverseSlots();
if ((seg->dir() & 3) == 3 && aSilf->bidiPass() == 0xFF)
seg->doMirror(aSilf->aMirror());
bool res = aSilf->runGraphite(seg, 0, aSilf->positionPass(), true);
if (res)
{
@ -185,6 +189,7 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
#if !defined GRAPHITE2_NTRACING
if (dbgout)
{
seg->positionSlots(0, 0, 0, aSilf->dir());
*dbgout << json::item
<< json::close // Close up the passes array
<< "output" << json::array;
@ -233,7 +238,9 @@ uint16 Face::getGlyphMetric(uint16 gid, uint8 metric) const
{
case kgmetAscent : return m_ascent;
case kgmetDescent : return m_descent;
default: return glyphs().glyph(gid)->getMetric(metric);
default:
if (gid > glyphs().numGlyphs()) return 0;
return glyphs().glyph(gid)->getMetric(metric);
}
}
@ -277,7 +284,6 @@ Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
if (!TtfUtil::CheckTable(n, _p, _sz))
{
this->~Table(); // Make sure we release the table buffer even if the table filed it's checks
_p = 0; _sz = 0;
return;
}
@ -285,6 +291,15 @@ Face::Table::Table(const Face & face, const Tag n, uint32 version) throw()
decompress();
}
void Face::Table::releaseBuffers()
{
if (_compressed)
free(const_cast<byte *>(_p));
else if (_p && _f->m_ops.release_table)
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
_p = 0; _sz = 0;
}
Face::Table & Face::Table::operator = (const Table & rhs) throw()
{
if (_p == rhs._p) return *this;
@ -297,6 +312,8 @@ Face::Table & Face::Table::operator = (const Table & rhs) throw()
Error Face::Table::decompress()
{
Error e;
if (e.test(_sz < 2 * sizeof(uint32) + 3, E_BADSIZE))
return e;
byte * uncompressed_table = 0;
size_t uncompressed_size = 0;
@ -308,25 +325,30 @@ Error Face::Table::decompress()
switch(compression(hdr >> 27))
{
case NONE: return e;
case SHRINKER:
case LZ4:
{
uncompressed_size = hdr & 0x07ffffff;
uncompressed_table = gralloc<byte>(uncompressed_size);
//TODO: Coverty: 1315803: FORWARD_NULL
if (!e.test(!uncompressed_table, E_OUTOFMEM))
e.test(shrinker::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
//TODO: Coverty: 1315800: CHECKED_RETURN
e.test(lz4::decompress(p, _sz - 2*sizeof(uint32), uncompressed_table, uncompressed_size) != signed(uncompressed_size), E_SHRINKERFAILED);
break;
}
default:
e.error(E_BADSCHEME);
};
// Check the uncompressed version number against the original.
if (!e)
//TODO: Coverty: 1315800: CHECKED_RETURN
e.test(be::peek<uint32>(uncompressed_table) != version, E_SHRINKERFAILED);
// Tell the provider to release the compressed form since were replacing
// it anyway.
this->~Table();
releaseBuffers();
if (e)
{

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

@ -131,11 +131,12 @@ bool FeatureMap::readFeats(const Face & face)
const uint16 num_settings = be::read<uint16>(p);
if (version >= 0x00020000)
be::skip<uint16>(p);
const byte * const feat_setts = feat_start + be::read<uint32>(p);
const uint32 settings_offset = be::read<uint32>(p);
const uint16 flags = be::read<uint16>(p),
uiName = be::read<uint16>(p);
if (feat_setts + num_settings * FEATURE_SETTING_SIZE > feat_end)
if (settings_offset > size_t(feat_end - feat_start)
|| settings_offset + num_settings * FEATURE_SETTING_SIZE > size_t(feat_end - feat_start))
{
free(defVals);
return false;
@ -151,7 +152,7 @@ bool FeatureMap::readFeats(const Face & face)
free(defVals);
return false;
}
maxVal = readFeatureSettings(feat_setts, uiSet, num_settings);
maxVal = readFeatureSettings(feat_start + settings_offset, uiSet, num_settings);
defVals[i] = uiSet[0].value();
}
else

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

@ -83,7 +83,7 @@ const void *FileFace::get_table_fn(const void* appFaceHandle, unsigned int name,
if (!TtfUtil::GetTableInfo(name, file_face._header_tbl, file_face._table_dir, tbl_offset, tbl_len))
return 0;
if (tbl_offset + tbl_len > file_face._file_len
if (tbl_offset > file_face._file_len || tbl_len > file_face._file_len - tbl_offset
|| fseek(file_face._file, tbl_offset, SEEK_SET) != 0)
return 0;

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

@ -62,7 +62,7 @@ namespace
// This is strictly a >= operator. A true == operator could be
// implemented that test for overlap but it would be more expensive a
// test.
bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e; }
bool operator == (const _glat_iterator<W> & rhs) { return _v >= rhs._e - 1; }
bool operator != (const _glat_iterator<W> & rhs) { return !operator==(rhs); }
value_type operator * () const {
@ -78,7 +78,8 @@ namespace
typedef _glat_iterator<uint16> glat2_iterator;
}
const Rect GlyphCache::nullRect = Rect();
const SlantBox SlantBox::empty = {0,0,0,0};
class GlyphCache::Loader
{
@ -145,7 +146,7 @@ GlyphCache::GlyphCache(const Face & face, const uint32 face_options)
}
else if (numsubs > 0)
{
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + (numsubs-1) * 8 * sizeof(float));
GlyphBox * boxes = (GlyphBox *)gralloc<char>(_num_glyphs * sizeof(GlyphBox) + numsubs * 8 * sizeof(float));
GlyphBox * currbox = boxes;
for (uint16 gid = 0; currbox && gid != _num_glyphs; ++gid)
@ -277,19 +278,20 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
// subtracting the length of the attribids array (numAttribs long if present)
// and dividing by either 2 or 4 depending on shor or lonf format
_long_fmt = flags & 1;
_num_glyphs_attributes = (m_pGloc.size()
int tmpnumgattrs = (m_pGloc.size()
- (p - m_pGloc)
- sizeof(uint16)*(flags & 0x2 ? _num_attrs : 0))
/ (_long_fmt ? sizeof(uint32) : sizeof(uint16)) - 1;
if (version >= 0x00020000
if (version >= 0x00020000 || tmpnumgattrs < 0 || tmpnumgattrs > 65535
|| _num_attrs == 0 || _num_attrs > 0x3000 // is this hard limit appropriate?
|| _num_glyphs_graphics > _num_glyphs_attributes)
|| _num_glyphs_graphics > tmpnumgattrs)
{
_head = Face::Table();
return;
}
_num_glyphs_attributes = static_cast<unsigned short>(tmpnumgattrs);
p = m_pGlat;
version = be::read<uint32>(p);
if (version >= 0x00040000) // reject Glat tables that are too new
@ -347,8 +349,12 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
{
if ((xMin > xMax) || (yMin > yMax))
return 0;
bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
Position(static_cast<float>(xMax), static_cast<float>(yMax)));
}
}
if (TtfUtil::HorMetrics(glyphid, _hmtx, _hmtx.size(), _hhea, nLsb, nAdvWid))
advance = Position(static_cast<float>(nAdvWid), 0);
@ -398,7 +404,8 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
else
{
if (gloce - glocs < 3*sizeof(uint16) // can a glyph have no attributes? why not?
|| gloce - glocs > _num_attrs*3*sizeof(uint16))
|| gloce - glocs > _num_attrs*3*sizeof(uint16)
|| glocs > m_pGlat.size() - 2*sizeof(uint16))
return 0;
new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
}

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

@ -31,7 +31,7 @@ of the License or (at your option) any later version.
#include "inc/CharInfo.h"
#include "inc/Slot.h"
#include "inc/Main.h"
#include <math.h>
#include <cmath>
using namespace graphite2;
@ -70,6 +70,13 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
if (width < 0 && !(silf()->flags()))
return width;
if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
{
reverseSlots();
s = pFirst;
pFirst = pLast;
pLast = s;
}
if (!pFirst) pFirst = pSlot;
while (!pFirst->isBase()) pFirst = pFirst->attachedTo();
if (!pLast) pLast = last();
@ -170,7 +177,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
}
}
currWidth += diff - error;
} while (i == 0 && int(abs(error)) > 0 && tWeight);
} while (i == 0 && int(std::abs(error)) > 0 && tWeight);
}
Slot *oldFirst = m_first;
@ -203,7 +210,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
if (dbgout)
{
*dbgout << json::item << json::close; // Close up the passes array
positionSlots(NULL, pSlot, pLast);
positionSlots(NULL, pSlot, pLast, m_dir);
Slot *lEnd = pLast->nextSibling();
*dbgout << "output" << json::array;
for(Slot * t = pSlot; t != lEnd; t = t->next())
@ -212,7 +219,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
}
#endif
res = positionSlots(font, pSlot, pLast);
res = positionSlots(font, pSlot, pLast, m_dir);
if (silf()->flags() & 1)
{
@ -221,6 +228,9 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
}
m_first = oldFirst;
m_last = oldLast;
if ((m_dir & 1) != m_silf->dir() && m_silf->bidiPass() != m_silf->numPasses())
reverseSlots();
return res.x;
}

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

@ -42,6 +42,13 @@ using namespace graphite2;
using vm::Machine;
typedef Machine::Code Code;
enum KernCollison
{
None = 0,
CrossSpace = 1,
InWord = 2,
reserved = 3
};
Pass::Pass()
: m_silf(0),
@ -53,16 +60,20 @@ Pass::Pass()
m_states(0),
m_codes(0),
m_progs(0),
m_flags(0),
m_numCollRuns(0),
m_kernColls(0),
m_iMaxLoop(0),
m_numGlyphs(0),
m_numRules(0),
m_numStates(0),
m_numTransition(0),
m_numSuccess(0),
m_successStart(0),
m_numColumns(0),
m_minPreCtxt(0),
m_maxPreCtxt(0)
m_maxPreCtxt(0),
m_colThreshold(0),
m_isReverseDir(false)
{
}
@ -88,13 +99,17 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
// Read in basic values
m_flags = be::read<byte>(p);
if (e.test((m_flags & 15) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
const byte flags = be::read<byte>(p);
if (e.test((flags & 0x1f) && pt < PASS_TYPE_POSITIONING, E_BADCOLLISIONPASS))
return face.error(e);
m_numCollRuns = flags & 0x7;
m_kernColls = (flags >> 3) & 0x3;
m_isReverseDir = (flags >> 5) & 0x1;
m_iMaxLoop = be::read<byte>(p);
if (m_iMaxLoop < 1) m_iMaxLoop = 1;
be::skip<byte>(p,2); // skip maxContext & maxBackup
m_numRules = be::read<uint16>(p);
if (e.test(!m_numRules && !(m_flags & 7), E_BADEMPTYPASS)) return face.error(e);
if (e.test(!m_numRules && m_numCollRuns == 0, E_BADEMPTYPASS)) return face.error(e);
be::skip<uint16>(p); // fsmOffset - not sure why we would want this
const byte * const pcCode = pass_start + be::read<uint32>(p) - subtable_base,
* const rcCode = pass_start + be::read<uint32>(p) - subtable_base,
@ -152,7 +167,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
const uint16 * const o_actions = reinterpret_cast<const uint16 *>(p);
be::skip<uint16>(p, m_numRules + 1);
const byte * const states = p;
if (e.test(p + 2 * m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
if (e.test(p + 2u*m_numTransition*m_numColumns >= pass_end, E_BADPASSLENGTH)) return face.error(e);
be::skip<int16>(p, m_numTransition*m_numColumns);
be::skip<uint8>(p);
if (e.test(p != pcCode, E_BADPASSCCODEPTR)) return face.error(e);
@ -212,9 +227,10 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
// Allocate pools
m_rules = new Rule [m_numRules];
m_codes = new Code [m_numRules*2];
m_progs = static_cast<byte *>(malloc((ac_end - ac_data + rc_end - rc_data)
*(sizeof(vm::instr)+sizeof(byte))));
byte * prog_pool_free = m_progs;
const size_t prog_pool_sz = vm::Machine::Code::estimateCodeDataOut(ac_end - ac_data + rc_end - rc_data);
m_progs = gralloc<byte>(prog_pool_sz);
byte * prog_pool_free = m_progs,
* prog_pool_end = m_progs + prog_pool_sz;
if (e.test(!(m_rules && m_codes && m_progs), E_OUTOFMEM)) return face.error(e);
Rule * r = m_rules + m_numRules - 1;
@ -233,10 +249,11 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
rc_begin = be::peek<uint16>(o_constraint) ? rc_data + be::peek<uint16>(o_constraint) : rc_end;
if (ac_begin > ac_end || ac_begin > ac_data_end || ac_end > ac_data_end
|| rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end)
|| rc_begin > rc_end || rc_begin > rc_data_end || rc_end > rc_data_end
|| vm::Machine::Code::estimateCodeDataOut(ac_end - ac_begin + rc_end - rc_begin) > size_t(prog_pool_end - prog_pool_free))
return false;
r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free);
r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, prog_pool_free);
r->action = new (m_codes+n*2-2) vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
r->constraint = new (m_codes+n*2-1) vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face, pt, &prog_pool_free);
if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
|| e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
@ -245,19 +262,21 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
return face.error(e);
}
// Shrink the program pool
ptrdiff_t const delta = static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs)) - m_progs;
if (delta)
byte * moved_progs = static_cast<byte *>(realloc(m_progs, prog_pool_free - m_progs));
if (e.test(!moved_progs, E_OUTOFMEM)) return face.error(e);
if (moved_progs != m_progs)
{
m_progs += delta;
for (Code * c = m_codes, * const ce = c + m_numRules*2; c != ce; ++c)
{
c->externalProgramMoved(delta);
c->externalProgramMoved(moved_progs - m_progs);
}
m_progs = moved_progs;
}
// Load the rule entries map
face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
//TODO: Coverty: 1315804: FORWARD_NULL
RuleEntry * re = m_ruleMap = gralloc<RuleEntry>(num_entries);
if (e.test(!re, E_OUTOFMEM)) return face.error(e);
for (size_t n = num_entries; n; --n, ++re)
@ -360,10 +379,11 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
}
bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const
bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const
{
Slot *s = m.slotMap().segment.first();
if (!s || !testPassConstraint(m)) return true;
if (reverse) m.slotMap().segment.reverseSlots();
if (m_numRules)
{
Slot *currHigh = s->next();
@ -387,23 +407,25 @@ bool Pass::runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const
}
} while (s);
}
//TODO: Use enums for flags
const bool collisions = m_numCollRuns || m_kernColls;
if (!(m_flags & 15) || !m.slotMap().segment.hasCollisionInfo())
if (!collisions || !m.slotMap().segment.hasCollisionInfo())
return true;
if (m_flags & 7)
if (m_numCollRuns)
{
if (!(m.slotMap().segment.flags() & Segment::SEG_INITCOLLISIONS))
{
m.slotMap().segment.positionSlots(0, 0, 0, true);
m.slotMap().segment.positionSlots(0, 0, 0, m.slotMap().dir(), true);
// m.slotMap().segment.flags(m.slotMap().segment.flags() | Segment::SEG_INITCOLLISIONS);
}
if (!collisionShift(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout))
if (!collisionShift(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
return false;
}
if ((m_flags & 24) && !collisionKern(&m.slotMap().segment, m.slotMap().segment.dir(), fsm.dbgout))
if ((m_kernColls) && !collisionKern(&m.slotMap().segment, m.slotMap().dir(), fsm.dbgout))
return false;
if ((m_flags & 15) && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
if (collisions && !collisionFinish(&m.slotMap().segment, fsm.dbgout))
return false;
return true;
}
@ -478,8 +500,8 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
if (r != re)
{
const int adv = doAction(r->rule->action, slot, m);
dumpRuleEventOutput(fsm, *r->rule, slot);
if (r->rule->action->deletes()) fsm.slots.collectGarbage();
dumpRuleEventOutput(fsm, m, *r->rule, slot);
if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
adjustSlot(adv, slot, fsm.slots);
*fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
<< json::close; // Close RuelEvent object
@ -501,7 +523,7 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
if (r != re)
{
const int adv = doAction(r->rule->action, slot, m);
if (r->rule->action->deletes()) fsm.slots.collectGarbage();
if (r->rule->action->deletes()) fsm.slots.collectGarbage(slot);
adjustSlot(adv, slot, fsm.slots);
return;
}
@ -533,7 +555,7 @@ void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEnt
}
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, Machine & m, const Rule & r, Slot * const last_slot) const
{
*fsm.dbgout << json::item << json::flat << json::object
<< "id" << &r - m_rules
@ -551,7 +573,7 @@ void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, S
<< json::close // close "input"
<< "slots" << json::array;
const Position rsb_prepos = last_slot ? last_slot->origin() : fsm.slots.segment.advance();
fsm.slots.segment.positionSlots(0);
fsm.slots.segment.positionSlots(0, 0, 0, m.slotMap().dir());
for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
*fsm.dbgout << dslot(&fsm.slots.segment, slot);
@ -607,12 +629,16 @@ bool Pass::testConstraint(const Rule & r, Machine & m) const
}
void SlotMap::collectGarbage()
void SlotMap::collectGarbage(Slot * &aSlot)
{
for(Slot **s = begin(), *const *const se = end() - 1; s != se; ++s) {
Slot *& slot = *s;
if(slot->isDeleted() || slot->isCopied())
{
if (slot == aSlot)
aSlot = slot->prev() ? slot->prev() : slot->next();
segment.freeSlot(slot);
}
}
}
@ -681,7 +707,6 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
{
ShiftCollider shiftcoll(dbgout);
// bool isfirst = true;
const uint8 numLoops = m_flags & 7; // number of loops permitted to fix collisions; does not include kerning
bool hasCollisions = false;
Slot *start = seg->first(); // turn on collision fixing for the first slot
Slot *end = NULL;
@ -690,7 +715,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
#if !defined GRAPHITE2_NTRACING
if (dbgout)
*dbgout << "collisions" << json::array
<< json::flat << json::object << "num-loops" << numLoops << json::close;
<< json::flat << json::object << "num-loops" << m_numCollRuns << json::close;
#endif
while (start)
@ -707,7 +732,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
if (start && (c->flags() & (SlotCollision::COLL_FIX | SlotCollision::COLL_KERN)) == SlotCollision::COLL_FIX
&& !resolveCollisions(seg, s, start, shiftcoll, false, dir, moved, hasCollisions, dbgout))
return false;
if (s != start && c->flags() & SlotCollision::COLL_END)
if (s != start && (c->flags() & SlotCollision::COLL_END))
{
end = s->next();
break;
@ -720,7 +745,7 @@ bool Pass::collisionShift(Segment *seg, int dir, json * const dbgout) const
#endif
// phase 2 : loop until happy.
for (int i = 0; i < numLoops - 1; ++i)
for (int i = 0; i < m_numCollRuns - 1; ++i)
{
if (hasCollisions || moved)
{
@ -918,7 +943,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
|| (rtl ^ ignoreForKern)) // or it comes before(ltr) or after(rtl)
&& (!isRev // if processing forwards then good to merge otherwise only:
|| !(cNbor->flags() & SlotCollision::COLL_FIX) // merge in immovable stuff
|| (cNbor->flags() & SlotCollision::COLL_KERN && !sameCluster) // ignore other kernable clusters
|| ((cNbor->flags() & SlotCollision::COLL_KERN) && !sameCluster) // ignore other kernable clusters
|| (cNbor->flags() & SlotCollision::COLL_ISCOL)) // test against other collided glyphs
&& !coll.mergeSlot(seg, nbor, cNbor->shift(), !ignoreForKern, sameCluster, collides, false, dbgout))
return false;
@ -944,7 +969,7 @@ bool Pass::resolveCollisions(Segment *seg, Slot *slotFix, Slot *start,
Rect bbox;
Position here = slotFix->origin() + shift;
float clusterMin = here.x;
slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, false);
slotFix->firstChild()->finalise(seg, NULL, here, bbox, 0, clusterMin, rtl, false);
}
}
}
@ -1002,7 +1027,7 @@ float Pass::resolveKern(Segment *seg, Slot *slotFix, GR_MAYBE_UNUSED Slot *start
SlotCollision *cNbor = seg->collisionInfo(nbor);
if (bb.bl.y == 0.f && bb.tr.y == 0.f)
{
if ((m_flags & 24) == 16)
if (m_kernColls == InWord)
break;
// Add space for a space glyph.
currSpace += nbor->advance();

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

@ -40,7 +40,7 @@ using namespace graphite2;
SegCache::SegCache(const SegCacheStore * store, const Features & feats)
: m_prefixLength(ePrefixLength),
m_maxCachedSegLength(eMaxSpliceSize),
// m_maxCachedSegLength(eMaxSpliceSize),
m_segmentCount(0),
m_features(feats),
m_totalAccessCount(0l), m_totalMisses(0l),
@ -84,7 +84,7 @@ SegCacheEntry* SegCache::cache(SegCacheStore * store, const uint16* cmapGlyphs,
{
uint16 pos = 0;
if (!length) return NULL;
assert(length < m_maxCachedSegLength);
// assert(length < m_maxCachedSegLength);
SegCachePrefixArray pArray = m_prefixes;
while (pos + 1 < m_prefixLength)
{

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

@ -36,7 +36,7 @@ of the License or (at your option) any later version.
#include "inc/Slot.h"
#include "inc/Main.h"
#include "inc/CmapCache.h"
#include "inc/Bidi.h"
//#include "inc/Bidi.h"
#include "inc/Collider.h"
#include "graphite2/Segment.h"
@ -68,8 +68,10 @@ Segment::~Segment()
{
for (SlotRope::iterator i = m_slots.begin(); i != m_slots.end(); ++i)
free(*i);
for (AttributeRope::iterator j = m_userAttrs.begin(); j != m_userAttrs.end(); ++j)
free(*j);
for (AttributeRope::iterator i = m_userAttrs.begin(); i != m_userAttrs.end(); ++i)
free(*i);
for (JustifyRope::iterator i = m_justifies.begin(); i != m_justifies.end(); ++i)
free(*i);
delete[] m_charinfo;
}
@ -154,6 +156,12 @@ void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
aSlot->originate(id);
aSlot->before(id);
aSlot->after(id);
// uint8 aBidi = m_silf->aBidi();
// if (aBidi != 0xFF)
// {
// unsigned int bAttr = glyphAttr(gid, aBidi);
// aSlot->setBidiClass((bAttr <= 22) * bAttr);
// }
if (m_last) m_last->next(aSlot);
aSlot->prev(m_last);
m_last = aSlot;
@ -167,6 +175,9 @@ Slot *Segment::newSlot()
{
if (!m_freeSlots)
{
// check that the segment doesn't grow indefinintely
if (m_numGlyphs > m_numCharinfo * MAX_SEG_GROWTH_FACTOR)
return NULL;
int numUser = m_silf->numUser();
#if !defined GRAPHITE2_NTRACING
if (m_face->logger()) ++numUser;
@ -176,9 +187,8 @@ Slot *Segment::newSlot()
if (!newSlots || !newAttrs) return NULL;
for (size_t i = 0; i < m_bufSize; i++)
{
::new (newSlots + i) Slot(newAttrs + i * numUser);
newSlots[i].next(newSlots + i + 1);
newSlots[i].userAttrs(newAttrs + i * numUser);
newSlots[i].setBidiClass(-1);
}
newSlots[m_bufSize - 1].next(NULL);
newSlots[0].next(NULL);
@ -205,7 +215,7 @@ void Segment::freeSlot(Slot *aSlot)
aSlot->removeChild(aSlot->firstChild());
}
// reset the slot incase it is reused
::new (aSlot) Slot;
::new (aSlot) Slot(aSlot->userAttrs());
memset(aSlot->userAttrs(), 0, m_silf->numUser() * sizeof(int16));
// Update generation counter for debug
#if !defined GRAPHITE2_NTRACING
@ -309,6 +319,61 @@ void Segment::splice(size_t offset, size_t length, Slot * const startSlot,
}
#endif // GRAPHITE2_NSEGCACHE
// reverse the slots but keep diacritics in their same position after their bases
void Segment::reverseSlots()
{
m_dir = m_dir ^ 64; // invert the reverse flag
if (m_first == m_last) return; // skip 0 or 1 glyph runs
Slot *t = 0;
Slot *curr = m_first;
Slot *tlast;
Slot *tfirst;
Slot *out = 0;
while (curr && getSlotBidiClass(curr) == 16)
curr = curr->next();
if (!curr) return;
tfirst = curr->prev();
tlast = curr;
while (curr)
{
if (getSlotBidiClass(curr) == 16)
{
Slot *d = curr->next();
while (d && getSlotBidiClass(d) == 16)
d = d->next();
d = d ? d->prev() : m_last;
Slot *p = out->next(); // one after the diacritics. out can't be null
if (p)
p->prev(d);
else
tlast = d;
t = d->next();
d->next(p);
curr->prev(out);
out->next(curr);
}
else // will always fire first time round the loop
{
if (out)
out->prev(curr);
t = curr->next();
curr->next(out);
out = curr;
}
curr = t;
}
out->prev(tfirst);
if (tfirst)
tfirst->next(out);
else
m_first = out;
m_last = tlast;
}
void Segment::linkClusters(Slot *s, Slot * end)
{
end = end->next();
@ -338,7 +403,7 @@ void Segment::linkClusters(Slot *s, Slot * end)
}
}
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isFinal)
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bool isRtl, bool isFinal)
{
Position currpos(0., 0.);
float clusterMin = 0.;
@ -347,12 +412,12 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo
if (!iStart) iStart = m_first;
if (!iEnd) iEnd = m_last;
if (m_dir & 1)
if (isRtl)
{
for (Slot * s = iEnd, * const end = iStart->prev(); s && s != end; s = s->prev())
{
if (s->isBase())
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal);
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
else
@ -360,7 +425,7 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd, bo
for (Slot * s = iStart, * const end = iEnd->next(); s && s != end; s = s->next())
{
if (s->isBase())
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isFinal);
currpos = s->finalise(this, font, currpos, bbox, 0, clusterMin = currpos.x, isRtl, isFinal);
}
}
return currpos;
@ -437,12 +502,13 @@ bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NU
return true;
}
#if 0
Slot *process_bidi(Slot *start, int level, int prelevel, int &nextLevel, int dirover, int isol, int &cisol, int &isolerr, int &embederr, int init, Segment *seg, uint8 aMirror, BracketPairStack &stack);
void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror);
void resolveWhitespace(int baseLevel, Slot *s);
Slot *resolveOrder(Slot * & s, const bool reordered, const int level = 0);
void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
void Segment::bidiPass(int paradir, uint8 aMirror)
{
if (slotCount() == 0)
return;
@ -453,11 +519,8 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
unsigned int ssize = 0;
for (s = first(); s; s = s->next())
{
if (s->getBidiClass() == -1)
{
unsigned int bAttr = glyphAttr(s->gid(), aBidi);
s->setBidiClass((bAttr <= 22) * bAttr);
}
if (getSlotBidiClass(s) < 0)
s->setBidiClass(0);
bmask |= (1 << s->getBidiClass());
s->setBidiLevel(baseLevel);
if (s->getBidiClass() == 21)
@ -489,6 +552,18 @@ void Segment::bidiPass(uint8 aBidi, int paradir, uint8 aMirror)
}
}
}
#endif
void Segment::doMirror(uint16 aMirror)
{
Slot * s;
for (s = m_first; s; s = s->next())
{
unsigned short g = glyphAttr(s->gid(), aMirror);
if (g && (!(dir() & 4) || !glyphAttr(s->gid(), aMirror + 1)))
s->setGlyph(this, g);
}
}
bool Segment::initCollisions()
{

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

@ -51,6 +51,7 @@ Silf::Silf() throw()
m_jPass(0),
m_bPass(0),
m_flags(0),
m_dir(0),
m_aPseudo(0),
m_aBreak(0),
m_aUser(0),
@ -58,6 +59,7 @@ Silf::Silf() throw()
m_aMirror(0),
m_aPassBits(0),
m_iMaxComp(0),
m_aCollision(0),
m_aLig(0),
m_numPseudo(0),
m_nClass(0),
@ -141,10 +143,10 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
}
if (e.test(p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end, E_BADENDJUSTS)) { releaseBuffers(); return face.error(e); }
m_aLig = be::read<uint16>(p);
m_aUser = be::read<uint8>(p);
m_iMaxComp = be::read<uint8>(p);
be::skip<byte>(p); // direction
m_aLig = be::read<uint16>(p);
m_aUser = be::read<uint8>(p);
m_iMaxComp = be::read<uint8>(p);
m_dir = be::read<uint8>(p) - 1;
m_aCollision = be::read<uint8>(p);
be::skip<byte>(p,3);
be::skip<uint16>(p, be::read<uint8>(p)); // don't need critical features yet
@ -198,7 +200,9 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face,
const byte * const pass_start = silf_start + be::read<uint32>(o_passes),
* const pass_end = silf_start + be::peek<uint32>(o_passes);
face.error_context((face.error_context() & 0xFF00) + EC_ASILF + (i << 16));
if (e.test(pass_start > pass_end, E_BADPASSSTART) || e.test(pass_end > silf_end, E_BADPASSEND)) {
if (e.test(pass_start > pass_end, E_BADPASSSTART)
|| e.test(pass_start < passes_start, E_BADPASSSTART)
|| e.test(pass_end > silf_end, E_BADPASSEND)) {
releaseBuffers(); return face.error(e);
}
@ -268,6 +272,9 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error
if (max_off == ERROROFFSET) return ERROROFFSET;
if (e.test((int)max_off < m_nLinear + (m_nClass - m_nLinear) * 6, E_CLASSESTOOBIG))
return ERROROFFSET;
// Check the linear offsets are sane, these must be monotonically increasing.
for (const uint32 *o = m_classOffsets, * const o_end = o + m_nLinear; o != o_end; ++o)
if (e.test(o[0] > o[1], E_BADCLASSOFFSET))
@ -283,10 +290,10 @@ size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error
for (const uint32 *o = m_classOffsets + m_nLinear, * const o_end = m_classOffsets + m_nClass; o != o_end; ++o)
{
const uint16 * lookup = m_classData + *o;
if (e.test(*o > max_off - 4, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off
if (e.test(*o + 4 > max_off, E_HIGHCLASSOFFSET) // LookupClass doesn't stretch over max_off
|| e.test(lookup[0] == 0 // A LookupClass with no looks is a suspicious thing ...
|| lookup[0] > (max_off - *o - 4)/2 // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
|| lookup[3] != lookup[0] - lookup[1], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange
|| lookup[0] * 2 + *o + 4 > max_off // numIDs lookup pairs fits within (start of LookupClass' lookups array, max_off]
|| lookup[3] + lookup[1] != lookup[0], E_BADCLASSLOOKUPINFO)) // rangeShift: numIDs - searchRange
return ERROROFFSET;
}
@ -307,7 +314,7 @@ uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
const uint16 * cls = m_classData + m_classOffsets[cid];
if (cid < m_nLinear) // output class being used for input, shouldn't happen
{
for (unsigned int i = 0, n = m_classOffsets[cid + 1]; i < n; ++i, ++cls)
for (unsigned int i = 0, n = m_classOffsets[cid + 1] - m_classOffsets[cid]; i < n; ++i, ++cls)
if (*cls == gid) return i;
return -1;
}
@ -348,7 +355,7 @@ uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
{
assert(seg != 0);
SlotMap map(*seg);
SlotMap map(*seg, m_dir);
FiniteStateMachine fsm(map, seg->getFace()->logger());
vm::Machine m(map);
unsigned int initSize = seg->slotCount();
@ -363,7 +370,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
return true;
lastPass = m_numPasses;
}
if (firstPass <= lbidi && lastPass >= lbidi && dobidi)
if ((firstPass < lbidi || (dobidi && firstPass == lbidi)) && (lastPass >= lbidi || (dobidi && lastPass + 1 == lbidi)))
lastPass++;
else
lbidi = 0xFF;
@ -379,7 +386,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
*dbgout << json::item << json::object
<< "id" << -1
<< "slots" << json::array;
seg->positionSlots(0);
seg->positionSlots(0, 0, 0, m_dir);
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close
@ -387,22 +394,13 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
<< json::close;
}
#endif
if (!(seg->dir() & 2))
seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
else if (m_aMirror && (seg->dir() & 1))
{
Slot * s;
for (s = seg->first(); s; s = s->next())
{
unsigned short g = seg->glyphAttr(s->gid(), m_aMirror);
if (g && (!(seg->dir() & 4) || !seg->glyphAttr(s->gid(), m_aMirror + 1)))
s->setGlyph(seg, g);
}
}
if (seg->currdir() != m_dir)
seg->reverseSlots();
if (m_aMirror && (seg->dir() & 3) == 3)
seg->doMirror(m_aMirror);
--i;
lbidi = lastPass;
--lastPass;
lbidi = 0xFF;
continue;
}
@ -412,7 +410,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
*dbgout << json::item << json::object
<< "id" << i+1
<< "slots" << json::array;
seg->positionSlots(0);
seg->positionSlots(0, 0, 0, m_dir);
for(Slot * s = seg->first(); s; s = s->next())
*dbgout << dslot(seg, s);
*dbgout << json::close;
@ -420,13 +418,13 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi
#endif
// test whether to reorder, prepare for positioning
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || (m_passes[i].flags() & 7))
&& !m_passes[i].runGraphite(m, fsm))
bool reverse = (lbidi == 0xFF) && (seg->currdir() != ((m_dir & 1) ^ m_passes[i].reverseDir()));
if ((i >= 32 || (seg->passBits() & (1 << i)) == 0 || m_passes[i].collisionLoops())
&& !m_passes[i].runGraphite(m, fsm, reverse))
return false;
// only subsitution passes can change segment length, cached subsegments are short for their text
if (m.status() != vm::Machine::finished
|| (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
|| (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
|| (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))
return false;
}
return true;

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

@ -34,15 +34,14 @@ of the License or (at your option) any later version.
using namespace graphite2;
Slot::Slot() :
Slot::Slot(int16 *user_attrs) :
m_next(NULL), m_prev(NULL),
m_glyphid(0), m_realglyphid(0), m_original(0), m_before(0), m_after(0),
m_index(0), m_parent(NULL), m_child(NULL), m_sibling(NULL),
m_position(0, 0), m_shift(0, 0), m_advance(0, 0),
m_attach(0, 0), m_with(0, 0), m_just(0.),
m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0), m_justs(NULL)
// Do not set m_userAttr since it is set *before* new is called since this
// is used as a positional new to reset the GrSlot
m_flags(0), m_attLevel(0), m_bidiCls(-1), m_bidiLevel(0),
m_userAttr(user_attrs), m_justs(NULL)
{
}
@ -86,17 +85,17 @@ void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
m_position = m_position + relpos;
}
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal)
Position Slot::finalise(const Segment *seg, const Font *font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal)
{
SlotCollision *coll = NULL;
if (attrLevel && m_attLevel > attrLevel) return Position(0, 0);
float scale = font ? font->scale() : 1.0f;
Position shift(m_shift.x * ((seg->dir() & 1) * -2 + 1) + m_just, m_shift.y);
Position shift(m_shift.x * (rtl * -2 + 1) + m_just, m_shift.y);
float tAdvance = m_advance.x + m_just;
if (isFinal && (coll = seg->collisionInfo(this)))
{
const Position &collshift = coll->offset();
if (!(coll->flags() & SlotCollision::COLL_KERN) || (seg->dir() & 1))
if (!(coll->flags() & SlotCollision::COLL_KERN) || rtl)
shift = shift + collshift;
}
const GlyphFace * glyphFace = seg->getFace()->glyphs().glyphSafe(glyph());
@ -134,13 +133,13 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R
if (m_child && m_child != this && m_child->attachedTo() == this)
{
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, isFinal);
Position tRes = m_child->finalise(seg, font, m_position, bbox, attrLevel, clusterMin, rtl, isFinal);
if ((!m_parent || m_advance.x >= 0.5f) && tRes.x > res.x) res = tRes;
}
if (m_parent && m_sibling && m_sibling != this && m_sibling->attachedTo() == m_parent)
{
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, isFinal);
Position tRes = m_sibling->finalise(seg, font, base, bbox, attrLevel, clusterMin, rtl, isFinal);
if (tRes.x > res.x) res = tRes;
}
@ -154,12 +153,14 @@ Position Slot::finalise(const Segment *seg, const Font *font, Position & base, R
return res;
}
int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel, bool rtl)
{
Position base;
if (glyph() >= seg->getFace()->glyphs().numGlyphs())
return 0;
Rect bbox = seg->theGlyphBBoxTemporary(glyph());
float clusterMin = 0.;
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, false);
Position res = finalise(seg, NULL, base, bbox, attrLevel, clusterMin, rtl, false);
switch (metrics(metric))
{
@ -192,7 +193,6 @@ int32 Slot::clusterMetric(const Segment *seg, uint8 metric, uint8 attrLevel)
int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
{
if (!this) return 0;
if (ind == gr_slatUserDefnV1)
{
ind = gr_slatUserDefn;
@ -220,9 +220,7 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
case gr_slatAttLevel : return m_attLevel;
case gr_slatBreak : return seg->charinfo(m_original)->breakWeight();
case gr_slatCompRef : return 0;
case gr_slatDir : if (m_bidiCls == -1)
const_cast<Slot *>(this)->setBidiClass(int8(seg->glyphAttr(gid(), seg->silf()->aBidi())));
return m_bidiCls;
case gr_slatDir : return seg->dir() & 1;
case gr_slatInsert : return isInsertBefore();
case gr_slatPosX : return int(m_position.x); // but need to calculate it
case gr_slatPosY : return int(m_position.y);
@ -272,7 +270,6 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, const SlotMap & map)
{
if (!this) return;
if (ind == gr_slatUserDefnV1)
{
ind = gr_slatUserDefn;
@ -299,7 +296,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
if (!other->isChildOf(this) && other->child(this))
{
attachTo(other);
if (((seg->dir() & 1) != 0) ^ (idx > subindex))
if ((map.dir() != 0) ^ (idx > subindex))
m_with = Position(advance(), 0);
else // normal match to previous root
m_attach = Position(other->advance(), 0);
@ -322,7 +319,7 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
seg->charinfo(m_original)->breakWeight(value);
break;
case gr_slatCompRef : break; // not sure what to do here
case gr_slatDir : m_bidiCls = int8(value); break;
case gr_slatDir : break;
case gr_slatInsert :
markInsertBefore(value? true : false);
break;
@ -450,6 +447,7 @@ bool Slot::removeSibling(Slot *ap)
void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
{
m_glyphid = glyphid;
m_bidiCls = -1;
if (!theGlyph)
{
theGlyph = seg->getFace()->glyphs().glyphSafe(glyphid);
@ -461,6 +459,8 @@ void Slot::setGlyph(Segment *seg, uint16 glyphid, const GlyphFace * theGlyph)
}
}
m_realglyphid = theGlyph->attrs()[seg->silf()->aPseudo()];
if (m_realglyphid > seg->getFace()->glyphs().numGlyphs())
m_realglyphid = 0;
const GlyphFace *aGlyph = theGlyph;
if (m_realglyphid)
{

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

@ -30,7 +30,7 @@ of the License or (at your option) any later version.
using namespace graphite2;
sparse::chunk sparse::empty_chunk = {0,0};
const sparse::chunk sparse::empty_chunk = {0,0};
sparse::~sparse() throw()
{

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

@ -62,8 +62,10 @@ Description
***********************************************************************************************/
namespace
{
#ifdef ALL_TTFUTILS
// max number of components allowed in composite glyphs
const int kMaxGlyphComponents = 8;
#endif
template <int R, typename T>
inline float fixed_to_float(const T f) {
@ -227,7 +229,7 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
using namespace Sfnt;
if (pTable == 0) return false;
if (pTable == 0 || lTableSize < 4) return false;
switch(TableId)
{
@ -235,6 +237,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::CharacterCodeMap * const pCmap
= reinterpret_cast<const Sfnt::CharacterCodeMap *>(pTable);
if (lTableSize < sizeof(Sfnt::CharacterCodeMap))
return false;
return be::swap(pCmap->version) == 0;
}
@ -242,6 +246,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::FontHeader * const pHead
= reinterpret_cast<const Sfnt::FontHeader *>(pTable);
if (lTableSize < sizeof(Sfnt::FontHeader))
return false;
bool r = be::swap(pHead->version) == OneFix
&& be::swap(pHead->magic_number) == FontHeader::MagicNumber
&& be::swap(pHead->glyph_data_format)
@ -258,6 +264,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::PostScriptGlyphName * const pPost
= reinterpret_cast<const Sfnt::PostScriptGlyphName *>(pTable);
if (lTableSize < sizeof(Sfnt::PostScriptGlyphName))
return false;
const fixed format = be::swap(pPost->format);
bool r = format == PostScriptGlyphName::Format1
|| format == PostScriptGlyphName::Format2
@ -270,6 +278,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::HorizontalHeader * pHhea =
reinterpret_cast<const Sfnt::HorizontalHeader *>(pTable);
if (lTableSize < sizeof(Sfnt::HorizontalHeader))
return false;
bool r = be::swap(pHhea->version) == OneFix
&& be::swap(pHhea->metric_data_format) == 0
&& sizeof (Sfnt::HorizontalHeader) <= lTableSize;
@ -280,6 +290,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::MaximumProfile * pMaxp =
reinterpret_cast<const Sfnt::MaximumProfile *>(pTable);
if (lTableSize < sizeof(Sfnt::MaximumProfile))
return false;
bool r = be::swap(pMaxp->version) == OneFix
&& sizeof(Sfnt::MaximumProfile) <= lTableSize;
return r;
@ -324,6 +336,8 @@ bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize)
{
const Sfnt::FontNames * pName
= reinterpret_cast<const Sfnt::FontNames *>(pTable);
if (lTableSize < sizeof(Sfnt::FontNames))
return false;
return be::swap(pName->format) == 0;
}
@ -796,7 +810,7 @@ bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void
size_t cLongHorMetrics = be::swap(phhea->num_long_hor_metrics);
if (nGlyphId < cLongHorMetrics)
{ // glyph id is acceptable
if (nGlyphId * sizeof(Sfnt::HorizontalMetric) >= lHmtxSize) return false;
if ((nGlyphId + 1) * sizeof(Sfnt::HorizontalMetric) > lHmtxSize) return false;
nAdvWid = be::swap(phmtx[nGlyphId].advance_width);
nLsb = be::swap(phmtx[nGlyphId].left_side_bearing);
}
@ -806,7 +820,7 @@ bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize, const void
size_t lLsbOffset = sizeof(Sfnt::HorizontalMetric) * cLongHorMetrics +
sizeof(int16) * (nGlyphId - cLongHorMetrics); // offset in bytes
// We test like this as LsbOffset is an offset not a length.
if (lLsbOffset > lHmtxSize - sizeof(int16))
if (lLsbOffset >= lHmtxSize - sizeof(int16) || cLongHorMetrics == 0)
{
nLsb = 0;
return false;
@ -873,7 +887,7 @@ const void * FindCmapSubtable(const void * pCmap, int nPlatformId, /* =3 */ int
/*----------------------------------------------------------------------------------------------
Check the Microsoft Unicode subtable for expected values
----------------------------------------------------------------------------------------------*/
bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
bool CheckCmapSubtable4(const void * pCmapSubtable4, size_t table_len /*, unsigned int maxgid*/)
{
if (!pCmapSubtable4) return false;
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable4);
@ -882,6 +896,8 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
if (be::swap(pTable->format) != 4) return false;
const Sfnt::CmapSubTableFormat4 * pTable4 = reinterpret_cast<const Sfnt::CmapSubTableFormat4 *>(pCmapSubtable4);
uint16 length = be::swap(pTable4->length);
if (length > table_len)
return false;
if (length < sizeof(Sfnt::CmapSubTableFormat4))
return false;
uint16 nRanges = be::swap(pTable4->seg_count_x2) >> 1;
@ -919,7 +935,7 @@ bool CheckCmapSubtable4(const void * pCmapSubtable4 /*, unsigned int maxgid*/)
lastend = end;
}
#endif
return true;;
return true;
}
/*----------------------------------------------------------------------------------------------
@ -1062,7 +1078,7 @@ unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnico
/*----------------------------------------------------------------------------------------------
Check the Microsoft UCS-4 subtable for expected values.
----------------------------------------------------------------------------------------------*/
bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/)
bool CheckCmapSubtable12(const void *pCmapSubtable12, size_t table_len /*, unsigned int maxgid*/)
{
if (!pCmapSubtable12) return false;
const Sfnt::CmapSubTable * pTable = reinterpret_cast<const Sfnt::CmapSubTable *>(pCmapSubtable12);
@ -1070,6 +1086,8 @@ bool CheckCmapSubtable12(const void *pCmapSubtable12 /*, unsigned int maxgid*/)
return false;
const Sfnt::CmapSubTableFormat12 * pTable12 = reinterpret_cast<const Sfnt::CmapSubTableFormat12 *>(pCmapSubtable12);
uint32 length = be::swap(pTable12->length);
if (length > table_len)
return false;
if (length < sizeof(Sfnt::CmapSubTableFormat12))
return false;
uint32 num_groups = be::swap(pTable12->num_groups);
@ -1221,7 +1239,7 @@ size_t LocaLookup(gid16 nGlyphId,
void * GlyfLookup(const void * pGlyf, size_t nGlyfOffset, size_t nTableLen)
{
const uint8 * pByte = reinterpret_cast<const uint8 *>(pGlyf);
if (nGlyfOffset == size_t(-1) || nGlyfOffset == size_t(-2) || nGlyfOffset >= nTableLen)
if (nGlyfOffset + pByte < pByte || nGlyfOffset + sizeof(Sfnt::Glyph) >= nTableLen)
return NULL;
return const_cast<uint8 *>(pByte + nGlyfOffset);
}
@ -1833,7 +1851,6 @@ bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca
This range is parallel to the prgnX & prgnY
Return true if successful, false otherwise. On false, all points may be INT_MIN
False may indicate a white space glyph, a multi-level composite, or a corrupt font
// TODO: doesn't support composite glyphs whose components are themselves components
It's not clear from the TTF spec when the transforms should be applied. Should the
transform be done before or after attachment point calcs? (current code - before)
Should the transform be applied to other offsets? (currently - no; however commented

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

@ -70,6 +70,7 @@ struct regbank {
SlotMap & smap;
slotref * const map_base;
const instr * & ip;
uint8 direction;
int8 flags;
};
@ -86,6 +87,7 @@ namespace {
#define map reg.map
#define mapb reg.map_base
#define flags reg.flags
#define dir reg.direction
#include "inc/opcodes.h"
@ -96,6 +98,7 @@ namespace {
#undef map
#undef mapb
#undef flags
#undef dir
}
Machine::stack_t Machine::run(const instr * program,
@ -110,7 +113,7 @@ Machine::stack_t Machine::run(const instr * program,
const byte * dp = data;
stack_t * sp = _stack + Machine::STACK_GUARD,
* const sb = sp;
regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, 0};
regbank reg = {*map, map, _map, _map.begin()+_map.context(), ip, _map.dir(), 0};
// Run the program
while ((reinterpret_cast<ip_t>(*++ip))(dp, sp, sb, reg)) {}

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

@ -61,6 +61,7 @@ const void * direct_run(const bool get_table_mode,
const byte * data,
Machine::stack_t * stack,
slotref * & __map,
uint8 _dir,
SlotMap * __smap=0)
{
// We need to define and return to opcode table from within this function
@ -79,6 +80,7 @@ const void * direct_run(const bool get_table_mode,
slotref is = *__map,
* map = __map,
* const mapb = smap.begin()+smap.context();
uint8 dir = _dir;
int8 flags = 0;
// start the program
@ -109,7 +111,7 @@ Machine::stack_t Machine::run(const instr * program,
assert(program != 0);
const stack_t *sp = static_cast<const stack_t *>(
direct_run(false, program, data, _stack, is, &_map));
direct_run(false, program, data, _stack, is, _map.dir(), &_map));
const stack_t ret = sp == _stack+STACK_GUARD+1 ? *sp-- : 0;
check_final_stack(sp);
return ret;

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

@ -47,7 +47,6 @@ $(_NS)_SOURCES = \
$($(_NS)_BASE)/src/gr_segment.cpp \
$($(_NS)_BASE)/src/gr_slot.cpp \
$($(_NS)_BASE)/src/json.cpp \
$($(_NS)_BASE)/src/Bidi.cpp \
$($(_NS)_BASE)/src/CachedFace.cpp \
$($(_NS)_BASE)/src/CmapCache.cpp \
$($(_NS)_BASE)/src/Code.cpp \
@ -78,13 +77,12 @@ $(_NS)_PRIVATE_HEADERS = \
$($(_NS)_BASE)/src/inc/bits.h \
$($(_NS)_BASE)/src/inc/debug.h \
$($(_NS)_BASE)/src/inc/json.h \
$($(_NS)_BASE)/src/inc/locale2lcid.h \
$($(_NS)_BASE)/src/inc/Bidi.h \
$($(_NS)_BASE)/src/inc/CachedFace.h \
$($(_NS)_BASE)/src/inc/CharInfo.h \
$($(_NS)_BASE)/src/inc/CmapCache.h \
$($(_NS)_BASE)/src/inc/Code.h \
$($(_NS)_BASE)/src/inc/Collider.h \
$($(_NS)_BASE)/src/inc/Compression.h \
$($(_NS)_BASE)/src/inc/Decompressor.h \
$($(_NS)_BASE)/src/inc/Endian.h \
$($(_NS)_BASE)/src/inc/Error.h \
@ -110,7 +108,6 @@ $(_NS)_PRIVATE_HEADERS = \
$($(_NS)_BASE)/src/inc/SegCacheEntry.h \
$($(_NS)_BASE)/src/inc/SegCacheStore.h \
$($(_NS)_BASE)/src/inc/Segment.h \
$($(_NS)_BASE)/src/inc/Shrinker.h \
$($(_NS)_BASE)/src/inc/Silf.h \
$($(_NS)_BASE)/src/inc/Slot.h \
$($(_NS)_BASE)/src/inc/Sparse.h \

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

@ -48,7 +48,7 @@ namespace
delete pRes;
return NULL;
}
pRes->finalise(font);
pRes->finalise(font, true);
return static_cast<gr_segment*>(pRes);
}

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

@ -69,7 +69,6 @@ public:
};
private:
static byte * local_memory;
class decoder;
instr * _code;
@ -87,22 +86,24 @@ private:
void failure(const status_t) throw();
public:
static size_t estimateCodeDataOut(size_t num_bytecodes);
Code() throw();
Code(bool is_constraint, const byte * bytecode_begin, const byte * const bytecode_end,
uint8 pre_context, uint16 rule_length, const Silf &, const Face &,
enum passtype pt, byte * & _out = local_memory);
enum passtype pt, byte * * const _out = 0);
Code(const Machine::Code &) throw();
~Code() throw();
Code & operator=(const Code &rhs) throw();
operator bool () const throw();
status_t status() const throw();
bool constraint() const throw();
size_t dataSize() const throw();
size_t instructionCount() const throw();
bool immutable() const throw();
bool deletes() const throw();
size_t maxRef() const throw();
operator bool () const throw() { return _code && status() == loaded; }
status_t status() const throw() { return _status; }
bool constraint() const throw() { return _constraint; }
size_t dataSize() const throw() { return _data_size; }
size_t instructionCount() const throw() { return _instr_count; }
bool immutable() const throw() { return !(_delete || _modify); }
bool deletes() const throw() { return _delete; }
size_t maxRef() const throw() { return _max_ref; }
void externalProgramMoved(ptrdiff_t) throw();
int32 run(Machine &m, slotref * & map) const;
@ -110,10 +111,16 @@ public:
CLASS_NEW_DELETE;
};
inline
size_t Machine::Code::estimateCodeDataOut(size_t n_bc)
{
return n_bc * (sizeof(instr)+sizeof(byte));
}
inline Machine::Code::Code() throw()
: _code(0), _data(0), _data_size(0), _instr_count(0), _max_ref(0),
_status(loaded), _constraint(false), _modify(false),_delete(false),
_status(loaded), _constraint(false), _modify(false), _delete(false),
_own(false)
{
}
@ -149,41 +156,6 @@ inline Machine::Code & Machine::Code::operator=(const Machine::Code &rhs) throw(
return *this;
}
inline Machine::Code::operator bool () const throw () {
return _code && status() == loaded;
}
inline Machine::Code::status_t Machine::Code::status() const throw() {
return _status;
}
inline bool Machine::Code::constraint() const throw() {
return _constraint;
}
inline size_t Machine::Code::dataSize() const throw() {
return _data_size;
}
inline size_t Machine::Code::instructionCount() const throw() {
return _instr_count;
}
inline bool Machine::Code::immutable() const throw()
{
return !(_delete || _modify);
}
inline bool Machine::Code::deletes() const throw()
{
return _delete;
}
inline size_t Machine::Code::maxRef() const throw()
{
return _max_ref;
}
inline void Machine::Code::externalProgramMoved(ptrdiff_t dist) throw()
{
if (_code && !_own)

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

@ -28,7 +28,7 @@ of the License or (at your option) any later version.
#include <utility>
#include "inc/List.h"
#include "inc/Slot.h"
//#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/Intervals.h"
#include "inc/debug.h"
@ -118,8 +118,8 @@ private:
}; // end of class SlotColllision
class BBox;
class SlantBox;
struct BBox;
struct SlantBox;
class ShiftCollider
{
@ -128,13 +128,7 @@ public:
typedef Vector<fpair> vfpairs;
typedef vfpairs::iterator ivfpairs;
ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
{
#if !defined GRAPHITE2_NTRACING
for (int i = 0; i < 4; ++i)
_ranges[i].setdebug(dbgout);
#endif
}
ShiftCollider(json *dbgout);
~ShiftCollider() throw() { };
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint,
@ -176,10 +170,25 @@ protected:
}; // end of class ShiftCollider
inline
ShiftCollider::ShiftCollider(GR_MAYBE_UNUSED json *dbgout)
: _target(0),
_margin(0.0),
_marginWt(0.0),
_seqClass(0),
_seqProxClass(0),
_seqOrder(0)
{
#if !defined GRAPHITE2_NTRACING
for (int i = 0; i < 4; ++i)
_ranges[i].setdebug(dbgout);
#endif
}
class KernCollider
{
public:
KernCollider(GR_MAYBE_UNUSED json *dbg) : _miny(-1e38f), _maxy(1e38f) { };
KernCollider(json *dbg);
~KernCollider() throw() { };
bool initSlot(Segment *seg, Slot *aSlot, const Rect &constraint, float margin,
const Position &currShift, const Position &offsetPrev, int dir,
@ -213,8 +222,24 @@ private:
inline
float sqr(float x) { return x * x; }
float sqr(float x) {
return x * x;
}
inline
KernCollider::KernCollider(GR_MAYBE_UNUSED json *dbg)
: _target(0),
_margin(0.0f),
_miny(-1e38f),
_maxy(1e38f),
_sliceWidth(0.0f),
_mingap(0.0f),
_xbound(0.0)
{
#if !defined GRAPHITE2_NTRACING
_seg = 0;
#endif
};
}; // end of namespace graphite2

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

@ -0,0 +1,120 @@
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cassert>
#include <cstddef>
#include <cstring>
#include <iterator>
#if ((defined GCC_VERSION && GCC_VERSION >= 302) || (defined __INTEL_COMPILER && __INTEL_COMPILER >= 800) || defined(__clang__))
#define expect(expr,value) (__builtin_expect ((expr),(value)) )
#else
#define expect(expr,value) (expr)
#endif
#define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0)
namespace
{
#if defined(_MSC_VER)
typedef unsigned __int8 u8;
typedef unsigned __int16 u16;
typedef unsigned __int32 u32;
typedef unsigned __int64 u64;
#else
#include <stdint.h>
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#endif
ptrdiff_t const MINMATCH = 4;
template<int S>
inline
void unaligned_copy(void * d, void const * s) {
::memcpy(d, s, S);
}
inline
size_t align(size_t p) {
return (p + sizeof(unsigned long)-1) & ~(sizeof(unsigned long)-1);
}
inline
u8 * overrun_copy(u8 * d, u8 const * s, size_t n) {
size_t const WS = sizeof(unsigned long);
u8 const * e = s + n;
do
{
unaligned_copy<WS>(d, s);
d += WS;
s += WS;
}
while (s < e);
d-=(s-e);
return d;
}
inline
u8 * fast_copy(u8 * d, u8 const * s, size_t n) {
size_t const WS = sizeof(unsigned long);
size_t wn = n/WS;
while (wn--)
{
unaligned_copy<WS>(d, s);
d += WS;
s += WS;
}
n &= WS-1;
while (n--) {*d++ = *s++; }
return d;
}
inline
u8 * copy(u8 * d, u8 const * s, size_t n) {
if (likely(d>s+sizeof(unsigned long)))
return overrun_copy(d,s,n);
else
while (n--) *d++ = *s++;
return d;
}
} // end of anonymous namespace

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

@ -1,51 +1,39 @@
/* Copyright (c) 2012, Siyuan Fu <fusiyuan2010@gmail.com>
Copyright (c) 2015, SIL International
/* GRAPHITE2 LICENSING
Copyright 2015, SIL International
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
This library is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should also have received a copy of the GNU Lesser General Public
License along with this library in the file named "LICENSE".
If not, write to the Free Software Foundation, 51 Franklin Street,
Suite 500, Boston, MA 02110-1335, USA or visit their web page on the
internet at http://www.fsf.org/licenses/lgpl.html.
Alternatively, the contents of this file may be used under the terms of the
Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public
License, as published by the Free Software Foundation, either version 2
of the License or (at your option) any later version.
*/
#pragma once
#include <cstddef>
namespace shrinker
namespace lz4
{
// return value is either decompressed size of -1
int decompress(void const *in, size_t in_size, void *out, size_t out_size);
/*
in: inbuf --- compressed data
out: outbuf --- decompressed data to place in
size: decompressed(original) data size should be
return value:
positive integer means decompress success and it's the sizeof decompressed data,
which should be equal to size.
or -1 means decompress failed
*/
} // end of namespace shrinker

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

@ -43,6 +43,7 @@ class FileFace;
class GlyphCache;
class NameTable;
class json;
class Font;
using TtfUtil::Tag;
@ -174,6 +175,8 @@ class Face::Table
Error decompress();
void releaseBuffers();
public:
Table() throw();
Table(const Face & face, const Tag n, uint32 version=0xffffffff) throw();
@ -202,10 +205,7 @@ Face::Table::Table(const Table & rhs) throw()
inline
Face::Table::~Table() throw()
{
if (_compressed)
free(const_cast<byte *>(_p));
else if (_p && _f->m_ops.release_table)
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
releaseBuffers();
}
inline

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

@ -56,7 +56,7 @@ class FeatureRef
static const uint8 SIZEOF_CHUNK = sizeof(chunk_t)*8;
public:
FeatureRef() : m_nameValues(0) {}
FeatureRef();
FeatureRef(const Face & face, unsigned short & bits_offset, uint32 max_val,
uint32 name, uint16 uiName, uint16 flags,
FeatureSetting *settings, uint16 num_set) throw();
@ -99,6 +99,16 @@ private: //unimplemented
};
inline
FeatureRef::FeatureRef()
: m_pFace(0), m_nameValues(0),
m_mask(0), m_max(0), m_id(0),
m_nameid(0), m_flags(0), m_numSet(0),
m_bits(0), m_index(0)
{
}
class NameAndFeatureRef
{
public:

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

@ -39,10 +39,11 @@ class FeatureVal;
class Segment;
class SlantBox
struct SlantBox
{
public:
SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
static const SlantBox empty;
// SlantBox(float psi = 0., float pdi = 0., float psa = 0., float pda = 0.) : si(psi), di(pdi), sa(psa), da(pda) {};
float width() const { return sa - si; }
float height() const { return da - di; }
float si; // min
@ -51,11 +52,9 @@ public:
float da; // max
};
static SlantBox nullSlant(0, 0, 0, 0);
class BBox
struct BBox
{
public:
BBox(float pxi = 0, float pyi = 0., float pxa = 0., float pya = 0.) : xi(pxi), yi(pyi), xa(pxa), ya(pya) {};
float width() const { return xa - xi; }
float height() const { return ya - yi; }
@ -65,7 +64,6 @@ public:
float ya; // max
};
static BBox nullBBox(0, 0, 0, 0);
class GlyphBox
{
@ -95,8 +93,6 @@ class GlyphCache
GlyphCache(const GlyphCache&);
GlyphCache& operator=(const GlyphCache&);
static const Rect nullRect;
public:
GlyphCache(const Face & face, const uint32 face_options);
~GlyphCache();
@ -110,7 +106,7 @@ public:
float getBoundingMetric(unsigned short glyphid, uint8 metric) const;
uint8 numSubBounds(unsigned short glyphid) const;
float getSubBoundingMetric(unsigned short glyphid, uint8 subindex, uint8 metric) const;
const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : nullRect; }
const Rect & slant(unsigned short glyphid) const { return _boxes[glyphid] ? _boxes[glyphid]->slant() : _empty_slant_box; }
const SlantBox & getBoundingSlantBox(unsigned short glyphid) const;
const BBox & getBoundingBBox(unsigned short glyphid) const;
const SlantBox & getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const;
@ -120,6 +116,7 @@ public:
CLASS_NEW_DELETE;
private:
const Rect _empty_slant_box;
const Loader * _glyph_loader;
const GlyphFace * * _glyphs;
GlyphBox * * _boxes;
@ -149,7 +146,7 @@ unsigned short GlyphCache::unitsPerEm() const throw()
inline
bool GlyphCache::check(unsigned short glyphid) const
{
return glyphid < _num_glyphs;
return _boxes && glyphid < _num_glyphs;
}
inline
@ -177,7 +174,7 @@ float GlyphCache::getBoundingMetric(unsigned short glyphid, uint8 metric) const
inline const SlantBox &GlyphCache::getBoundingSlantBox(unsigned short glyphid) const
{
return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : nullSlant;
return _boxes[glyphid] ? *(SlantBox *)(&(_boxes[glyphid]->slant())) : SlantBox::empty;
}
inline const BBox &GlyphCache::getBoundingBBox(unsigned short glyphid) const
@ -207,14 +204,12 @@ float GlyphCache::getSubBoundingMetric(unsigned short glyphid, uint8 subindex, u
inline const SlantBox &GlyphCache::getSubBoundingSlantBox(unsigned short glyphid, uint8 subindex) const
{
GlyphBox *b = _boxes[glyphid];
// if (b == NULL || subindex >= b->num()) return nullSlant;
return *(SlantBox *)(b->subs() + 2 * subindex + 1);
}
inline const BBox &GlyphCache::getSubBoundingBBox(unsigned short glyphid, uint8 subindex) const
{
GlyphBox *b = _boxes[glyphid];
// if (b == NULL || subindex >= b->num()) return nullBBox;
return *(BBox *)(b->subs() + 2 * subindex);
}

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

@ -144,6 +144,9 @@ inline
Zones::Zones()
: _margin_len(0), _margin_weight(0), _pos(0), _posm(0)
{
#if !defined GRAPHITE2_NTRACING
_dbg = 0;
#endif
_exclusions.reserve(8);
}

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

@ -105,6 +105,7 @@ void Vector<T>::reserve(size_t n)
{
const ptrdiff_t sz = size();
m_first = static_cast<T*>(realloc(m_first, n*sizeof(T)));
if (!m_first) std::abort();
m_last = m_first + sz;
m_end = m_first + n;
}

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

@ -85,7 +85,7 @@ template <typename T> T * gralloc(size_t n)
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
return reinterpret_cast<T*>(malloc(sizeof(T) * n));
return static_cast<T*>(malloc(sizeof(T) * n));
}
template <typename T> T * grzeroalloc(size_t n)
@ -93,7 +93,7 @@ template <typename T> T * grzeroalloc(size_t n)
#ifdef GRAPHITE2_TELEMETRY
telemetry::count_bytes(sizeof(T) * n);
#endif
return reinterpret_cast<T*>(calloc(n, sizeof(T)));
return static_cast<T*>(calloc(n, sizeof(T)));
}
template <typename T>
@ -128,5 +128,5 @@ inline T max(const T a, const T b)
#ifdef _MSC_VER
#pragma warning(disable: 4800)
#pragma warning(once: 4355)
#pragma warning(disable: 4355)
#endif

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

@ -53,9 +53,10 @@ public:
bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face,
enum passtype pt, uint32 version, Error &e);
bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const;
bool runGraphite(vm::Machine & m, FiniteStateMachine & fsm, bool reverse) const;
void init(Silf *silf) { m_silf = silf; }
byte flags() const { return m_flags; }
byte collisionLoops() const { return m_numCollRuns; }
bool reverseDir() const { return m_isReverseDir; }
CLASS_NEW_DELETE
private:
@ -73,7 +74,7 @@ private:
uint16 glyphToCol(const uint16 gid) const;
bool runFSM(FiniteStateMachine & fsm, Slot * slot) const;
void dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const;
void dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * os) const;
void dumpRuleEventOutput(const FiniteStateMachine & fsm, vm::Machine & m, const Rule & r, Slot * os) const;
void adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
bool collisionShift(Segment *seg, int dir, json * const dbgout) const;
bool collisionKern(Segment *seg, int dir, json * const dbgout) const;
@ -93,7 +94,8 @@ private:
vm::Machine::Code * m_codes;
byte * m_progs;
byte m_flags;
byte m_numCollRuns;
byte m_kernColls;
byte m_iMaxLoop;
uint16 m_numGlyphs;
uint16 m_numRules;
@ -105,6 +107,7 @@ private:
byte m_minPreCtxt;
byte m_maxPreCtxt;
byte m_colThreshold;
bool m_isReverseDir;
vm::Machine::Code m_cPConstraint;
private: //defensive

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

@ -41,8 +41,8 @@ struct Rule {
uint16 rule_idx;
#endif
Rule() : constraint(0), action(0), sort(0), preContext(0) {}
~Rule();
Rule();
~Rule() {}
CLASS_NEW_DELETE;
@ -51,8 +51,16 @@ private:
Rule & operator = (const Rule &);
};
inline Rule::~Rule()
inline
Rule::Rule()
: constraint(0),
action(0),
sort(0),
preContext(0)
{
#ifndef NDEBUG
rule_idx = 0;
#endif
}
@ -94,7 +102,7 @@ class SlotMap
{
public:
enum {MAX_SLOTS=64};
SlotMap(Segment & seg);
SlotMap(Segment & seg, uint8 direction);
Slot * * begin();
Slot * * end();
@ -105,19 +113,22 @@ public:
Slot * const & operator[](int n) const;
Slot * & operator [] (int);
void pushSlot(Slot * const slot);
void collectGarbage();
void collectGarbage(Slot *& aSlot);
Slot * highwater() { return m_highwater; }
void highwater(Slot *s) { m_highwater = s; m_highpassed = false; }
bool highpassed() const { return m_highpassed; }
void highpassed(bool v) { m_highpassed = v; }
uint8 dir() const { return m_dir; }
Segment & segment;
private:
Slot * m_slot_map[MAX_SLOTS+1];
unsigned short m_size;
unsigned short m_precontext;
Slot * m_highwater;
uint8 m_dir;
bool m_highpassed;
};
@ -231,8 +242,8 @@ void FiniteStateMachine::Rules::accumulate_rules(const State &state)
}
inline
SlotMap::SlotMap(Segment & seg)
: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_highpassed(false)
SlotMap::SlotMap(Segment & seg, uint8 direction)
: segment(seg), m_size(0), m_precontext(0), m_highwater(0), m_dir(direction), m_highpassed(false)
{
m_slot_map[0] = 0;
}

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

@ -263,7 +263,7 @@ private:
unsigned long long minAccessCount, unsigned long long oldAccessTime);
uint16 m_prefixLength;
uint16 m_maxCachedSegLength;
// uint16 m_maxCachedSegLength;
size_t m_segmentCount;
SegCachePrefixArray m_prefixes;
Features m_features;

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

@ -39,7 +39,7 @@ of the License or (at your option) any later version.
#include "inc/Slot.h"
#include "inc/Position.h"
#include "inc/List.h"
#include "inc/Bidi.h"
//#include "inc/Bidi.h"
#include "inc/Collider.h"
#define MAX_SEG_GROWTH_FACTOR 256
@ -48,7 +48,7 @@ namespace graphite2 {
typedef Vector<Features> FeatureList;
typedef Vector<Slot *> SlotRope;
typedef Vector<int16 *> AttributeRope;
typedef Vector<int16 *> AttributeRope;
typedef Vector<SlotJustify *> JustifyRope;
#ifndef GRAPHITE2_NSEGCACHE
@ -101,7 +101,6 @@ public:
unsigned int charInfoCount() const { return m_numCharinfo; }
const CharInfo *charinfo(unsigned int index) const { return index < m_numCharinfo ? m_charinfo + index : NULL; }
CharInfo *charinfo(unsigned int index) { return index < m_numCharinfo ? m_charinfo + index : NULL; }
int8 dir() const { return m_dir; }
Segment(unsigned int numchars, const Face* face, uint32 script, int dir);
~Segment();
@ -124,7 +123,7 @@ public:
void freeSlot(Slot *);
SlotJustify *newJustify();
void freeJustify(SlotJustify *aJustify);
Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isFinal = true);
Position positionSlots(const Font *font=0, Slot *first=0, Slot *last=0, bool isRtl = false, bool isFinal = true);
void associateChars(int offset, int num);
void linkClusters(Slot *first, Slot *last);
uint16 getClassGlyph(uint16 cid, uint16 offset) const { return m_silf->getClassGlyph(cid, offset); }
@ -138,11 +137,13 @@ public:
if (val > pFR->maxVal()) val = pFR->maxVal();
pFR->applyValToFeature(val, m_feats[index]);
} }
int8 dir() const { return m_dir; }
void dir(int8 val) { m_dir = val; }
bool currdir() const { return ((m_dir >> 6) ^ m_dir) & 1; }
unsigned int passBits() const { return m_passBits; }
void mergePassBits(const unsigned int val) { m_passBits &= val; }
int16 glyphAttr(uint16 gid, uint16 gattr) const { const GlyphFace * p = m_face->glyphs().glyphSafe(gid); return p ? p->attrs()[gattr] : 0; }
int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const;
int32 getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const;
float glyphAdvance(uint16 gid) const { return m_face->glyphs().glyph(gid)->theAdvance().x; }
const Rect &theGlyphBBoxTemporary(uint16 gid) const { return m_face->glyphs().glyph(gid)->theBBox(); } //warning value may become invalid when another glyph is accessed
Slot *findRoot(Slot *is) const { return is->attachedTo() ? findRoot(is->attachedTo()) : is; }
@ -150,10 +151,13 @@ public:
int defaultOriginal() const { return m_defaultOriginal; }
const Face * getFace() const { return m_face; }
const Features & getFeatures(unsigned int /*charIndex*/) { assert(m_feats.size() == 1); return m_feats[0]; }
void bidiPass(uint8 aBidi, int paradir, uint8 aMirror);
void bidiPass(int paradir, uint8 aMirror);
int8 getSlotBidiClass(Slot *s) const;
void doMirror(uint16 aMirror);
Slot *addLineEnd(Slot *nSlot);
void delLineEnd(Slot *s);
bool hasJustification() const { return m_justifies.size() != 0; }
void reverseSlots();
bool isWhitespace(const int cid) const;
bool hasCollisionInfo() const { return m_collisions != 0; }
@ -163,7 +167,7 @@ public:
public: //only used by: GrSegment* makeAndInitialize(const GrFont *font, const GrFace *face, uint32 script, const FeaturesHandle& pFeats/*must not be IsNull*/, encform enc, const void* pStart, size_t nChars, int dir);
bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
void finalise(const Font *font);
void finalise(const Font *font, bool reverse=false);
float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
bool initCollisions();
@ -190,24 +194,34 @@ private:
uint8 m_flags; // General purpose flags
};
inline
int8 Segment::getSlotBidiClass(Slot *s) const
{
int8 res = s->getBidiClass();
if (res != -1) return res;
res = glyphAttr(s->gid(), m_silf->aBidi());
s->setBidiClass(res);
return res;
}
inline
void Segment::finalise(const Font *font)
void Segment::finalise(const Font *font, bool reverse)
{
if (!m_first) return;
m_advance = positionSlots(font);
m_advance = positionSlots(font, m_first, m_last, m_silf->dir(), true);
//associateChars(0, m_numCharinfo);
if (reverse && currdir() != (m_dir & 1))
reverseSlots();
linkClusters(m_first, m_last);
}
inline
int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel) const {
int32 Segment::getGlyphMetric(Slot *iSlot, uint8 metric, uint8 attrLevel, bool rtl) const {
if (attrLevel > 0)
{
Slot *is = findRoot(iSlot);
return is->clusterMetric(this, metric, attrLevel);
return is->clusterMetric(this, metric, attrLevel, rtl);
}
else
return m_face->getGlyphMetric(iSlot->gid(), metric);

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

@ -94,6 +94,7 @@ public:
uint8 maxCompPerLig() const { return m_iMaxComp; }
uint16 numClasses() const { return m_nClass; }
byte flags() const { return m_flags; }
byte dir() const { return m_dir; }
uint8 numJustLevels() const { return m_numJusts; }
Justinfo *justAttrs() const { return m_justs; }
uint16 endLineGlyphid() const { return m_gEndLine; }
@ -113,7 +114,7 @@ private:
uint8 m_numPasses;
uint8 m_numJusts;
uint8 m_sPass, m_pPass, m_jPass, m_bPass,
m_flags;
m_flags, m_dir;
uint8 m_aPseudo, m_aBreak, m_aUser, m_aBidi, m_aMirror, m_aPassBits,
m_iMaxComp, m_aCollision;

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

@ -32,15 +32,13 @@ of the License or (at your option) any later version.
#include "inc/Font.h"
#include "inc/Position.h"
namespace graphite2 {
typedef gr_attrCode attrCode;
class GlyphFace;
class Segment;
class SegCacheEntry;
class Segment;
struct SlotJustify
{
@ -82,7 +80,7 @@ public:
uint32 index() const { return m_index; }
void index(uint32 val) { m_index = val; }
Slot();
Slot(int16 *m_userAttr = NULL);
void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars);
Slot *next() const { return m_next; }
void next(Slot *s) { m_next = s; }
@ -99,7 +97,7 @@ public:
void after(int ind) { m_after = ind; }
bool isBase() const { return (!m_parent); }
void update(int numSlots, int numCharInfo, Position &relpos);
Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool isFinal);
Position finalise(const Segment* seg, const Font* font, Position & base, Rect & bbox, uint8 attrLevel, float & clusterMin, bool rtl, bool isFinal);
bool isDeleted() const { return (m_flags & DELETED) ? true : false; }
void markDeleted(bool state) { if (state) m_flags |= DELETED; else m_flags &= ~DELETED; }
bool isCopied() const { return (m_flags & COPIED) ? true : false; }
@ -109,6 +107,7 @@ public:
bool isInsertBefore() const { return !(m_flags & INSERTED); }
uint8 getBidiLevel() const { return m_bidiLevel; }
void setBidiLevel(uint8 level) { m_bidiLevel = level; }
int8 getBidiClass(const Segment *seg);
int8 getBidiClass() const { return m_bidiCls; }
void setBidiClass(int8 cls) { m_bidiCls = cls; }
int16 *userAttrs() const { return m_userAttr; }
@ -130,7 +129,7 @@ public:
bool sibling(Slot *ap);
bool removeChild(Slot *ap);
bool removeSibling(Slot *ap);
int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel);
int32 clusterMetric(const Segment* seg, uint8 metric, uint8 attrLevel, bool rtl);
void positionShift(Position a) { m_position += a; }
void floodShift(Position adj);
float just() const { return m_just; }

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

@ -56,7 +56,7 @@ private:
key_type offset;
};
static chunk empty_chunk;
static const chunk empty_chunk;
sparse(const sparse &);
sparse & operator = (const sparse &);
@ -88,7 +88,7 @@ private:
inline
sparse::sparse() throw() : m_nchunks(0)
{
m_array.map = &empty_chunk;
m_array.map = const_cast<graphite2::sparse::chunk *>(&empty_chunk);
}
@ -113,7 +113,7 @@ sparse::sparse(I attr, const I last)
}
if (m_nchunks == 0)
{
m_array.map=&empty_chunk;
m_array.map=const_cast<graphite2::sparse::chunk *>(&empty_chunk);
return;
}

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

@ -137,11 +137,11 @@ public:
////////////////////////////////// cmap lookup tools
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
int nEncodingId = 1, size_t length = 0);
bool CheckCmapSubtable4(const void * pCmap31 /*, unsigned int maxgid*/);
bool CheckCmapSubtable4(const void * pCmap31, size_t table_len /*, unsigned int maxgid*/);
gid16 CmapSubtable4Lookup(const void * pCmapSubtabel4, unsigned int nUnicodeId, int rangeKey = 0);
unsigned int CmapSubtable4NextCodepoint(const void *pCmap31, unsigned int nUnicodeId,
int * pRangeKey = 0);
bool CheckCmapSubtable12(const void *pCmap310 /*, unsigned int maxgid*/);
bool CheckCmapSubtable12(const void *pCmap310, size_t table_len /*, unsigned int maxgid*/);
gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
int * pRangeKey = 0);

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

@ -61,6 +61,7 @@ of the License or (at your option) any later version.
// isl = The last positioned slot
// ip = The current instruction pointer
// endPos = Position of advance of last cluster
// dir = writing system directionality of the font
// #define NOT_IMPLEMENTED assert(false)
@ -313,6 +314,8 @@ STARTOP(insert)
{
newSlot->originate(seg.defaultOriginal());
}
if (is == smap.highwater())
smap.highpassed(false);
is = newSlot;
seg.extendLength(1);
if (map != &smap[-1])
@ -389,7 +392,7 @@ STARTOP(attr_add)
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, 0);
@ -402,7 +405,7 @@ STARTOP(attr_sub)
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, 0);
@ -431,7 +434,7 @@ STARTOP(push_slot_attr)
const int slot_ref = int8(param[1]);
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
@ -458,7 +461,7 @@ STARTOP(push_glyph_metric)
const signed int attr_level = uint8(param[2]);
slotref slot = slotat(slot_ref);
if (slot)
push(seg.getGlyphMetric(slot, glyph_attr, attr_level));
push(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir));
ENDOP
STARTOP(push_feat)
@ -496,7 +499,7 @@ STARTOP(push_att_to_glyph_metric)
{
slotref att = slot->attachedTo();
if (att) slot = att;
push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level)));
push(int32(seg.getGlyphMetric(slot, glyph_attr, attr_level, dir)));
}
ENDOP
@ -507,7 +510,7 @@ STARTOP(push_islot_attr)
idx = uint8(param[2]);
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
slotref slot = slotat(slot_ref);
@ -552,7 +555,7 @@ STARTOP(iattr_add)
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, idx);
@ -566,7 +569,7 @@ STARTOP(iattr_sub)
const int val = int(pop());
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
{
seg.positionSlots(0, *smap.begin(), *(smap.end()-1));
seg.positionSlots(0, *smap.begin(), *(smap.end()-1), dir);
flags |= POSITIONED;
}
int res = is->getAttr(&seg, slat, idx);

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

@ -5,6 +5,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=982141
-->
<head>
<meta charset="utf-8">
<meta name="viewport" content="user-scalable=no">
<title>Test for Bug 982141, helper page</title>
<script type="application/javascript" src="apz_test_utils.js"></script>
<script type="application/javascript">
@ -87,7 +88,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=982141
}
</script>
</head>
<body style="overflow: hidden;"><!-- Make sure the root frame is not scrollable -->
<body style="overflow: hidden;"><!-- This combined with the user-scalable=no ensures the root frame is not scrollable -->
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=982141">Mozilla Bug 982141</a>
<!-- A scrollable subframe, with enough content to make it have a nonzero scroll range -->
<div style="height: 50px; width: 50px; overflow: scroll">

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

@ -787,13 +787,13 @@ APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification(
nsIWidget* aWidget,
const WidgetTouchEvent& aEvent,
uint64_t aInputBlockId,
const nsRefPtr<SetAllowedTouchBehaviorCallback>& aCallback)
const SetAllowedTouchBehaviorCallback& aCallback)
{
nsTArray<TouchBehaviorFlags> flags;
for (uint32_t i = 0; i < aEvent.touches.Length(); i++) {
flags.AppendElement(widget::ContentHelper::GetAllowedTouchBehavior(aWidget, aEvent.touches[i]->mRefPoint));
}
aCallback->Run(aInputBlockId, flags);
aCallback(aInputBlockId, flags);
}
void

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

@ -8,6 +8,7 @@
#include "FrameMetrics.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Function.h"
#include "mozilla/layers/APZUtils.h"
#include "nsIDOMWindowUtils.h"
@ -22,15 +23,8 @@ template<class T> class nsRefPtr;
namespace mozilla {
namespace layers {
/* A base class for callbacks to be passed to
* APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification. */
struct SetAllowedTouchBehaviorCallback {
public:
NS_INLINE_DECL_REFCOUNTING(SetAllowedTouchBehaviorCallback)
virtual void Run(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aFlags) const = 0;
protected:
virtual ~SetAllowedTouchBehaviorCallback() {}
};
typedef Function<void(uint64_t, const nsTArray<TouchBehaviorFlags>&)>
SetAllowedTouchBehaviorCallback;
/* This class contains some helper methods that facilitate implementing the
GeckoContentController callback interface required by the AsyncPanZoomController.
@ -162,7 +156,7 @@ public:
static void SendSetAllowedTouchBehaviorNotification(nsIWidget* aWidget,
const WidgetTouchEvent& aEvent,
uint64_t aInputBlockId,
const nsRefPtr<SetAllowedTouchBehaviorCallback>& aCallback);
const SetAllowedTouchBehaviorCallback& aCallback);
/* Notify content of a mouse scroll testing event. */
static void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent);

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

@ -9,6 +9,7 @@
#include "APZCCallbackHelper.h"
#include "gfxPrefs.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/Move.h"
#include "mozilla/Preferences.h"
#include "mozilla/TouchEvents.h"
#include "mozilla/layers/APZCCallbackHelper.h"
@ -91,10 +92,10 @@ static int32_t sActiveDurationMs = 10;
static bool sActiveDurationMsSet = false;
APZEventState::APZEventState(nsIWidget* aWidget,
const nsRefPtr<ContentReceivedInputBlockCallback>& aCallback)
ContentReceivedInputBlockCallback&& aCallback)
: mWidget(nullptr) // initialized in constructor body
, mActiveElementManager(new ActiveElementManager())
, mContentReceivedInputBlockCallback(aCallback)
, mContentReceivedInputBlockCallback(Move(aCallback))
, mPendingTouchPreventedResponse(false)
, mPendingTouchPreventedBlockId(0)
, mEndTouchIsClick(false)
@ -244,7 +245,7 @@ APZEventState::ProcessLongTap(const nsCOMPtr<nsIPresShell>& aPresShell,
APZES_LOG("MOZLONGTAP event handled: %d\n", eventHandled);
}
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, eventHandled);
mContentReceivedInputBlockCallback(aGuid, aInputBlockId, eventHandled);
}
void
@ -266,13 +267,13 @@ APZEventState::ProcessTouchEvent(const WidgetTouchEvent& aEvent,
if (mPendingTouchPreventedResponse) {
// We can enter here if we get two TOUCH_STARTs in a row and didn't
// respond to the first one. Respond to it now.
mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
mContentReceivedInputBlockCallback(mPendingTouchPreventedGuid,
mPendingTouchPreventedBlockId, false);
sentContentResponse = true;
mPendingTouchPreventedResponse = false;
}
if (isTouchPrevented) {
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, isTouchPrevented);
mContentReceivedInputBlockCallback(aGuid, aInputBlockId, isTouchPrevented);
sentContentResponse = true;
} else {
mPendingTouchPreventedResponse = true;
@ -328,7 +329,7 @@ APZEventState::ProcessWheelEvent(const WidgetWheelEvent& aEvent,
// scroll by setting defaultPrevented to true.
bool defaultPrevented =
aEvent.mFlags.mDefaultPrevented || aEvent.TriggersSwipe();
mContentReceivedInputBlockCallback->Run(aGuid, aInputBlockId, defaultPrevented);
mContentReceivedInputBlockCallback(aGuid, aInputBlockId, defaultPrevented);
}
void
@ -408,7 +409,7 @@ bool
APZEventState::SendPendingTouchPreventedResponse(bool aPreventDefault)
{
if (mPendingTouchPreventedResponse) {
mContentReceivedInputBlockCallback->Run(mPendingTouchPreventedGuid,
mContentReceivedInputBlockCallback(mPendingTouchPreventedGuid,
mPendingTouchPreventedBlockId, aPreventDefault);
mPendingTouchPreventedResponse = false;
return true;

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

@ -11,11 +11,12 @@
#include "FrameMetrics.h" // for ScrollableLayerGuid
#include "Units.h"
#include "mozilla/EventForwards.h"
#include "mozilla/Function.h"
#include "mozilla/layers/GeckoContentController.h" // for APZStateChange
#include "mozilla/nsRefPtr.h"
#include "nsCOMPtr.h"
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
#include "nsIWeakReferenceUtils.h" // for nsWeakPtr
#include "mozilla/nsRefPtr.h"
template <class> class nsCOMPtr;
class nsIDocument;
@ -27,15 +28,10 @@ namespace layers {
class ActiveElementManager;
struct ContentReceivedInputBlockCallback {
public:
NS_INLINE_DECL_REFCOUNTING(ContentReceivedInputBlockCallback);
virtual void Run(const ScrollableLayerGuid& aGuid,
uint64_t aInputBlockId,
bool aPreventDefault) const = 0;
protected:
virtual ~ContentReceivedInputBlockCallback() {}
};
typedef Function<void(const ScrollableLayerGuid&,
uint64_t /* input block id */,
bool /* prevent default */)>
ContentReceivedInputBlockCallback;
/**
* A content-side component that keeps track of state for handling APZ
@ -46,7 +42,7 @@ class APZEventState {
typedef FrameMetrics::ViewID ViewID;
public:
APZEventState(nsIWidget* aWidget,
const nsRefPtr<ContentReceivedInputBlockCallback>& aCallback);
ContentReceivedInputBlockCallback&& aCallback);
NS_INLINE_DECL_REFCOUNTING(APZEventState);
@ -76,7 +72,7 @@ private:
private:
nsWeakPtr mWidget;
nsRefPtr<ActiveElementManager> mActiveElementManager;
nsRefPtr<ContentReceivedInputBlockCallback> mContentReceivedInputBlockCallback;
ContentReceivedInputBlockCallback mContentReceivedInputBlockCallback;
bool mPendingTouchPreventedResponse;
ScrollableLayerGuid mPendingTouchPreventedGuid;
uint64_t mPendingTouchPreventedBlockId;

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

@ -585,21 +585,45 @@ AdjustForClip(const Matrix4x4& asyncTransform, Layer* aLayer)
return result;
}
static void
ExpandRootClipRect(Layer* aLayer, const ScreenMargin& aFixedLayerMargins)
{
// For Fennec we want to expand the root scrollable layer clip rect based on
// the fixed position margins. In particular, we want this while the dynamic
// toolbar is in the process of sliding offscreen and the area of the
// LayerView visible to the user is larger than the viewport size that Gecko
// knows about (and therefore larger than the clip rect). We could also just
// clear the clip rect on aLayer entirely but this seems more precise.
Maybe<ParentLayerIntRect> rootClipRect = aLayer->AsLayerComposite()->GetShadowClipRect();
if (rootClipRect && aFixedLayerMargins != ScreenMargin()) {
#ifndef MOZ_WIDGET_ANDROID
// We should never enter here on anything other than Fennec, since
// aFixedLayerMargins should be empty everywhere else.
MOZ_ASSERT(false);
#endif
ParentLayerRect rect(rootClipRect.value());
rect.Deflate(ViewAs<ParentLayerPixel>(aFixedLayerMargins,
PixelCastJustification::ScreenIsParentLayerForRoot));
aLayer->AsLayerComposite()->SetShadowClipRect(Some(RoundedOut(rect)));
}
}
bool
AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer,
bool* aOutFoundRoot)
{
bool appliedTransform = false;
for (Layer* child = aLayer->GetFirstChild();
child; child = child->GetNextSibling()) {
appliedTransform |=
ApplyAsyncContentTransformToTree(child);
ApplyAsyncContentTransformToTree(child, aOutFoundRoot);
}
Matrix4x4 oldTransform = aLayer->GetTransform();
Matrix4x4 combinedAsyncTransform;
bool hasAsyncTransform = false;
ScreenMargin fixedLayerMargins(0, 0, 0, 0);
ScreenMargin fixedLayerMargins;
// Each layer has multiple clips. Its local clip, which must move with async
// transforms, and its scrollframe clips, which are the clips between each
@ -642,34 +666,43 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
}
const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
// TODO: When we enable APZ on Fennec, we'll need to call SyncFrameMetrics here.
// When doing so, it might be useful to look at how it was called here before
// bug 1036967 removed the (dead) call.
#if defined(MOZ_ANDROID_APZ)
bool rootContentLayer = metrics.IsRootContent();
#ifdef MOZ_B2GDROID
// B2GDroid is a special snowflake since it doesn't seem to have any root
// content document. However we still need to send a setFirstPaintViewport
// message, so we use the root of the layer tree as the root content layer
// instead. For the most part this should work fine; the Java code will just
// think the root layer is the "main" content, which in a manner of speaking,
// it is.
rootContentLayer = (aLayer->GetParent() == nullptr);
#endif // MOZ_B2GDROID
if (rootContentLayer) {
if (mIsFirstPaint) {
// If we find a metrics which is the root content doc, use that. If not, use
// the root layer. Since this function recurses on children first we should
// only end up using the root layer if the entire tree was devoid of a
// root content metrics. This is a temporary solution; in the long term we
// should not need the root content metrics at all. See bug 1201529 comment
// 6 for details.
if (!(*aOutFoundRoot)) {
*aOutFoundRoot = metrics.IsRootContent() || /* RCD */
(aLayer->GetParent() == nullptr && /* rootmost metrics */
i + 1 >= aLayer->GetFrameMetricsCount());
if (*aOutFoundRoot) {
CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
mContentRect = metrics.GetScrollableRect();
SetFirstPaintViewport(scrollOffsetLayerPixels,
geckoZoom,
mContentRect);
if (mIsFirstPaint) {
LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
mContentRect = metrics.GetScrollableRect();
SetFirstPaintViewport(scrollOffsetLayerPixels,
geckoZoom,
mContentRect);
} else {
// Compute the painted displayport in document-relative CSS pixels.
CSSRect displayPort(metrics.GetCriticalDisplayPort().IsEmpty() ?
metrics.GetDisplayPort() :
metrics.GetCriticalDisplayPort());
displayPort += metrics.GetScrollOffset();
SyncFrameMetrics(scrollOffset,
geckoZoom * asyncTransformWithoutOverscroll.mScale,
metrics.GetScrollableRect(), displayPort, geckoZoom, mLayersUpdated,
mPaintSyncId, fixedLayerMargins);
}
mIsFirstPaint = false;
mLayersUpdated = false;
mPaintSyncId = 0;
}
mIsFirstPaint = false;
mLayersUpdated = false;
}
#endif // MOZ_ANDROID_APZ
#endif
// Transform the current local clip by this APZC's async transform. If we're
// using containerful scrolling, then the clip is not part of the scrolled
@ -745,6 +778,8 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer)
appliedTransform = true;
}
ExpandRootClipRect(aLayer, fixedLayerMargins);
if (aLayer->GetScrollbarDirection() != Layer::NONE) {
ApplyAsyncTransformToScrollbar(aLayer);
}
@ -1103,24 +1138,7 @@ AsyncCompositionManager::TransformScrollableLayer(Layer* aLayer)
AlignFixedAndStickyLayers(aLayer, aLayer, metrics.GetScrollId(), oldTransform,
aLayer->GetLocalTransform(), fixedLayerMargins);
// For Fennec we want to expand the root scrollable layer clip rect based on
// the fixed position margins. In particular, we want this while the dynamic
// toolbar is in the process of sliding offscreen and the area of the
// LayerView visible to the user is larger than the viewport size that Gecko
// knows about (and therefore larger than the clip rect). We could also just
// clear the clip rect on aLayer entirely but this seems more precise.
Maybe<ParentLayerIntRect> rootClipRect = aLayer->AsLayerComposite()->GetShadowClipRect();
if (rootClipRect && fixedLayerMargins != ScreenMargin()) {
#ifndef MOZ_WIDGET_ANDROID
// We should never enter here on anything other than Fennec, since
// fixedLayerMargins should be empty everywhere else.
MOZ_ASSERT(false);
#endif
ParentLayerRect rect(rootClipRect.value());
rect.Deflate(ViewAs<ParentLayerPixel>(fixedLayerMargins,
PixelCastJustification::ScreenIsParentLayerForRoot));
aLayer->AsLayerComposite()->SetShadowClipRect(Some(RoundedOut(rect)));
}
ExpandRootClipRect(aLayer, fixedLayerMargins);
}
void
@ -1160,7 +1178,12 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame,
// its own platform-specific async rendering that is done partially
// in Gecko and partially in Java.
wantNextFrame |= SampleAPZAnimations(LayerMetricsWrapper(root), aCurrentFrame);
if (!ApplyAsyncContentTransformToTree(root)) {
bool foundRoot = false;
if (ApplyAsyncContentTransformToTree(root, &foundRoot)) {
#if defined(MOZ_ANDROID_APZ)
MOZ_ASSERT(foundRoot);
#endif
} else {
nsAutoTArray<Layer*,1> scrollableLayers;
#ifdef MOZ_WIDGET_ANDROID
mLayerManager->GetRootScrollableLayers(scrollableLayers);
@ -1229,18 +1252,18 @@ AsyncCompositionManager::SyncViewportInfo(const LayerIntRect& aDisplayPort,
void
AsyncCompositionManager::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset,
float aZoom,
const CSSToParentLayerScale& aZoom,
const CSSRect& aCssPageRect,
bool aLayersUpdated,
const CSSRect& aDisplayPort,
const CSSToLayerScale& aDisplayResolution,
bool aIsFirstPaint,
const CSSToLayerScale& aPaintedResolution,
bool aLayersUpdated,
int32_t aPaintSyncId,
ScreenMargin& aFixedLayerMargins)
{
#ifdef MOZ_WIDGET_ANDROID
AndroidBridge::Bridge()->SyncFrameMetrics(aScrollOffset, aZoom, aCssPageRect,
aLayersUpdated, aDisplayPort,
aDisplayResolution, aIsFirstPaint,
aDisplayPort, aPaintedResolution,
aLayersUpdated, aPaintSyncId,
aFixedLayerMargins);
#endif
}

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

@ -128,8 +128,11 @@ public:
private:
void TransformScrollableLayer(Layer* aLayer);
// Return true if an AsyncPanZoomController content transform was
// applied for |aLayer|.
bool ApplyAsyncContentTransformToTree(Layer* aLayer);
// applied for |aLayer|. |*aOutFoundRoot| is set to true on Android only, if
// one of the metrics on one of the layers was determined to be the "root"
// and its state was synced to the Java front-end. |aOutFoundRoot| must be
// non-null.
bool ApplyAsyncContentTransformToTree(Layer* aLayer, bool* aOutFoundRoot);
/**
* Update the shadow transform for aLayer assuming that is a scrollbar,
* so that it stays in sync with the content that is being scrolled by APZ.
@ -148,12 +151,12 @@ private:
CSSToParentLayerScale& aScale,
ScreenMargin& aFixedLayerMargins);
void SyncFrameMetrics(const ParentLayerPoint& aScrollOffset,
float aZoom,
const CSSToParentLayerScale& aZoom,
const CSSRect& aCssPageRect,
bool aLayersUpdated,
const CSSRect& aDisplayPort,
const CSSToLayerScale& aDisplayResolution,
bool aIsFirstPaint,
const CSSToLayerScale& aPaintedResolution,
bool aLayersUpdated,
int32_t aPaintSyncId,
ScreenMargin& aFixedLayerMargins);
/**

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

@ -4,6 +4,11 @@
-->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
width="100%" height="100%">
<!-- There is a bug with MultiTiledContentClient that causes improper painting;
bug 1204076 is on file for this issue. As a temporary workaround, we set
user-scalable=no here so that WantAsyncZoom() returns false and we don't
use a MultiTiledContentClient. Once bug 1204076 is fixed, we can remove this. -->
<meta xmlns="http://www.w3.org/1999/xhtml" name="viewport" content="user-scalable=no"/>
<title>Testcase for small circles</title>
<!--From https://bugzilla.mozilla.org/show_bug.cgi?id=1143303 -->

До

Ширина:  |  Высота:  |  Размер: 770 B

После

Ширина:  |  Высота:  |  Размер: 1.2 KiB

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