Merge m-c to b2g-inbound
@ -117,7 +117,6 @@ run-if = crashreporter
|
||||
[browser_aboutHealthReport.js]
|
||||
skip-if = os == "linux" # Bug 924307
|
||||
[browser_aboutHome.js]
|
||||
skip-if = os == "linux" # Bug 945667
|
||||
[browser_aboutSyncProgress.js]
|
||||
[browser_addKeywordSearch.js]
|
||||
[browser_alltabslistener.js]
|
||||
|
@ -89,11 +89,15 @@ let gTests = [
|
||||
}
|
||||
},
|
||||
|
||||
// Disabled on Linux for intermittent issues with FHR, see Bug 945667.
|
||||
{
|
||||
desc: "Check that performing a search fires a search event and records to " +
|
||||
"Firefox Health Report.",
|
||||
setup: function () { },
|
||||
run: function () {
|
||||
// Skip this test on Linux.
|
||||
if (navigator.platform.indexOf("Linux") == 0) { return; }
|
||||
|
||||
try {
|
||||
let cm = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
|
||||
cm.getCategoryEntry("healthreport-js-provider-default", "SearchesProvider");
|
||||
|
@ -12,6 +12,9 @@ support-files =
|
||||
[browser_880164_customization_context_menus.js]
|
||||
[browser_880382_drag_wide_widgets_in_panel.js]
|
||||
[browser_885052_customize_mode_observers_disabed.js]
|
||||
# Bug 951403 - Disabled on OSX for frequent failures
|
||||
skip-if = os == "mac"
|
||||
|
||||
[browser_885530_showInPrivateBrowsing.js]
|
||||
[browser_886323_buildArea_removable_nodes.js]
|
||||
[browser_887438_currentset_shim.js]
|
||||
|
@ -5,14 +5,8 @@
|
||||
ifdef ENABLE_TESTS
|
||||
pp_mochitest_browser_files := \
|
||||
browser_google.js \
|
||||
$(NULL)
|
||||
|
||||
# This test depends on browser_aboutHome.js, which was disabled (bug 945667)
|
||||
ifndef MOZ_WIDGET_GTK
|
||||
pp_mochitest_browser_files += \
|
||||
browser_google_behavior.js \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
pp_mochitest_browser_files_PATH := $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
|
||||
pp_mochitest_browser_files_FLAGS := -DMOZ_DISTRIBUTION_ID=$(MOZ_DISTRIBUTION_ID)
|
||||
|
@ -10,19 +10,18 @@ function ifWebGLSupported() {
|
||||
let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
|
||||
|
||||
let reloaded = reload(target);
|
||||
let firstProgram = yield once(gFront, "program-linked");
|
||||
yield once(gFront, "program-linked");
|
||||
yield reloaded;
|
||||
|
||||
let navigated = navigate(target, MULTIPLE_CONTEXTS_URL);
|
||||
let [secondProgram, thirdProgram] = yield getPrograms(gFront, 2);
|
||||
yield getPrograms(gFront, 2);
|
||||
yield navigated;
|
||||
|
||||
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
||||
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
||||
|
||||
yield navigateInHistory(target, "back", "will-navigate");
|
||||
yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
|
||||
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
|
||||
yield waitForSources();
|
||||
|
||||
is($("#content").hidden, false,
|
||||
"The tool's content should not be hidden.");
|
||||
@ -37,8 +36,7 @@ function ifWebGLSupported() {
|
||||
"The fragment shader editor contains the correct text.");
|
||||
|
||||
yield navigateInHistory(target, "forward", "will-navigate");
|
||||
yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
|
||||
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
|
||||
yield waitForSources();
|
||||
|
||||
is($("#content").hidden, false,
|
||||
"The tool's content should not be hidden.");
|
||||
@ -54,4 +52,18 @@ function ifWebGLSupported() {
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
|
||||
function waitForSources() {
|
||||
let deferred = promise.defer();
|
||||
let win = panel.panelWin;
|
||||
// These events must fire in this in order and the second event fires
|
||||
// synchronously after the first event, so we can't use Promise.all and the
|
||||
// `once` helper.
|
||||
win.once(win.EVENTS.PROGRAMS_ADDED, () => {
|
||||
win.once(win.EVENTS.SOURCES_SHOWN, () => {
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ this.WinTaskbarJumpList =
|
||||
}
|
||||
break;
|
||||
|
||||
case "back":
|
||||
case "active":
|
||||
this._updateTimer();
|
||||
break;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
@ -467,6 +467,10 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
|
||||
-moz-image-region: rect(18px, 630px, 36px, 612px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"][open] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
-moz-image-region: rect(36px, 630px, 54px, 612px);
|
||||
}
|
||||
|
||||
#history-panelmenu@toolbarButtonPressed@ {
|
||||
-moz-image-region: rect(18px, 180px, 36px, 162px);
|
||||
}
|
||||
@ -475,7 +479,6 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
|
||||
-moz-image-region: rect(36px, 180px, 54px, 162px);
|
||||
}
|
||||
|
||||
#downloads-indicator@toolbarButtonPressed@,
|
||||
#downloads-button@toolbarButtonPressed@ {
|
||||
-moz-image-region: rect(18px, 198px, 36px, 180px);
|
||||
}
|
||||
@ -671,6 +674,10 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
|
||||
-moz-image-region: rect(36px, 1260px, 72px, 1224px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"][open] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
-moz-image-region: rect(72px, 1260px, 108px, 1224px);
|
||||
}
|
||||
|
||||
#history-panelmenu[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 360px, 36px, 324px);
|
||||
}
|
||||
@ -683,12 +690,10 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
|
||||
-moz-image-region: rect(72px, 360px, 108px, 324px);
|
||||
}
|
||||
|
||||
#downloads-indicator[cui-areatype="toolbar"],
|
||||
#downloads-button[cui-areatype="toolbar"] {
|
||||
-moz-image-region: rect(0, 396px, 36px, 360px);
|
||||
}
|
||||
|
||||
#downloads-indicator[cui-areatype="toolbar"]:hover:active:not([disabled="true"]),
|
||||
#downloads-button[cui-areatype="toolbar"]:hover:active:not([disabled="true"]) {
|
||||
-moz-image-region: rect(36px, 396px, 72px, 360px);
|
||||
}
|
||||
@ -941,7 +946,6 @@ toolbar .toolbarbutton-1:not([type="menu-button"]),
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="menu-panel"],
|
||||
#downloads-indicator[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #downloads-button {
|
||||
-moz-image-region: rect(0px, 512px, 64px, 448px);
|
||||
}
|
||||
@ -1916,6 +1920,11 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"].bookmark-item > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ toolbarpaletteitem[place="palette"] > #history-panelmenu {
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="menu-panel"],
|
||||
#downloads-indicator[cui-areatype="menu-panel"],
|
||||
toolbarpaletteitem[place="palette"] > #downloads-button {
|
||||
-moz-image-region: rect(0px, 256px, 32px, 224px);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
@ -119,6 +119,21 @@ the build system.
|
||||
|
||||
There are various proposals for fixing this. See bug 795995.
|
||||
|
||||
Installing Python Manually
|
||||
==========================
|
||||
|
||||
We highly recommend you use your system's package manager or a
|
||||
well-supported 3rd party package manager to install Python for you. If
|
||||
these are not available to you, we recommend the following tools for
|
||||
installing Python:
|
||||
|
||||
* `buildout.python <https://github.com/collective/buildout.python>`_
|
||||
* `pyenv <https://github.com/yyuu/pyenv>`_
|
||||
* An official installer from http://www.python.org.
|
||||
|
||||
If all else fails, consider compiling Python from source manually. But this
|
||||
should be viewed as the least desirable option.
|
||||
|
||||
Common Issues with Python
|
||||
=========================
|
||||
|
||||
|
@ -19,6 +19,8 @@ interface WorkerGlobalScope : EventTarget {
|
||||
void close();
|
||||
attribute OnErrorEventHandler onerror;
|
||||
|
||||
attribute EventHandler onoffline;
|
||||
attribute EventHandler ononline;
|
||||
// also has additional members in a partial interface
|
||||
};
|
||||
|
||||
|
@ -6,3 +6,4 @@ interface WorkerNavigator {
|
||||
};
|
||||
|
||||
WorkerNavigator implements NavigatorID;
|
||||
WorkerNavigator implements NavigatorOnLine;
|
||||
|
@ -17,17 +17,18 @@ NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WorkerNavigator, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WorkerNavigator, Release)
|
||||
|
||||
/* static */ already_AddRefed<WorkerNavigator>
|
||||
WorkerNavigator::Create()
|
||||
WorkerNavigator::Create(bool aOnLine)
|
||||
{
|
||||
RuntimeService* rts = RuntimeService::GetService();
|
||||
MOZ_ASSERT(rts);
|
||||
|
||||
const RuntimeService::NavigatorStrings& strings =
|
||||
rts->GetNavigatorStrings();
|
||||
const RuntimeService::NavigatorProperties& properties =
|
||||
rts->GetNavigatorProperties();
|
||||
|
||||
nsRefPtr<WorkerNavigator> navigator =
|
||||
new WorkerNavigator(strings.mAppName, strings.mAppVersion,
|
||||
strings.mPlatform, strings.mUserAgent);
|
||||
new WorkerNavigator(properties.mAppName, properties.mAppVersion,
|
||||
properties.mPlatform, properties.mUserAgent,
|
||||
aOnLine);
|
||||
|
||||
return navigator.forget();
|
||||
}
|
||||
|
@ -18,15 +18,18 @@ class WorkerNavigator MOZ_FINAL : public nsWrapperCache
|
||||
nsString mAppVersion;
|
||||
nsString mPlatform;
|
||||
nsString mUserAgent;
|
||||
bool mOnline;
|
||||
|
||||
WorkerNavigator(const nsAString& aAppName,
|
||||
const nsAString& aAppVersion,
|
||||
const nsAString& aPlatform,
|
||||
const nsAString& aUserAgent)
|
||||
const nsAString& aUserAgent,
|
||||
bool aOnline)
|
||||
: mAppName(aAppName)
|
||||
, mAppVersion(aAppVersion)
|
||||
, mPlatform(aPlatform)
|
||||
, mUserAgent(aUserAgent)
|
||||
, mOnline(aOnline)
|
||||
{
|
||||
MOZ_COUNT_CTOR(WorkerNavigator);
|
||||
SetIsDOMBinding();
|
||||
@ -38,7 +41,7 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WorkerNavigator)
|
||||
|
||||
static already_AddRefed<WorkerNavigator>
|
||||
Create();
|
||||
Create(bool aOnLine);
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
@ -60,10 +63,12 @@ public:
|
||||
{
|
||||
aAppName = mAppName;
|
||||
}
|
||||
|
||||
void GetAppVersion(nsString& aAppVersion) const
|
||||
{
|
||||
aAppVersion = mAppVersion;
|
||||
}
|
||||
|
||||
void GetPlatform(nsString& aPlatform) const
|
||||
{
|
||||
aPlatform = mPlatform;
|
||||
@ -76,10 +81,22 @@ public:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void GetUserAgent(nsString& aUserAgent) const
|
||||
{
|
||||
aUserAgent = mUserAgent;
|
||||
}
|
||||
|
||||
bool OnLine() const
|
||||
{
|
||||
return mOnline;
|
||||
}
|
||||
|
||||
// Worker thread only!
|
||||
void SetOnLine(bool aOnline)
|
||||
{
|
||||
mOnline = aOnline;
|
||||
}
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -1223,7 +1223,7 @@ bool RuntimeService::sDefaultPreferences[WORKERPREF_COUNT] = { false };
|
||||
|
||||
RuntimeService::RuntimeService()
|
||||
: mMutex("RuntimeService::mMutex"), mObserved(false),
|
||||
mShuttingDown(false), mNavigatorStringsLoaded(false)
|
||||
mShuttingDown(false), mNavigatorPropertiesLoaded(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
NS_ASSERTION(!gRuntimeService, "More than one service!");
|
||||
@ -1352,17 +1352,17 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!mNavigatorStringsLoaded) {
|
||||
NS_GetNavigatorAppName(mNavigatorStrings.mAppName);
|
||||
if (NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorStrings.mAppVersion)) ||
|
||||
NS_FAILED(NS_GetNavigatorPlatform(mNavigatorStrings.mPlatform)) ||
|
||||
NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorStrings.mUserAgent))) {
|
||||
if (!mNavigatorPropertiesLoaded) {
|
||||
NS_GetNavigatorAppName(mNavigatorProperties.mAppName);
|
||||
if (NS_FAILED(NS_GetNavigatorAppVersion(mNavigatorProperties.mAppVersion)) ||
|
||||
NS_FAILED(NS_GetNavigatorPlatform(mNavigatorProperties.mPlatform)) ||
|
||||
NS_FAILED(NS_GetNavigatorUserAgent(mNavigatorProperties.mUserAgent))) {
|
||||
JS_ReportError(aCx, "Failed to load navigator strings!");
|
||||
UnregisterWorker(aCx, aWorkerPrivate);
|
||||
return false;
|
||||
}
|
||||
|
||||
mNavigatorStringsLoaded = true;
|
||||
mNavigatorPropertiesLoaded = true;
|
||||
}
|
||||
|
||||
nsPIDOMWindow* window = aWorkerPrivate->GetWindow();
|
||||
@ -1660,6 +1660,10 @@ RuntimeService::Init()
|
||||
NS_WARNING("Failed to register for memory pressure notifications!");
|
||||
}
|
||||
|
||||
if (NS_FAILED(obs->AddObserver(this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC, false))) {
|
||||
NS_WARNING("Failed to register for offline notification event!");
|
||||
}
|
||||
|
||||
NS_ASSERTION(!gRuntimeServiceDuringInit, "This should be null!");
|
||||
gRuntimeServiceDuringInit = this;
|
||||
|
||||
@ -1911,6 +1915,10 @@ RuntimeService::Cleanup()
|
||||
NS_WARNING("Failed to unregister for memory pressure notifications!");
|
||||
}
|
||||
|
||||
if (NS_FAILED(obs->RemoveObserver(this,
|
||||
NS_IOSERVICE_OFFLINE_STATUS_TOPIC))) {
|
||||
NS_WARNING("Failed to unregister for offline notification event!");
|
||||
}
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID);
|
||||
obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
mObserved = false;
|
||||
@ -2288,6 +2296,12 @@ RuntimeService::CycleCollectAllWorkers()
|
||||
BROADCAST_ALL_WORKERS(CycleCollect, /* dummy = */ false);
|
||||
}
|
||||
|
||||
void
|
||||
RuntimeService::SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline)
|
||||
{
|
||||
BROADCAST_ALL_WORKERS(OfflineStatusChangeEvent, aIsOffline);
|
||||
}
|
||||
|
||||
// nsISupports
|
||||
NS_IMPL_ISUPPORTS1(RuntimeService, nsIObserver)
|
||||
|
||||
@ -2319,6 +2333,10 @@ RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
CycleCollectAllWorkers();
|
||||
return NS_OK;
|
||||
}
|
||||
if (!strcmp(aTopic, NS_IOSERVICE_OFFLINE_STATUS_TOPIC)) {
|
||||
SendOfflineStatusChangeEventToAllWorkers(NS_IsOffline());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Unknown observer topic!");
|
||||
return NS_OK;
|
||||
|
@ -100,7 +100,7 @@ private:
|
||||
static bool sDefaultPreferences[WORKERPREF_COUNT];
|
||||
|
||||
public:
|
||||
struct NavigatorStrings
|
||||
struct NavigatorProperties
|
||||
{
|
||||
nsString mAppName;
|
||||
nsString mAppVersion;
|
||||
@ -109,12 +109,12 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
NavigatorStrings mNavigatorStrings;
|
||||
NavigatorProperties mNavigatorProperties;
|
||||
|
||||
// True when the observer service holds a reference to this object.
|
||||
bool mObserved;
|
||||
bool mShuttingDown;
|
||||
bool mNavigatorStringsLoaded;
|
||||
bool mNavigatorPropertiesLoaded;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -150,10 +150,10 @@ public:
|
||||
void
|
||||
ForgetSharedWorker(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
const NavigatorStrings&
|
||||
GetNavigatorStrings() const
|
||||
const NavigatorProperties&
|
||||
GetNavigatorProperties() const
|
||||
{
|
||||
return mNavigatorStrings;
|
||||
return mNavigatorProperties;
|
||||
}
|
||||
|
||||
void
|
||||
@ -239,6 +239,9 @@ public:
|
||||
void
|
||||
CycleCollectAllWorkers();
|
||||
|
||||
void
|
||||
SendOfflineStatusChangeEventToAllWorkers(bool aIsOffline);
|
||||
|
||||
private:
|
||||
RuntimeService();
|
||||
~RuntimeService();
|
||||
|
@ -73,6 +73,7 @@
|
||||
|
||||
#include "File.h"
|
||||
#include "MessagePort.h"
|
||||
#include "Navigator.h"
|
||||
#include "Principal.h"
|
||||
#include "RuntimeService.h"
|
||||
#include "ScriptLoader.h"
|
||||
@ -1693,6 +1694,26 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class OfflineStatusChangeRunnable : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
OfflineStatusChangeRunnable(WorkerPrivate* aWorkerPrivate, bool aIsOffline)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
mIsOffline(aIsOffline)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
aWorkerPrivate->OfflineStatusChangeEventInternal(aCx, mIsOffline);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mIsOffline;
|
||||
};
|
||||
|
||||
class WorkerJSRuntimeStats : public JS::RuntimeStats
|
||||
{
|
||||
const nsACString& mRtPath;
|
||||
@ -3035,6 +3056,56 @@ WorkerPrivateParent<Derived>::CycleCollect(JSContext* aCx, bool aDummy)
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline)
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
|
||||
nsRefPtr<OfflineStatusChangeRunnable> runnable =
|
||||
new OfflineStatusChangeRunnable(ParentAsWorkerPrivate(), aIsOffline);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
NS_WARNING("Failed to dispatch offline status change event!");
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
for (uint32_t index = 0; index < mChildWorkers.Length(); ++index) {
|
||||
mChildWorkers[index]->OfflineStatusChangeEvent(aCx, aIsOffline);
|
||||
}
|
||||
|
||||
mOnLine = !aIsOffline;
|
||||
WorkerGlobalScope* globalScope = GlobalScope();
|
||||
nsRefPtr<WorkerNavigator> nav = globalScope->GetExistingNavigator();
|
||||
if (nav) {
|
||||
nav->SetOnLine(mOnLine);
|
||||
}
|
||||
|
||||
nsString eventType;
|
||||
if (aIsOffline) {
|
||||
eventType.AssignLiteral("offline");
|
||||
} else {
|
||||
eventType.AssignLiteral("online");
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv =
|
||||
NS_NewDOMEvent(getter_AddRefs(event), globalScope, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
rv = event->InitEvent(eventType, false, false);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
globalScope->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
bool
|
||||
WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
|
||||
@ -3554,10 +3625,12 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx,
|
||||
if (aParent) {
|
||||
aParent->AssertIsOnWorkerThread();
|
||||
aParent->GetAllPreferences(mPreferences);
|
||||
mOnLine = aParent->OnLine();
|
||||
}
|
||||
else {
|
||||
AssertIsOnMainThread();
|
||||
RuntimeService::GetDefaultPreferences(mPreferences);
|
||||
mOnLine = !NS_IsOffline();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,6 +392,9 @@ public:
|
||||
void
|
||||
CycleCollect(JSContext* aCx, bool aDummy);
|
||||
|
||||
void
|
||||
OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
|
||||
|
||||
bool
|
||||
RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
|
||||
|
||||
@ -743,6 +746,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
#endif
|
||||
|
||||
bool mPreferences[WORKERPREF_COUNT];
|
||||
bool mOnLine;
|
||||
|
||||
protected:
|
||||
~WorkerPrivate();
|
||||
@ -902,6 +906,9 @@ public:
|
||||
void
|
||||
CycleCollectInternal(JSContext* aCx, bool aCollectChildren);
|
||||
|
||||
void
|
||||
OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline);
|
||||
|
||||
JSContext*
|
||||
GetJSContext() const
|
||||
{
|
||||
@ -983,6 +990,13 @@ public:
|
||||
return mPreferences[WORKERPREF_PROMISE];
|
||||
}
|
||||
|
||||
bool
|
||||
OnLine() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mOnLine;
|
||||
}
|
||||
|
||||
void
|
||||
StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult);
|
||||
|
||||
|
@ -99,7 +99,7 @@ WorkerGlobalScope::Navigator()
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (!mNavigator) {
|
||||
mNavigator = WorkerNavigator::Create();
|
||||
mNavigator = WorkerNavigator::Create(mWorkerPrivate->OnLine());
|
||||
MOZ_ASSERT(mNavigator);
|
||||
}
|
||||
|
||||
@ -107,6 +107,15 @@ WorkerGlobalScope::Navigator()
|
||||
return navigator.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<WorkerNavigator>
|
||||
WorkerGlobalScope::GetExistingNavigator() const
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<WorkerNavigator> navigator = mNavigator;
|
||||
return navigator.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerGlobalScope::Close(JSContext* aCx)
|
||||
{
|
||||
|
@ -60,8 +60,13 @@ public:
|
||||
|
||||
already_AddRefed<WorkerLocation>
|
||||
Location();
|
||||
|
||||
already_AddRefed<WorkerNavigator>
|
||||
Navigator();
|
||||
|
||||
already_AddRefed<WorkerNavigator>
|
||||
GetExistingNavigator() const;
|
||||
|
||||
void
|
||||
Close(JSContext* aCx);
|
||||
|
||||
@ -97,6 +102,8 @@ public:
|
||||
void
|
||||
Btoa(const nsAString& aBtoa, nsAString& aOutput, ErrorResult& aRv) const;
|
||||
|
||||
IMPL_EVENT_HANDLER(online)
|
||||
IMPL_EVENT_HANDLER(offline)
|
||||
IMPL_EVENT_HANDLER(close)
|
||||
|
||||
void
|
||||
|
@ -27,6 +27,9 @@ support-files =
|
||||
multi_sharedWorker_sharedWorker.js
|
||||
navigator_worker.js
|
||||
newError_worker.js
|
||||
onLine_worker.js
|
||||
onLine_worker_child.js
|
||||
onLine_worker_head.js
|
||||
promise_worker.js
|
||||
recursion_worker.js
|
||||
recursiveOnerror_worker.js
|
||||
@ -90,6 +93,7 @@ support-files =
|
||||
[test_multi_sharedWorker_lifetimes.html]
|
||||
[test_navigator.html]
|
||||
[test_newError.html]
|
||||
[test_onLine.html]
|
||||
[test_promise.html]
|
||||
[test_recursion.html]
|
||||
[test_recursiveOnerror.html]
|
||||
|
@ -9,7 +9,8 @@ var supportedProps = [
|
||||
"platform",
|
||||
"product",
|
||||
"taintEnabled",
|
||||
"userAgent"
|
||||
"userAgent",
|
||||
"onLine"
|
||||
];
|
||||
|
||||
for (var prop in navigator) {
|
||||
|
65
dom/workers/test/onLine_worker.js
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
importScripts("onLine_worker_head.js");
|
||||
|
||||
var N_CHILDREN = 3;
|
||||
var children = [];
|
||||
var finishedChildrenCount = 0;
|
||||
var lastTest = false;
|
||||
|
||||
for (var event of ["online", "offline"]) {
|
||||
addEventListener(event,
|
||||
makeHandler(
|
||||
"addEventListener('%1', ..., false)",
|
||||
event, 1, "Parent Worker"),
|
||||
false);
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
if (e.data === 'lastTest') {
|
||||
children.forEach(function(w) {
|
||||
w.postMessage({ type: 'lastTest' });
|
||||
});
|
||||
lastTest = true;
|
||||
}
|
||||
}
|
||||
|
||||
function setupChildren(cb) {
|
||||
var readyCount = 0;
|
||||
for (var i = 0; i < N_CHILDREN; ++i) {
|
||||
var w = new Worker("onLine_worker_child.js");
|
||||
children.push(w);
|
||||
|
||||
w.onerror = function(e) {
|
||||
info("Error creating child " + e.message);
|
||||
}
|
||||
|
||||
w.onmessage = function(e) {
|
||||
if (e.data.type === 'ready') {
|
||||
info("Got ready from child");
|
||||
readyCount++;
|
||||
if (readyCount === N_CHILDREN) {
|
||||
cb();
|
||||
}
|
||||
} else if (e.data.type === 'finished') {
|
||||
finishedChildrenCount++;
|
||||
|
||||
if (lastTest && finishedChildrenCount === N_CHILDREN) {
|
||||
postMessage({ type: 'finished' });
|
||||
children = [];
|
||||
close();
|
||||
}
|
||||
} else if (e.data.type === 'ok') {
|
||||
// Pass on test to page.
|
||||
postMessage(e.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupChildren(function() {
|
||||
postMessage({ type: 'ready' });
|
||||
});
|
75
dom/workers/test/onLine_worker_child.js
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function info(text) {
|
||||
dump("Test for Bug 925437: worker: " + text + "\n");
|
||||
}
|
||||
|
||||
function ok(test, message) {
|
||||
postMessage({ type: 'ok', test: test, message: message });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handler function for an online/offline event. The returned handler
|
||||
* ensures the passed event object has expected properties and that the handler
|
||||
* is called at the right moment (according to the gState variable).
|
||||
* @param nameTemplate The string identifying the hanlder. '%1' in that
|
||||
* string will be replaced with the event name.
|
||||
* @param eventName 'online' or 'offline'
|
||||
* @param expectedState value of gState at the moment the handler is called.
|
||||
* The handler increases gState by one before checking
|
||||
* if it matches expectedState.
|
||||
*/
|
||||
function makeHandler(nameTemplate, eventName, expectedState, prefix, custom) {
|
||||
prefix += ": ";
|
||||
return function(e) {
|
||||
var name = nameTemplate.replace(/%1/, eventName);
|
||||
ok(e.constructor == Event, prefix + "event should be an Event");
|
||||
ok(e.type == eventName, prefix + "event type should be " + eventName);
|
||||
ok(!e.bubbles, prefix + "event should not bubble");
|
||||
ok(!e.cancelable, prefix + "event should not be cancelable");
|
||||
ok(e.target == self, prefix + "the event target should be the worker scope");
|
||||
ok(eventName == 'online' ? navigator.onLine : !navigator.onLine, prefix + "navigator.onLine " + navigator.onLine + " should reflect event " + eventName);
|
||||
|
||||
if (custom) {
|
||||
custom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var lastTest = false;
|
||||
|
||||
function lastTestTest() {
|
||||
if (lastTest) {
|
||||
postMessage({ type: 'finished' });
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
for (var event of ["online", "offline"]) {
|
||||
addEventListener(event,
|
||||
makeHandler(
|
||||
"addEventListener('%1', ..., false)",
|
||||
event, 1, "Child Worker", lastTestTest
|
||||
),
|
||||
false);
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
if (e.data.type === 'lastTest') {
|
||||
lastTest = true;
|
||||
} else if (e.data.type === 'navigatorState') {
|
||||
ok(e.data.state === navigator.onLine, "Child and parent navigator state should match");
|
||||
}
|
||||
}
|
||||
|
||||
postMessage({ type: 'ready' });
|
43
dom/workers/test/onLine_worker_head.js
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
function info(text) {
|
||||
dump("Test for Bug 925437: worker: " + text + "\n");
|
||||
}
|
||||
|
||||
function ok(test, message) {
|
||||
postMessage({ type: 'ok', test: test, message: message });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handler function for an online/offline event. The returned handler
|
||||
* ensures the passed event object has expected properties and that the handler
|
||||
* is called at the right moment (according to the gState variable).
|
||||
* @param nameTemplate The string identifying the hanlder. '%1' in that
|
||||
* string will be replaced with the event name.
|
||||
* @param eventName 'online' or 'offline'
|
||||
* @param expectedState value of gState at the moment the handler is called.
|
||||
* The handler increases gState by one before checking
|
||||
* if it matches expectedState.
|
||||
*/
|
||||
function makeHandler(nameTemplate, eventName, expectedState, prefix, custom) {
|
||||
prefix += ": ";
|
||||
return function(e) {
|
||||
var name = nameTemplate.replace(/%1/, eventName);
|
||||
ok(e.constructor == Event, prefix + "event should be an Event");
|
||||
ok(e.type == eventName, prefix + "event type should be " + eventName);
|
||||
ok(!e.bubbles, prefix + "event should not bubble");
|
||||
ok(!e.cancelable, prefix + "event should not be cancelable");
|
||||
ok(e.target == self, prefix + "the event target should be the worker scope");
|
||||
ok(eventName == 'online' ? navigator.onLine : !navigator.onLine, prefix + "navigator.onLine " + navigator.onLine + " should reflect event " + eventName);
|
||||
|
||||
if (custom) {
|
||||
custom();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
64
dom/workers/test/test_onLine.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 925437: online/offline events tests.
|
||||
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/licenses/publicdomain/
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 925437 (worker online/offline events)</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=925437">Mozilla Bug 925437</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
addLoadEvent(function() {
|
||||
var w = new Worker("onLine_worker.js");
|
||||
|
||||
w.onmessage = function(e) {
|
||||
if (e.data.type === 'ready') {
|
||||
doTest();
|
||||
} else if (e.data.type === 'ok') {
|
||||
ok(e.data.test, e.data.message);
|
||||
} else if (e.data.type === 'finished') {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
var iosvc = SpecialPowers.Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIIOService2);
|
||||
iosvc.manageOfflineStatus = false;
|
||||
|
||||
info("setting iosvc.offline = true");
|
||||
iosvc.offline = true;
|
||||
|
||||
info("setting iosvc.offline = false");
|
||||
iosvc.offline = false;
|
||||
|
||||
info("setting iosvc.offline = true");
|
||||
iosvc.offline = true;
|
||||
|
||||
for (var i = 0; i < 10; ++i) {
|
||||
iosvc.offline = !iosvc.offline;
|
||||
}
|
||||
|
||||
info("setting iosvc.offline = false");
|
||||
w.postMessage('lastTest');
|
||||
iosvc.offline = false;
|
||||
}
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +1,6 @@
|
||||
This directory contains the Graphite2 library from http://hg.palaso.org/graphitedev
|
||||
|
||||
Current version derived from upstream changeset 6b8ddb7d599f
|
||||
Current version derived from upstream changeset 1efd96aeade9
|
||||
|
||||
See gfx/graphite2/moz-gr-update.sh for update procedure.
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
#define GR2_VERSION_MAJOR 1
|
||||
#define GR2_VERSION_MINOR 2
|
||||
#define GR2_VERSION_BUGFIX 3
|
||||
#define GR2_VERSION_BUGFIX 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
@ -296,7 +296,7 @@ typedef struct gr_font_ops gr_font_ops;
|
||||
* @param appFontHandle font specific information that must stay alive as long
|
||||
* as the font does
|
||||
* @param font_ops pointer font specific callback structure for hinted metrics.
|
||||
* Must stay alive for the duration of the call.
|
||||
* Need only stay alive for the duration of the call.
|
||||
* @param face the face this font corresponds to. Must stay alive as long as
|
||||
* the font does.
|
||||
*/
|
||||
@ -310,7 +310,6 @@ GR2_API gr_font* gr_make_font_with_ops(float ppm, const void* appFontHandle, con
|
||||
* @param appFontHandle font specific information that must stay alive as long
|
||||
* as the font does
|
||||
* @param getAdvance callback function reference that returns horizontal advance in pixels for a glyph.
|
||||
* Must stay alive for the duration of the call.
|
||||
* @param face the face this font corresponds to. Must stay alive as long as
|
||||
* the font does.
|
||||
*/
|
||||
|
@ -125,6 +125,8 @@ enum gr_attrCode {
|
||||
gr_slatSegSplit = gr_slatJStretch + 29,
|
||||
/// User defined attribute, see subattr for user attr number
|
||||
gr_slatUserDefn,
|
||||
/// Bidi level
|
||||
gr_slatBidiLevel,
|
||||
|
||||
/// not implemented
|
||||
gr_slatMax,
|
||||
@ -327,8 +329,8 @@ GR2_API const gr_slot* gr_slot_first_attachment(const gr_slot* p);
|
||||
*
|
||||
* This returns the next slot in the singly linked list of slots attached to this
|
||||
* slot's parent. If there are no more such slots, NULL is returned. If there is
|
||||
* no parent, i.e. the passed slot is a base, then the next base in graphical order
|
||||
* (ltr even for rtl text) is returned.
|
||||
* no parent, i.e. the passed slot is a cluster base, then the next cluster base
|
||||
* in graphical order (ltr, even for rtl text) is returned.
|
||||
*
|
||||
* if gr_slot_next_sibling_attachment(p) != NULL then gr_slot_attached_to(gr_slot_next_sibling_attachment(p)) == gr_slot_attached_to(p).
|
||||
*/
|
||||
@ -398,7 +400,13 @@ GR2_API unsigned int gr_slot_index(const gr_slot* p/*not NULL*/);
|
||||
*/
|
||||
GR2_API int gr_slot_attr(const gr_slot* p/*not NULL*/, const gr_segment* pSeg/*not NULL*/, enum gr_attrCode index, gr_uint8 subindex); //tbd - do we need to expose this?
|
||||
|
||||
/** Returns whether text may be inserted before this glyph [check this isn't inverted] **/
|
||||
/** Returns whether text may be inserted before this glyph.
|
||||
*
|
||||
* This indicates whether a cursor can be put before this slot. It applies to
|
||||
* base glyphs that have no parent as well as attached glyphs that have the
|
||||
* .insert attribute explicitly set to true. This is the primary mechanism
|
||||
* for identifying contiguous sequences of base plus diacritics.
|
||||
*/
|
||||
GR2_API int gr_slot_can_insert_before(const gr_slot* p);
|
||||
|
||||
/** Returns the original gr_char_info index this slot refers to.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -27,6 +27,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Main.h"
|
||||
#include "inc/Slot.h"
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/Bidi.h"
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
@ -50,106 +51,273 @@ enum DirCode { // Hungarian: dirc
|
||||
RLE = 14, // RTL embedding
|
||||
PDF = 15, // pop directional format
|
||||
NSM = 16, // non-space mark
|
||||
LRI = 17, // LRI isolate
|
||||
RLI = 18, // RLI isolate
|
||||
FSI = 19, // FSI isolate
|
||||
PDI = 20, // pop isolate
|
||||
OPP = 21, // opening paired parenthesis
|
||||
CPP = 22, // closing paired parenthesis
|
||||
|
||||
ON = N
|
||||
};
|
||||
|
||||
enum DirMask {
|
||||
Nmask = 1,
|
||||
Lmask = 2,
|
||||
Rmask = 4,
|
||||
ALmask = 8,
|
||||
ENmask = 0x10,
|
||||
ESmask = 0x20,
|
||||
ETmask = 0x40,
|
||||
ANmask = 0x80,
|
||||
CSmask = 0x100,
|
||||
WSmask = 0x200,
|
||||
BNmask = 0x400,
|
||||
LROmask = 0x800,
|
||||
RLOmask = 0x1000,
|
||||
LREmask = 0x2000,
|
||||
RLEmask = 0x4000,
|
||||
PDFmask = 0x8000,
|
||||
NSMmask = 0x10000
|
||||
WSflag = (1 << 7), // keep track of WS for eos handling
|
||||
WSMask = ~(1 << 7)
|
||||
};
|
||||
|
||||
unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6 };
|
||||
// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag.
|
||||
#define MAX_LEVEL 61
|
||||
inline uint8 BaseClass(Slot *s) { return s->getBidiClass() & WSMask; }
|
||||
|
||||
Slot *resolveExplicit(int level, int dir, Slot *s, int nNest = 0)
|
||||
unsigned int bidi_class_map[] = { 0, 1, 2, 5, 4, 8, 9, 3, 7, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0 };
|
||||
// Algorithms based on Unicode reference standard code. Thanks Asmus Freitag.
|
||||
|
||||
void resolveWeak(Slot *start, int sos, int eos);
|
||||
void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos);
|
||||
void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack);
|
||||
|
||||
inline int calc_base_level(Slot *s)
|
||||
{
|
||||
int nLastValid = nNest;
|
||||
Slot *res = NULL;
|
||||
for ( ; s && !res; s = s->next())
|
||||
int count = 0;
|
||||
for ( ; s; s = s->next())
|
||||
{
|
||||
int cls = s->getBidiClass();
|
||||
switch(cls)
|
||||
if (count)
|
||||
{
|
||||
case LRO:
|
||||
case LRE:
|
||||
nNest++;
|
||||
if (level & 1)
|
||||
s->setBidiLevel(level + 1);
|
||||
else
|
||||
s->setBidiLevel(level + 2);
|
||||
if (s->getBidiLevel() > MAX_LEVEL)
|
||||
s->setBidiLevel(level);
|
||||
else
|
||||
switch(cls)
|
||||
{
|
||||
s = resolveExplicit(s->getBidiLevel(), (cls == LRE ? N : L), s->next(), nNest);
|
||||
nNest--;
|
||||
if (s) continue; else break;
|
||||
case LRI :
|
||||
case RLI :
|
||||
case FSI :
|
||||
++count;
|
||||
break;
|
||||
case PDI :
|
||||
--count;
|
||||
}
|
||||
cls = BN;
|
||||
s->setBidiClass(cls);
|
||||
break;
|
||||
|
||||
case RLO:
|
||||
case RLE:
|
||||
nNest++;
|
||||
if (level & 1)
|
||||
s->setBidiLevel(level + 2);
|
||||
else
|
||||
s->setBidiLevel(level + 1);
|
||||
if (s->getBidiLevel() > MAX_LEVEL)
|
||||
s->setBidiLevel(level);
|
||||
else
|
||||
{
|
||||
s = resolveExplicit(s->getBidiLevel(), (cls == RLE ? N : R), s->next(), nNest);
|
||||
nNest--;
|
||||
if (s) continue; else break;
|
||||
}
|
||||
cls = BN;
|
||||
s->setBidiClass(cls);
|
||||
break;
|
||||
|
||||
case PDF:
|
||||
cls = BN;
|
||||
s->setBidiClass(cls);
|
||||
if (nNest)
|
||||
{
|
||||
if (nLastValid < nNest)
|
||||
--nNest;
|
||||
else
|
||||
res = s;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (dir != N)
|
||||
cls = dir;
|
||||
if (s)
|
||||
{
|
||||
s->setBidiLevel(level);
|
||||
if (s->getBidiClass() != BN)
|
||||
s->setBidiClass(cls);
|
||||
}
|
||||
else
|
||||
break;
|
||||
{
|
||||
switch(cls)
|
||||
{
|
||||
case L :
|
||||
return 0;
|
||||
case R :
|
||||
case AL :
|
||||
return 1;
|
||||
case LRI :
|
||||
case RLI :
|
||||
case FSI :
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// inline or not?
|
||||
void do_resolves(Slot *start, int level, int sos, int eos, int &bmask, Segment *seg, uint8 aMirror, BracketPairStack &stack)
|
||||
{
|
||||
if (bmask & 0x1F1178)
|
||||
resolveWeak(start, sos, eos);
|
||||
if (bmask & 0x200000)
|
||||
processParens(start, seg, aMirror, level, stack);
|
||||
if (bmask & 0x7E0361)
|
||||
resolveNeutrals(start, level, sos, eos);
|
||||
bmask = 0;
|
||||
}
|
||||
|
||||
enum maxs
|
||||
{
|
||||
MAX_LEVEL = 125,
|
||||
};
|
||||
|
||||
// returns where we are up to in processing
|
||||
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 &bstack)
|
||||
{
|
||||
int bmask = 0;
|
||||
Slot *s = start;
|
||||
Slot *slast = start;
|
||||
Slot *scurr = 0;
|
||||
Slot *stemp;
|
||||
int lnextLevel = nextLevel;
|
||||
int newLevel;
|
||||
int empty = 1;
|
||||
for ( ; s; s = s ? s->next() : s)
|
||||
{
|
||||
int cls = s->getBidiClass();
|
||||
bmask |= (1 << cls);
|
||||
s->setBidiLevel(level);
|
||||
// we keep s->prev() pointing backwards for PDI repeating
|
||||
|
||||
switch (cls)
|
||||
{
|
||||
case BN :
|
||||
if (slast == s) slast = s->next(); // ignore if at front of text
|
||||
continue;
|
||||
case LRE :
|
||||
case LRO :
|
||||
case RLE :
|
||||
case RLO :
|
||||
switch (cls)
|
||||
{
|
||||
case LRE :
|
||||
case LRO :
|
||||
newLevel = level + (level & 1 ? 1 : 2);
|
||||
break;
|
||||
case RLE :
|
||||
case RLO :
|
||||
newLevel = level + (level & 1 ? 2 : 1);
|
||||
break;
|
||||
}
|
||||
s->setBidiClass(BN);
|
||||
if (isolerr || newLevel > MAX_LEVEL || embederr)
|
||||
{
|
||||
if (!isolerr) ++embederr;
|
||||
break;
|
||||
}
|
||||
stemp = scurr;
|
||||
if (scurr)
|
||||
scurr->prev(0); // don't include control in string
|
||||
lnextLevel = newLevel;
|
||||
scurr = s;
|
||||
s->setBidiLevel(newLevel); // to make it vanish
|
||||
// recurse for the new subsequence. A sequence only contains text at the same level
|
||||
s = process_bidi(s->next(), newLevel, level, lnextLevel, cls < LRE, 0, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
|
||||
// s points at PDF or end of sequence
|
||||
// try to keep extending the run and not process it until we have to
|
||||
if (lnextLevel != level || !s) // if the subsequence really had something in it, or we are at the end of the run
|
||||
{
|
||||
if (slast != scurr) // process the run now, don't try to extend it
|
||||
{
|
||||
// process text preceeding embedding
|
||||
do_resolves(slast, level, (prelevel > level ? prelevel : level) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
|
||||
empty = 0;
|
||||
nextLevel = level;
|
||||
}
|
||||
else if (lnextLevel != level) // the subsequence had something
|
||||
{
|
||||
empty = 0; // so we aren't empty either
|
||||
nextLevel = lnextLevel; // but since we really are empty, pass back our level from the subsequence
|
||||
}
|
||||
if (s) // if still more to process
|
||||
{
|
||||
prelevel = lnextLevel; // future text starts out with sos of the higher subsequence
|
||||
lnextLevel = level; // and eos is our level
|
||||
}
|
||||
slast = s ? s->next() : s;
|
||||
}
|
||||
else if (stemp)
|
||||
stemp->prev(s);
|
||||
break;
|
||||
|
||||
case PDF :
|
||||
s->setBidiClass(BN);
|
||||
s->prev(0); // unstitch us since we skip final stitching code when we return
|
||||
if (isol || isolerr || init) // boundary error conditions
|
||||
break;
|
||||
if (embederr)
|
||||
{
|
||||
--embederr;
|
||||
break;
|
||||
}
|
||||
if (slast != s)
|
||||
{
|
||||
scurr->prev(0); // if slast, then scurr. Terminate before here
|
||||
do_resolves(slast, level, level & 1, level & 1, bmask, seg, aMirror, bstack);
|
||||
empty = 0;
|
||||
}
|
||||
if (empty)
|
||||
{
|
||||
nextLevel = prelevel; // no contents? set our level to that of parent
|
||||
s->setBidiLevel(prelevel);
|
||||
}
|
||||
return s;
|
||||
|
||||
case FSI :
|
||||
case LRI :
|
||||
case RLI :
|
||||
switch (cls)
|
||||
{
|
||||
case FSI :
|
||||
if (calc_base_level(s->next()))
|
||||
newLevel = level + (level & 1 ? 2 : 1);
|
||||
else
|
||||
newLevel = level + (level & 1 ? 1 : 2);
|
||||
break;
|
||||
case LRI :
|
||||
newLevel = level + (level & 1 ? 1 : 2);
|
||||
break;
|
||||
case RLI :
|
||||
newLevel = level + (level & 1 ? 2 : 1);
|
||||
break;
|
||||
}
|
||||
if (newLevel > MAX_LEVEL || isolerr)
|
||||
{
|
||||
++isolerr;
|
||||
s->setBidiClass(ON | WSflag);
|
||||
break;
|
||||
}
|
||||
++cisol;
|
||||
if (scurr) scurr->prev(s);
|
||||
scurr = s; // include FSI
|
||||
lnextLevel = newLevel;
|
||||
// recurse for the new sub sequence
|
||||
s = process_bidi(s->next(), newLevel, newLevel, lnextLevel, 0, 1, cisol, isolerr, embederr, 0, seg, aMirror, bstack);
|
||||
// s points at PDI
|
||||
if (s)
|
||||
{
|
||||
bmask |= 1 << BaseClass(s); // include the PDI in the mask
|
||||
s->setBidiLevel(level); // reset its level to our level
|
||||
}
|
||||
lnextLevel = level;
|
||||
break;
|
||||
|
||||
case PDI :
|
||||
if (isolerr)
|
||||
{
|
||||
--isolerr;
|
||||
s->setBidiClass(ON | WSflag);
|
||||
break;
|
||||
}
|
||||
if (init || !cisol)
|
||||
{
|
||||
s->setBidiClass(ON | WSflag);
|
||||
break;
|
||||
}
|
||||
embederr = 0;
|
||||
if (!isol) // we are in an embedded subsequence, we have to return through all those
|
||||
{
|
||||
if (empty) // if empty, reset the level to tell embedded parent
|
||||
nextLevel = prelevel;
|
||||
return s->prev(); // keep working up the stack pointing at this PDI until we get to an isolate entry
|
||||
}
|
||||
else // we are terminating an isolate sequence
|
||||
{
|
||||
if (slast != s) // process any remaining content in this subseqence
|
||||
{
|
||||
scurr->prev(0);
|
||||
do_resolves(slast, level, prelevel & 1, level & 1, bmask, seg, aMirror, bstack);
|
||||
}
|
||||
--cisol; // pop the isol sequence from the stack
|
||||
return s;
|
||||
}
|
||||
|
||||
default :
|
||||
if (dirover)
|
||||
s->setBidiClass((level & 1 ? R : L) | (WSflag * (cls == WS)));
|
||||
}
|
||||
if (s) s->prev(0); // unstitch us
|
||||
if (scurr) // stitch in text for processing
|
||||
scurr->prev(s);
|
||||
scurr = s; // add us to text to process
|
||||
}
|
||||
if (slast != s)
|
||||
{
|
||||
do_resolves(slast, level, (level > prelevel ? level : prelevel) & 1, lnextLevel & 1, bmask, seg, aMirror, bstack);
|
||||
empty = 0;
|
||||
}
|
||||
if (empty || isol)
|
||||
nextLevel = prelevel;
|
||||
return s;
|
||||
}
|
||||
|
||||
// === RESOLVE WEAK TYPES ================================================
|
||||
@ -183,30 +351,6 @@ enum bidi_state // possible states
|
||||
let, // ET following le
|
||||
} ;
|
||||
|
||||
enum bidi_state_mask
|
||||
{
|
||||
xamask = 1,
|
||||
xrmask = 2,
|
||||
xlmask = 4,
|
||||
aomask = 8,
|
||||
romask = 0x10,
|
||||
lomask = 0x20,
|
||||
rtmask = 0x40,
|
||||
ltmask = 0x80,
|
||||
cnmask = 0x100,
|
||||
ramask = 0x200,
|
||||
remask = 0x400,
|
||||
lamask = 0x800,
|
||||
lemask = 0x1000,
|
||||
acmask = 0x2000,
|
||||
rcmask = 0x4000,
|
||||
rsmask = 0x8000,
|
||||
lcmask = 0x10000,
|
||||
lsmask = 0x20000,
|
||||
retmask = 0x40000,
|
||||
letmask = 0x80000
|
||||
};
|
||||
|
||||
const bidi_state stateWeak[][10] =
|
||||
{
|
||||
// N, L, R, AN, EN, AL,NSM, CS, ES, ET,
|
||||
@ -233,8 +377,8 @@ const bidi_state stateWeak[][10] =
|
||||
{ /*lc*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS following la */ },
|
||||
{ /*ls*/ lo, xl, xr, la, le, xa, lo, lo, lo, lt, /* CS,ES following le */ },
|
||||
|
||||
{ /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re */ },
|
||||
{ /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le */ },
|
||||
{ /*ret*/ ro, xl, xr, ra, re, xa,ret, ro, ro,ret, /* ET following re */ },
|
||||
{ /*let*/ lo, xl, xr, la, le, xa,let, lo, lo,let, /* ET following le */ },
|
||||
|
||||
|
||||
};
|
||||
@ -269,7 +413,7 @@ enum bidi_action // possible actions
|
||||
|
||||
const bidi_action actionWeak[][10] =
|
||||
{
|
||||
// N,.. L, R, AN, EN, AL, NSM, CS,..ES, ET,
|
||||
// N,.. L, R, AN, EN, AL, NSM, CS,..ES, ET,
|
||||
{ /*xa*/ xxx, xxx, xxx, xxx, xxA, xxR, xxR, xxN, xxN, xxN, /* arabic letter */ },
|
||||
{ /*xr*/ xxx, xxx, xxx, xxx, xxE, xxR, xxR, xxN, xxN, xIx, /* right leter */ },
|
||||
{ /*xl*/ xxx, xxx, xxx, xxx, xxL, xxR, xxL, xxN, xxN, xIx, /* left letter */ },
|
||||
@ -300,66 +444,6 @@ const bidi_action actionWeak[][10] =
|
||||
inline uint8 GetDeferredType(bidi_action a) { return (a >> 4) & 0xF; }
|
||||
inline uint8 GetResolvedType(bidi_action a) { return a & 0xF; }
|
||||
inline DirCode EmbeddingDirection(int l) { return l & 1 ? R : L; }
|
||||
inline bool IsDeferredState(bidi_state a) { return 0 != ((1 << a) & (rtmask | ltmask | acmask | rcmask | rsmask | lcmask | lsmask)); }
|
||||
inline bool IsModifiedClass(DirCode a) { return 0 != ((1 << a) & (ALmask | NSMmask | ESmask | CSmask | ETmask | ENmask)); }
|
||||
|
||||
void SetDeferredRunClass(Slot *s, Slot *sRun, int nval)
|
||||
{
|
||||
if (!sRun || s == sRun) return;
|
||||
for (Slot *p = s->prev(); p != sRun; p = p->prev())
|
||||
p->setBidiClass(nval);
|
||||
}
|
||||
|
||||
void resolveWeak(int baseLevel, Slot *s)
|
||||
{
|
||||
int state = (baseLevel & 1) ? xr : xl;
|
||||
int cls;
|
||||
int level = baseLevel;
|
||||
Slot *sRun = NULL;
|
||||
Slot *sLast = s;
|
||||
|
||||
for ( ; s; s = s->next())
|
||||
{
|
||||
sLast = s;
|
||||
cls = s->getBidiClass();
|
||||
if (cls == BN)
|
||||
{
|
||||
s->setBidiLevel(level);
|
||||
if (!s->next() && level != baseLevel)
|
||||
s->setBidiClass(EmbeddingDirection(level));
|
||||
else if (s->next() && level != s->next()->getBidiLevel() && s->next()->getBidiClass() != BN)
|
||||
{
|
||||
int newLevel = s->next()->getBidiLevel();
|
||||
if (level > newLevel)
|
||||
newLevel = level;
|
||||
s->setBidiLevel(newLevel);
|
||||
s->setBidiClass(EmbeddingDirection(newLevel));
|
||||
level = s->next()->getBidiLevel();
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
|
||||
bidi_action action = actionWeak[state][bidi_class_map[cls]];
|
||||
int clsRun = GetDeferredType(action);
|
||||
if (clsRun != XX)
|
||||
{
|
||||
SetDeferredRunClass(s, sRun, clsRun);
|
||||
sRun = NULL;
|
||||
}
|
||||
int clsNew = GetResolvedType(action);
|
||||
if (clsNew != XX)
|
||||
s->setBidiClass(clsNew);
|
||||
if (!sRun && (IX & action))
|
||||
sRun = s->prev();
|
||||
state = stateWeak[state][bidi_class_map[cls]];
|
||||
}
|
||||
|
||||
cls = EmbeddingDirection(level);
|
||||
int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
|
||||
if (clsRun != XX)
|
||||
SetDeferredRunClass(sLast, sRun, clsRun);
|
||||
}
|
||||
|
||||
// Neutrals
|
||||
enum neutral_action
|
||||
@ -373,6 +457,151 @@ enum neutral_action
|
||||
LnL = (1<<4)+L, // set run and EN to L
|
||||
};
|
||||
|
||||
// ->prev() here means ->next()
|
||||
void SetDeferredRunClass(Slot *s, Slot *sRun, int nval)
|
||||
{
|
||||
if (!sRun || s == sRun) return;
|
||||
for (Slot *p = sRun; p != s; p = p->prev())
|
||||
if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
|
||||
else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
|
||||
}
|
||||
|
||||
void SetThisDeferredRunClass(Slot *s, Slot *sRun, int nval)
|
||||
{
|
||||
if (!sRun) return;
|
||||
for (Slot *p = sRun, *e = s->prev(); p != e; p = p->prev())
|
||||
if (p->getBidiClass() == WS) p->setBidiClass(nval | WSflag);
|
||||
else if (BaseClass(p) != BN) p->setBidiClass(nval | (p->getBidiClass() & WSflag));
|
||||
}
|
||||
|
||||
void resolveWeak(Slot *start, int sos, int eos)
|
||||
{
|
||||
int state = (sos & 1) ? xr : xl;
|
||||
int cls;
|
||||
Slot *s = start;
|
||||
Slot *sRun = NULL;
|
||||
Slot *sLast = s;
|
||||
|
||||
for ( ; s; s = s->prev())
|
||||
{
|
||||
sLast = s;
|
||||
cls = BaseClass(s);
|
||||
switch (cls)
|
||||
{
|
||||
case BN :
|
||||
if (s == start) start = s->prev(); // skip initial BNs for NSM resolving
|
||||
continue;
|
||||
case LRI :
|
||||
case RLI :
|
||||
case FSI :
|
||||
case PDI :
|
||||
{
|
||||
Slot *snext = s->prev();
|
||||
if (snext && snext->getBidiClass() == NSM)
|
||||
snext->setBidiClass(ON);
|
||||
s->setBidiClass(ON | WSflag);
|
||||
}
|
||||
break;
|
||||
|
||||
case NSM :
|
||||
if (s == start)
|
||||
{
|
||||
cls = EmbeddingDirection(sos);
|
||||
s->setBidiClass(cls);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
bidi_action action = actionWeak[state][bidi_class_map[cls]];
|
||||
int clsRun = GetDeferredType(action);
|
||||
if (clsRun != XX)
|
||||
{
|
||||
SetDeferredRunClass(s, sRun, clsRun);
|
||||
sRun = NULL;
|
||||
}
|
||||
int clsNew = GetResolvedType(action);
|
||||
if (clsNew != XX)
|
||||
s->setBidiClass(clsNew);
|
||||
if (!sRun && (IX & action))
|
||||
sRun = s;
|
||||
state = stateWeak[state][bidi_class_map[cls]];
|
||||
}
|
||||
|
||||
cls = EmbeddingDirection(eos);
|
||||
int clsRun = GetDeferredType(actionWeak[state][bidi_class_map[cls]]);
|
||||
if (clsRun != XX)
|
||||
SetThisDeferredRunClass(sLast, sRun, clsRun);
|
||||
}
|
||||
|
||||
void processParens(Slot *s, Segment *seg, uint8 aMirror, int level, BracketPairStack &stack)
|
||||
{
|
||||
uint8 mask = 0;
|
||||
int8 lastDir = -1;
|
||||
BracketPair *p;
|
||||
for ( ; s; s = s->prev()) // walk the sequence
|
||||
{
|
||||
uint16 ogid = seg->glyphAttr(s->gid(), aMirror);
|
||||
int cls = BaseClass(s);
|
||||
|
||||
switch(cls)
|
||||
{
|
||||
case OPP :
|
||||
stack.orin(mask);
|
||||
stack.push(ogid, s, lastDir, lastDir != CPP);
|
||||
mask = 0;
|
||||
lastDir = OPP;
|
||||
break;
|
||||
case CPP :
|
||||
stack.orin(mask);
|
||||
p = stack.scan(s->gid());
|
||||
if (!p) break;
|
||||
mask = 0;
|
||||
stack.close(p, s);
|
||||
lastDir = CPP;
|
||||
break;
|
||||
case L :
|
||||
lastDir = L;
|
||||
mask |= 1;
|
||||
break;
|
||||
case R :
|
||||
case AL :
|
||||
case AN :
|
||||
case EN :
|
||||
lastDir = R;
|
||||
mask |= 2;
|
||||
}
|
||||
}
|
||||
for (p = stack.start(); p; p =p->next()) // walk the stack
|
||||
{
|
||||
if (p->close() && p->mask())
|
||||
{
|
||||
int dir = (level & 1) + 1;
|
||||
if (p->mask() & dir)
|
||||
{ }
|
||||
else if (p->mask() & (1 << (~level & 1))) // if inside has strong other embedding
|
||||
{
|
||||
int ldir = p->before();
|
||||
if ((p->before() == OPP || p->before() == CPP) && p->prev())
|
||||
{
|
||||
for (BracketPair *q = p->prev(); q; q = q->prev())
|
||||
{
|
||||
ldir = q->open()->getBidiClass();
|
||||
if (ldir < 3) break;
|
||||
ldir = q->before();
|
||||
if (ldir < 3) break;
|
||||
}
|
||||
if (ldir > 2) ldir = 0;
|
||||
}
|
||||
if (ldir > 0 && (ldir - 1) != (level & 1)) // is dir given opp. to level dir (ldir == R or L)
|
||||
dir = (~level & 1) + 1;
|
||||
}
|
||||
p->open()->setBidiClass(dir);
|
||||
p->close()->setBidiClass(dir);
|
||||
}
|
||||
}
|
||||
stack.clear();
|
||||
}
|
||||
|
||||
int GetDeferredNeutrals(int action, int level)
|
||||
{
|
||||
action = (action >> 4) & 0xF;
|
||||
@ -384,11 +613,7 @@ int GetDeferredNeutrals(int action, int level)
|
||||
|
||||
int GetResolvedNeutrals(int action)
|
||||
{
|
||||
action = action & 0xF;
|
||||
if (action == In)
|
||||
return 0;
|
||||
else
|
||||
return action;
|
||||
return action & 0xF;
|
||||
}
|
||||
|
||||
// state values
|
||||
@ -403,12 +628,11 @@ enum neutral_state
|
||||
na, // N preceeded by a
|
||||
} ;
|
||||
|
||||
const uint8 neutral_class_map[] = { 0, 1, 2, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
const uint8 neutral_class_map[] = { 0, 1, 2, 0, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
const int actionNeutrals[][5] =
|
||||
{
|
||||
// N, L, R, AN, EN, = cls
|
||||
// state =
|
||||
// cls= N, L, R, AN, EN, state =
|
||||
{ In, 0, 0, 0, 0, }, // r right
|
||||
{ In, 0, 0, 0, L, }, // l left
|
||||
|
||||
@ -421,8 +645,7 @@ const int actionNeutrals[][5] =
|
||||
|
||||
const int stateNeutrals[][5] =
|
||||
{
|
||||
// N, L, R, AN, EN = cls
|
||||
// state =
|
||||
// cls= N, L, R, AN, EN state =
|
||||
{ rn, l, r, r, r, }, // r right
|
||||
{ ln, l, r, a, l, }, // l left
|
||||
|
||||
@ -433,50 +656,53 @@ const int stateNeutrals[][5] =
|
||||
{ na, l, r, a, l, }, // na N preceded by la
|
||||
} ;
|
||||
|
||||
void resolveNeutrals(int baseLevel, Slot *s)
|
||||
void resolveNeutrals(Slot *s, int baseLevel, int sos, int eos)
|
||||
{
|
||||
int state = baseLevel ? r : l;
|
||||
int state = (sos & 1) ? r : l;
|
||||
int cls;
|
||||
Slot *sRun = NULL;
|
||||
Slot *sLast = s;
|
||||
int level = baseLevel;
|
||||
|
||||
for ( ; s; s = s->next())
|
||||
for ( ; s; s = s->prev())
|
||||
{
|
||||
sLast = s;
|
||||
cls = s->getBidiClass();
|
||||
if (cls == BN)
|
||||
cls = BaseClass(s);
|
||||
switch (cls)
|
||||
{
|
||||
if (sRun)
|
||||
sRun = sRun->prev();
|
||||
case BN :
|
||||
continue;
|
||||
case LRI :
|
||||
case RLI :
|
||||
case FSI :
|
||||
s->setBidiClass(BN | WSflag);
|
||||
continue;
|
||||
}
|
||||
|
||||
int action = actionNeutrals[state][neutral_class_map[cls]];
|
||||
int clsRun = GetDeferredNeutrals(action, level);
|
||||
if (clsRun != N)
|
||||
{
|
||||
SetDeferredRunClass(s, sRun, clsRun);
|
||||
sRun = NULL;
|
||||
default :
|
||||
int action = actionNeutrals[state][neutral_class_map[cls]];
|
||||
int clsRun = GetDeferredNeutrals(action, level);
|
||||
if (clsRun != N)
|
||||
{
|
||||
SetDeferredRunClass(s, sRun, clsRun);
|
||||
sRun = NULL;
|
||||
}
|
||||
int clsNew = GetResolvedNeutrals(action);
|
||||
if (clsNew != N)
|
||||
s->setBidiClass(clsNew);
|
||||
if (!sRun && (action & In))
|
||||
sRun = s;
|
||||
state = stateNeutrals[state][neutral_class_map[cls]];
|
||||
}
|
||||
int clsNew = GetResolvedNeutrals(action);
|
||||
if (clsNew != N)
|
||||
s->setBidiClass(clsNew);
|
||||
if (!sRun && (action & In))
|
||||
sRun = s->prev();
|
||||
state = stateNeutrals[state][neutral_class_map[cls]];
|
||||
level = s->getBidiLevel();
|
||||
}
|
||||
cls = EmbeddingDirection(level);
|
||||
cls = EmbeddingDirection(eos);
|
||||
int clsRun = GetDeferredNeutrals(actionNeutrals[state][neutral_class_map[cls]], level);
|
||||
if (clsRun != N)
|
||||
SetDeferredRunClass(sLast, sRun, clsRun);
|
||||
SetThisDeferredRunClass(sLast, sRun, clsRun);
|
||||
}
|
||||
|
||||
const int addLevel[][4] =
|
||||
{
|
||||
// L, R, AN, EN = cls
|
||||
// level =
|
||||
// cls = L, R, AN, EN level =
|
||||
/* even */ { 0, 1, 2, 2, }, // EVEN
|
||||
/* odd */ { 1, 0, 1, 1, }, // ODD
|
||||
|
||||
@ -485,45 +711,51 @@ const int addLevel[][4] =
|
||||
void resolveImplicit(Slot *s, Segment *seg, uint8 aMirror)
|
||||
{
|
||||
bool rtl = seg->dir() & 1;
|
||||
int level = rtl;
|
||||
Slot *slast = 0;
|
||||
for ( ; s; s = s->next())
|
||||
{
|
||||
int cls = s->getBidiClass();
|
||||
if (cls == BN)
|
||||
continue;
|
||||
else if (cls == AN)
|
||||
cls = AL;
|
||||
int cls = BaseClass(s);
|
||||
s->prev(slast); // restitch the prev() side of the doubly linked list
|
||||
slast = s;
|
||||
if (cls == AN)
|
||||
cls = AL; // use AL value as the index for AN, no property change
|
||||
if (cls < 5 && cls > 0)
|
||||
{
|
||||
int level = s->getBidiLevel();
|
||||
level = s->getBidiLevel();
|
||||
level += addLevel[level & 1][cls - 1];
|
||||
s->setBidiLevel(level);
|
||||
if (aMirror)
|
||||
}
|
||||
if (aMirror)
|
||||
{
|
||||
int hasChar = seg->glyphAttr(s->gid(), aMirror + 1);
|
||||
if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar))
|
||||
|| ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) )
|
||||
{
|
||||
int hasChar = seg->glyphAttr(s->gid(), aMirror + 1);
|
||||
if ( ((level & 1) && (!(seg->dir() & 4) || !hasChar))
|
||||
|| ((rtl ^ (level & 1)) && (seg->dir() & 4) && hasChar) )
|
||||
{
|
||||
unsigned short g = seg->glyphAttr(s->gid(), aMirror);
|
||||
if (g) s->setGlyph(seg, g);
|
||||
}
|
||||
unsigned short g = seg->glyphAttr(s->gid(), aMirror);
|
||||
if (g) s->setGlyph(seg, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void resolveWhitespace(int baseLevel, Segment *seg, uint8 aBidi, Slot *s)
|
||||
void resolveWhitespace(int baseLevel, Slot *s)
|
||||
{
|
||||
for ( ; s; s = s->prev())
|
||||
{
|
||||
int cls = seg->glyphAttr(s->gid(), aBidi);
|
||||
if (cls == WS)
|
||||
int8 cls = s->getBidiClass();
|
||||
if (cls == WS || cls & WSflag)
|
||||
s->setBidiLevel(baseLevel);
|
||||
else
|
||||
else if (cls != BN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Stitch two spans together to make another span (with ends tied together).
|
||||
If the level is odd then swap the order of the two spans
|
||||
*/
|
||||
inline
|
||||
Slot * join(int level, Slot * a, Slot * b)
|
||||
{
|
||||
@ -535,14 +767,19 @@ Slot * join(int level, Slot * a, Slot * b)
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Given the first slot in a run of slots with the same bidi level, turn the run
|
||||
into it's own little doubly linked list ring (a span) with the two ends joined together.
|
||||
If the run is rtl then reverse its direction.
|
||||
Returns the first slot after the span
|
||||
*/
|
||||
Slot * span(Slot * & cs, const bool rtl)
|
||||
{
|
||||
Slot * r = cs, * re = cs; cs = cs->next();
|
||||
if (rtl)
|
||||
{
|
||||
Slot * t = r->next(); r->next(r->prev()); r->prev(t);
|
||||
for (int l = r->getBidiLevel(); cs && l == cs->getBidiLevel(); cs = cs->prev())
|
||||
for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->prev())
|
||||
{
|
||||
re = cs;
|
||||
t = cs->next(); cs->next(cs->prev()); cs->prev(t);
|
||||
@ -553,7 +790,7 @@ Slot * span(Slot * & cs, const bool rtl)
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int l = r->getBidiLevel(); cs && l == cs->getBidiLevel(); cs = cs->next())
|
||||
for (int l = r->getBidiLevel(); cs && (l == cs->getBidiLevel() || cs->getBidiClass() == BN); cs = cs->next())
|
||||
re = cs;
|
||||
r->prev(re);
|
||||
re->next(r);
|
||||
@ -562,17 +799,25 @@ Slot * span(Slot * & cs, const bool rtl)
|
||||
return r;
|
||||
}
|
||||
|
||||
inline int getlevel(const Slot *cs, const int level)
|
||||
{
|
||||
while (cs && cs->getBidiClass() == BN)
|
||||
{ cs = cs->next(); }
|
||||
if (cs)
|
||||
return cs->getBidiLevel();
|
||||
else
|
||||
return level;
|
||||
}
|
||||
|
||||
Slot *resolveOrder(Slot * & cs, const bool reordered, const int level)
|
||||
{
|
||||
Slot * r = 0;
|
||||
int ls;
|
||||
while (cs && level <= (ls = cs->getBidiLevel() - reordered))
|
||||
while (cs && level <= (ls = getlevel(cs, level) - reordered))
|
||||
{
|
||||
r = join(level, r, level >= ls
|
||||
? span(cs, level & 1)
|
||||
: resolveOrder(cs, reordered, level+1));
|
||||
r = join(level, r, level < ls
|
||||
? resolveOrder(/* updates */cs, reordered, level+1) // find span of heighest level
|
||||
: span(/* updates */cs, level & 1));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -104,15 +104,25 @@ 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"
|
||||
LINK_FLAGS "-nodefaultlibs"
|
||||
LINK_FLAGS "-nodefaultlibs ${GRAPHITE_LINK_FLAGS}"
|
||||
LINKER_LANGUAGE C)
|
||||
if (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
|
||||
target_link_libraries(graphite2 kernel32 msvcr90 mingw32 gcc user32)
|
||||
else (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
|
||||
target_link_libraries(graphite2 c gcc)
|
||||
if (GRAPHITE2_ASAN)
|
||||
target_link_libraries(graphite2 c gcc_s)
|
||||
else (GRAPHITE2_ASAN)
|
||||
target_link_libraries(graphite2 c gcc)
|
||||
endif (GRAPHITE2_ASAN)
|
||||
include(Graphite)
|
||||
nolib_test(stdc++ $<TARGET_SONAME_FILE:graphite2>)
|
||||
endif (${CMAKE_CXX_COMPILER} MATCHES ".*mingw.*")
|
||||
|
@ -61,7 +61,7 @@ bool CachedFace::runGraphite(Segment *seg, const Silf *pSilf) const
|
||||
if (silfIndex == m_numSilf) return false;
|
||||
SegCache * const segCache = m_cacheStore->getOrCreate(silfIndex, seg->getFeatures(0));
|
||||
if (!segCache)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
assert(m_cacheStore);
|
||||
// find where the segment can be broken
|
||||
@ -71,23 +71,23 @@ bool CachedFace::runGraphite(Segment *seg, const Silf *pSilf) const
|
||||
int subSegStart = 0;
|
||||
for (unsigned int i = 0; i < seg->charInfoCount(); ++i)
|
||||
{
|
||||
const unsigned int length = i - subSegStart + 1;
|
||||
const unsigned int length = i - subSegStart + 1;
|
||||
if (length < eMaxSpliceSize)
|
||||
cmapGlyphs[length-1] = subSegEndSlot->gid();
|
||||
else return false;
|
||||
const bool spaceOnly = m_cacheStore->isSpaceGlyph(subSegEndSlot->gid());
|
||||
// at this stage the character to slot mapping is still 1 to 1
|
||||
const int breakWeight = seg->charinfo(i)->breakWeight(),
|
||||
nextBreakWeight = (i + 1 < seg->charInfoCount())?
|
||||
seg->charinfo(i+1)->breakWeight() : 0;
|
||||
const int breakWeight = seg->charinfo(i)->breakWeight(),
|
||||
nextBreakWeight = (i + 1 < seg->charInfoCount())?
|
||||
seg->charinfo(i+1)->breakWeight() : 0;
|
||||
const uint8 f = seg->charinfo(i)->flags();
|
||||
if (((spaceOnly
|
||||
|| (breakWeight > 0 && breakWeight <= gr_breakWord)
|
||||
|| i + 1 == seg->charInfoCount()
|
||||
|| ((nextBreakWeight < 0 && nextBreakWeight >= gr_breakBeforeWord)
|
||||
|| (subSegEndSlot->next() && m_cacheStore->isSpaceGlyph(subSegEndSlot->next()->gid()))))
|
||||
&& f != 1)
|
||||
|| f == 2)
|
||||
|| (breakWeight > 0 && breakWeight <= gr_breakWord)
|
||||
|| i + 1 == seg->charInfoCount()
|
||||
|| ((nextBreakWeight < 0 && nextBreakWeight >= gr_breakBeforeWord)
|
||||
|| (subSegEndSlot->next() && m_cacheStore->isSpaceGlyph(subSegEndSlot->next()->gid()))))
|
||||
&& f != 1)
|
||||
|| f == 2)
|
||||
{
|
||||
// record the next slot before any splicing
|
||||
Slot * nextSlot = subSegEndSlot->next();
|
||||
@ -103,8 +103,8 @@ bool CachedFace::runGraphite(Segment *seg, const Silf *pSilf) const
|
||||
pSilf->runGraphite(seg, pSilf->substitutionPass(), pSilf->numPasses());
|
||||
if (length < eMaxSpliceSize)
|
||||
{
|
||||
seg->associateChars();
|
||||
entry = segCache->cache(m_cacheStore, cmapGlyphs, length, seg, subSegStart);
|
||||
seg->associateChars(subSegStart, length);
|
||||
segCache->cache(m_cacheStore, cmapGlyphs, length, seg, subSegStart);
|
||||
}
|
||||
seg->removeScope(scopeState);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ CachedCmap::CachedCmap(const Face & face)
|
||||
m_blocks(0)
|
||||
{
|
||||
const Face::Table cmap(face, Tag::cmap);
|
||||
if (!cmap) return;
|
||||
if (!cmap) return;
|
||||
|
||||
const void * bmp_cmap = bmp_subtable(cmap);
|
||||
const void * smp_cmap = smp_subtable(cmap);
|
||||
@ -114,7 +114,7 @@ CachedCmap::~CachedCmap() throw()
|
||||
if (!m_blocks) return;
|
||||
unsigned int numBlocks = (m_isBmpOnly)? 0x100 : 0x1100;
|
||||
for (unsigned int i = 0; i < numBlocks; i++)
|
||||
free(m_blocks[i]);
|
||||
free(m_blocks[i]);
|
||||
free(m_blocks);
|
||||
}
|
||||
|
||||
@ -130,7 +130,7 @@ uint16 CachedCmap::operator [] (const uint32 usv) const throw()
|
||||
|
||||
CachedCmap::operator bool() const throw()
|
||||
{
|
||||
return m_blocks != 0;
|
||||
return m_blocks != 0;
|
||||
}
|
||||
|
||||
|
||||
@ -150,6 +150,6 @@ uint16 DirectCmap::operator [] (const uint32 usv) const throw()
|
||||
|
||||
DirectCmap::operator bool () const throw()
|
||||
{
|
||||
return _cmap && _bmp;
|
||||
return _cmap && _bmp;
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ private:
|
||||
opcode fetch_opcode(const byte * bc);
|
||||
void analyse_opcode(const opcode, const int8 * const dp) throw();
|
||||
bool emit_opcode(opcode opc, const byte * & bc);
|
||||
bool validate_opcode(const opcode opc, const byte * const bc);
|
||||
bool validate_opcode(const opcode opc, const byte * const bc);
|
||||
bool valid_upto(const uint16 limit, const uint16 x) const throw();
|
||||
void failure(const status_t s) const throw() { _code.failure(s); }
|
||||
|
||||
@ -215,7 +215,10 @@ Machine::Code::Code(bool is_constraint, const byte * bytecode_begin, const byte
|
||||
_data = static_cast<byte *>(realloc(_data, _data_size*sizeof(byte)));
|
||||
|
||||
if (!_code)
|
||||
{
|
||||
failure(alloc_failed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make this RET_ZERO, we should never reach this but just in case ...
|
||||
_code[_instr_count] = op_to_fn[RET_ZERO].impl[_constraint];
|
||||
@ -257,7 +260,7 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
const opcode opc = opcode(*bc++);
|
||||
|
||||
// Do some basic sanity checks based on what we know about the opcode
|
||||
if (!validate_opcode(opc, bc)) return MAX_OPCODE;
|
||||
if (!validate_opcode(opc, bc)) return MAX_OPCODE;
|
||||
|
||||
// And check it's arguments as far as possible
|
||||
switch (opc)
|
||||
@ -322,11 +325,11 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
case ATTR_ADD :
|
||||
case ATTR_SUB :
|
||||
case ATTR_SET_SLOT :
|
||||
valid_upto(gr_slatMax, bc[0]);
|
||||
valid_upto(gr_slatMax, bc[0]);
|
||||
break;
|
||||
case IATTR_SET_SLOT :
|
||||
if (valid_upto(gr_slatMax, bc[0]))
|
||||
valid_upto(_max.attrid[bc[0]], bc[1]);
|
||||
valid_upto(_max.attrid[bc[0]], bc[1]);
|
||||
break;
|
||||
case PUSH_SLOT_ATTR :
|
||||
valid_upto(gr_slatMax, bc[0]);
|
||||
@ -357,8 +360,8 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
case PUSH_ISLOT_ATTR :
|
||||
if (valid_upto(gr_slatMax, bc[0]))
|
||||
{
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
valid_upto(_max.attrid[bc[0]], bc[2]);
|
||||
valid_upto(_rule_length, _pre_context + int8(bc[1]));
|
||||
valid_upto(_max.attrid[bc[0]], bc[2]);
|
||||
}
|
||||
break;
|
||||
case PUSH_IGLYPH_ATTR :// not implemented
|
||||
@ -370,7 +373,7 @@ opcode Machine::Code::decoder::fetch_opcode(const byte * bc)
|
||||
case IATTR_ADD :
|
||||
case IATTR_SUB :
|
||||
if (valid_upto(gr_slatMax, bc[0]))
|
||||
valid_upto(_max.attrid[bc[0]], bc[1]);
|
||||
valid_upto(_max.attrid[bc[0]], bc[1]);
|
||||
break;
|
||||
case PUSH_PROC_STATE : // dummy: dp[0] no check necessary
|
||||
case PUSH_VERSION :
|
||||
@ -544,26 +547,26 @@ void Machine::Code::decoder::apply_analysis(instr * const code, instr * code_end
|
||||
inline
|
||||
bool Machine::Code::decoder::validate_opcode(const opcode opc, const byte * const bc)
|
||||
{
|
||||
if (opc >= MAX_OPCODE)
|
||||
{
|
||||
failure(invalid_opcode);
|
||||
return false;
|
||||
}
|
||||
const opcode_t & op = Machine::getOpcodeTable()[opc];
|
||||
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
|
||||
if (bc + param_sz > _max.bytecode)
|
||||
{
|
||||
failure(arguments_exhausted);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (opc >= MAX_OPCODE)
|
||||
{
|
||||
failure(invalid_opcode);
|
||||
return false;
|
||||
}
|
||||
const opcode_t & op = Machine::getOpcodeTable()[opc];
|
||||
const size_t param_sz = op.param_sz == VARARGS ? bc[0] + 1 : op.param_sz;
|
||||
if (bc + param_sz > _max.bytecode)
|
||||
{
|
||||
failure(arguments_exhausted);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Machine::Code::decoder::valid_upto(const uint16 limit, const uint16 x) const throw()
|
||||
{
|
||||
const bool t = x < limit;
|
||||
if (!t) failure(out_of_range_data);
|
||||
const bool t = x < limit;
|
||||
if (!t) failure(out_of_range_data);
|
||||
return t;
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/SegCacheStore.h"
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/NameTable.h"
|
||||
|
||||
#include "inc/Error.h"
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
@ -47,6 +47,7 @@ Face::Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops)
|
||||
m_cmap(NULL),
|
||||
m_pNames(NULL),
|
||||
m_logger(NULL),
|
||||
m_error(0), m_errcntxt(0),
|
||||
m_silfs(NULL),
|
||||
m_numSilf(0),
|
||||
m_ascent(0),
|
||||
@ -78,20 +79,24 @@ float Face::default_glyph_advance(const void* font_ptr, gr_uint16 glyphid)
|
||||
|
||||
bool Face::readGlyphs(uint32 faceOptions)
|
||||
{
|
||||
Error e;
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _glyph_cat(tele.glyph);
|
||||
#endif
|
||||
error_context(EC_READGLYPHS);
|
||||
if (faceOptions & gr_face_cacheCmap)
|
||||
m_cmap = new CachedCmap(*this);
|
||||
m_cmap = new CachedCmap(*this);
|
||||
else
|
||||
m_cmap = new DirectCmap(*this);
|
||||
m_cmap = new DirectCmap(*this);
|
||||
|
||||
m_pGlyphFaceCache = new GlyphCache(*this, faceOptions);
|
||||
if (!m_pGlyphFaceCache
|
||||
|| m_pGlyphFaceCache->numGlyphs() == 0
|
||||
|| m_pGlyphFaceCache->unitsPerEm() == 0
|
||||
|| !m_cmap || !*m_cmap)
|
||||
return false;
|
||||
if (e.test(!m_pGlyphFaceCache, E_OUTOFMEM)
|
||||
|| e.test(m_pGlyphFaceCache->numGlyphs() == 0, E_NOGLYPHS)
|
||||
|| e.test(m_pGlyphFaceCache->unitsPerEm() == 0, E_BADUPEM)
|
||||
|| e.test(!m_cmap, E_OUTOFMEM) || e.test(!*m_cmap, E_BADCMAP))
|
||||
{
|
||||
return error(e);
|
||||
}
|
||||
|
||||
if (faceOptions & gr_face_preloadGlyphs)
|
||||
nameTable(); // preload the name table along with the glyphs.
|
||||
@ -104,24 +109,27 @@ bool Face::readGraphite(const Table & silf)
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _silf_cat(tele.silf);
|
||||
#endif
|
||||
Error e;
|
||||
error_context(EC_READSILF);
|
||||
const byte * p = silf;
|
||||
if (!p) return false;
|
||||
if (e.test(!p, E_NOSILF)) return error(e);
|
||||
|
||||
const uint32 version = be::read<uint32>(p);
|
||||
if (version < 0x00020000) return false;
|
||||
if (e.test(version < 0x00020000, E_TOOOLD)) return error(e);
|
||||
if (version >= 0x00030000)
|
||||
be::skip<uint32>(p); // compilerVersion
|
||||
be::skip<uint32>(p); // compilerVersion
|
||||
m_numSilf = be::read<uint16>(p);
|
||||
be::skip<uint16>(p); // reserved
|
||||
be::skip<uint16>(p); // reserved
|
||||
|
||||
bool havePasses = false;
|
||||
m_silfs = new Silf[m_numSilf];
|
||||
for (int i = 0; i < m_numSilf; i++)
|
||||
{
|
||||
error_context(EC_ASILF + (i << 8));
|
||||
const uint32 offset = be::read<uint32>(p),
|
||||
next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
|
||||
if (next > silf.size() || offset >= next)
|
||||
return false;
|
||||
next = i == m_numSilf - 1 ? silf.size() : be::peek<uint32>(p);
|
||||
if (e.test(next > silf.size() || offset >= next, E_BADSIZE))
|
||||
return error(e);
|
||||
|
||||
if (!m_silfs[i].readGraphite(silf + offset, next - offset, *this, version))
|
||||
return false;
|
||||
@ -144,33 +152,33 @@ bool Face::runGraphite(Segment *seg, const Silf *aSilf) const
|
||||
json * dbgout = logger();
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::object
|
||||
<< "id" << objectid(seg)
|
||||
<< "passes" << json::array;
|
||||
*dbgout << json::object
|
||||
<< "id" << objectid(seg)
|
||||
<< "passes" << json::array;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass());
|
||||
bool res = aSilf->runGraphite(seg, 0, aSilf->justificationPass(), true);
|
||||
if (res)
|
||||
res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses());
|
||||
res = aSilf->runGraphite(seg, aSilf->positionPass(), aSilf->numPasses(), false);
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::item
|
||||
<< json::close // Close up the passes array
|
||||
<< "output" << json::array;
|
||||
for(Slot * s = seg->first(); s; s = s->next())
|
||||
*dbgout << dslot(seg, s);
|
||||
seg->finalise(0); // Call this here to fix up charinfo back indexes.
|
||||
*dbgout << json::close
|
||||
<< "advance" << seg->advance()
|
||||
<< "chars" << json::array;
|
||||
for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
|
||||
*dbgout << json::flat << *seg->charinfo(i);
|
||||
*dbgout << json::close // Close up the chars array
|
||||
<< json::close; // Close up the segment object
|
||||
}
|
||||
*dbgout << json::item
|
||||
<< json::close // Close up the passes array
|
||||
<< "output" << json::array;
|
||||
for(Slot * s = seg->first(); s; s = s->next())
|
||||
*dbgout << dslot(seg, s);
|
||||
seg->finalise(0); // Call this here to fix up charinfo back indexes.
|
||||
*dbgout << json::close
|
||||
<< "advance" << seg->advance()
|
||||
<< "chars" << json::array;
|
||||
for(size_t i = 0, n = seg->charInfoCount(); i != n; ++i)
|
||||
*dbgout << json::flat << *seg->charinfo(i);
|
||||
*dbgout << json::close // Close up the chars array
|
||||
<< json::close; // Close up the segment object
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
|
@ -41,38 +41,38 @@ using namespace graphite2;
|
||||
|
||||
namespace
|
||||
{
|
||||
static int cmpNameAndFeatures(const void *ap, const void *bp)
|
||||
{
|
||||
const NameAndFeatureRef & a = *static_cast<const NameAndFeatureRef *>(ap),
|
||||
& b = *static_cast<const NameAndFeatureRef *>(bp);
|
||||
return (a < b ? -1 : (b < a ? 1 : 0));
|
||||
}
|
||||
static int cmpNameAndFeatures(const void *ap, const void *bp)
|
||||
{
|
||||
const NameAndFeatureRef & a = *static_cast<const NameAndFeatureRef *>(ap),
|
||||
& b = *static_cast<const NameAndFeatureRef *>(bp);
|
||||
return (a < b ? -1 : (b < a ? 1 : 0));
|
||||
}
|
||||
|
||||
const size_t FEAT_HEADER = sizeof(uint32) + 2*sizeof(uint16) + sizeof(uint32),
|
||||
FEATURE_SIZE = sizeof(uint32)
|
||||
+ 2*sizeof(uint16)
|
||||
+ sizeof(uint32)
|
||||
+ 2*sizeof(uint16),
|
||||
FEATURE_SETTING_SIZE = sizeof(int16) + sizeof(uint16);
|
||||
const size_t FEAT_HEADER = sizeof(uint32) + 2*sizeof(uint16) + sizeof(uint32),
|
||||
FEATURE_SIZE = sizeof(uint32)
|
||||
+ 2*sizeof(uint16)
|
||||
+ sizeof(uint32)
|
||||
+ 2*sizeof(uint16),
|
||||
FEATURE_SETTING_SIZE = sizeof(int16) + sizeof(uint16);
|
||||
|
||||
uint16 readFeatureSettings(const byte * p, FeatureSetting * s, size_t num_settings)
|
||||
{
|
||||
uint16 max_val = 0;
|
||||
uint16 readFeatureSettings(const byte * p, FeatureSetting * s, size_t num_settings)
|
||||
{
|
||||
uint16 max_val = 0;
|
||||
for (FeatureSetting * const end = s + num_settings; s != end; ++s)
|
||||
{
|
||||
const int16 value = be::read<int16>(p);
|
||||
const int16 value = be::read<int16>(p);
|
||||
::new (s) FeatureSetting(value, be::read<uint16>(p));
|
||||
if (uint16(value) > max_val) max_val = value;
|
||||
if (uint16(value) > max_val) max_val = value;
|
||||
}
|
||||
|
||||
return max_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FeatureRef::FeatureRef(const Face & face,
|
||||
unsigned short & bits_offset, uint32 max_val,
|
||||
uint32 name, uint16 uiName, uint16 flags,
|
||||
FeatureSetting *settings, uint16 num_set) throw()
|
||||
unsigned short & bits_offset, uint32 max_val,
|
||||
uint32 name, uint16 uiName, uint16 flags,
|
||||
FeatureSetting *settings, uint16 num_set) throw()
|
||||
: m_pFace(&face),
|
||||
m_nameValues(settings),
|
||||
m_mask(mask_over_val(max_val)),
|
||||
@ -82,13 +82,13 @@ FeatureRef::FeatureRef(const Face & face,
|
||||
m_flags(flags),
|
||||
m_numSet(num_set)
|
||||
{
|
||||
const uint8 need_bits = bit_set_count(m_mask);
|
||||
m_index = (bits_offset + need_bits) / SIZEOF_CHUNK;
|
||||
if (m_index > bits_offset / SIZEOF_CHUNK)
|
||||
bits_offset = m_index*SIZEOF_CHUNK;
|
||||
m_bits = bits_offset % SIZEOF_CHUNK;
|
||||
bits_offset += need_bits;
|
||||
m_mask <<= m_bits;
|
||||
const uint8 need_bits = bit_set_count(m_mask);
|
||||
m_index = (bits_offset + need_bits) / SIZEOF_CHUNK;
|
||||
if (m_index > bits_offset / SIZEOF_CHUNK)
|
||||
bits_offset = m_index*SIZEOF_CHUNK;
|
||||
m_bits = bits_offset % SIZEOF_CHUNK;
|
||||
bits_offset += need_bits;
|
||||
m_mask <<= m_bits;
|
||||
}
|
||||
|
||||
FeatureRef::~FeatureRef() throw()
|
||||
@ -104,7 +104,7 @@ bool FeatureMap::readFeats(const Face & face)
|
||||
if (feat.size() < FEAT_HEADER) return false;
|
||||
|
||||
const byte *const feat_start = p,
|
||||
*const feat_end = p + feat.size();
|
||||
*const feat_end = p + feat.size();
|
||||
|
||||
const uint32 version = be::read<uint32>(p);
|
||||
m_numFeats = be::read<uint16>(p);
|
||||
@ -112,27 +112,28 @@ bool FeatureMap::readFeats(const Face & face)
|
||||
be::skip<uint32>(p);
|
||||
|
||||
// Sanity checks
|
||||
if (m_numFeats == 0) return true;
|
||||
if (m_numFeats == 0) return true;
|
||||
if (version < 0x00010000 ||
|
||||
p + m_numFeats*FEATURE_SIZE > feat_end)
|
||||
p + m_numFeats*FEATURE_SIZE > feat_end)
|
||||
{ //defensive
|
||||
m_numFeats = 0;
|
||||
return false;
|
||||
m_numFeats = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_feats = new FeatureRef [m_numFeats];
|
||||
uint16 * const defVals = gralloc<uint16>(m_numFeats);
|
||||
uint16 * const defVals = gralloc<uint16>(m_numFeats);
|
||||
if (!defVals || !m_feats) return false;
|
||||
unsigned short bits = 0; //to cause overflow on first Feature
|
||||
|
||||
for (int i = 0, ie = m_numFeats; i != ie; i++)
|
||||
{
|
||||
const uint32 label = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p);
|
||||
const uint16 num_settings = be::read<uint16>(p);
|
||||
const uint32 label = version < 0x00020000 ? be::read<uint16>(p) : be::read<uint32>(p);
|
||||
const uint16 num_settings = be::read<uint16>(p);
|
||||
if (version >= 0x00020000)
|
||||
be::skip<uint16>(p);
|
||||
be::skip<uint16>(p);
|
||||
const byte * const feat_setts = feat_start + be::read<uint32>(p);
|
||||
const uint16 flags = be::read<uint16>(p),
|
||||
uiName = be::read<uint16>(p);
|
||||
const uint16 flags = be::read<uint16>(p),
|
||||
uiName = be::read<uint16>(p);
|
||||
|
||||
if (feat_setts + num_settings * FEATURE_SETTING_SIZE > feat_end)
|
||||
{
|
||||
@ -144,26 +145,36 @@ bool FeatureMap::readFeats(const Face & face)
|
||||
uint32 maxVal;
|
||||
if (num_settings != 0)
|
||||
{
|
||||
uiSet = gralloc<FeatureSetting>(num_settings);
|
||||
maxVal = readFeatureSettings(feat_setts, uiSet, num_settings);
|
||||
defVals[i] = uiSet[0].value();
|
||||
uiSet = gralloc<FeatureSetting>(num_settings);
|
||||
if (!uiSet)
|
||||
{
|
||||
free(defVals);
|
||||
return false;
|
||||
}
|
||||
maxVal = readFeatureSettings(feat_setts, uiSet, num_settings);
|
||||
defVals[i] = uiSet[0].value();
|
||||
}
|
||||
else
|
||||
{
|
||||
uiSet = 0;
|
||||
maxVal = 0xffffffff;
|
||||
defVals[i] = 0;
|
||||
uiSet = 0;
|
||||
maxVal = 0xffffffff;
|
||||
defVals[i] = 0;
|
||||
}
|
||||
|
||||
::new (m_feats + i) FeatureRef (face, bits, maxVal,
|
||||
label, uiName, flags,
|
||||
uiSet, num_settings);
|
||||
::new (m_feats + i) FeatureRef (face, bits, maxVal,
|
||||
label, uiName, flags,
|
||||
uiSet, num_settings);
|
||||
}
|
||||
m_defaultFeatures = new Features(bits/(sizeof(uint32)*8) + 1, *this);
|
||||
m_pNamedFeats = new NameAndFeatureRef[m_numFeats];
|
||||
if (!m_defaultFeatures || !m_pNamedFeats)
|
||||
{
|
||||
free(defVals);
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < m_numFeats; ++i)
|
||||
{
|
||||
m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
|
||||
m_feats[i].applyValToFeature(defVals[i], *m_defaultFeatures);
|
||||
m_pNamedFeats[i] = m_feats+i;
|
||||
}
|
||||
|
||||
@ -184,7 +195,7 @@ bool SillMap::readFace(const Face & face)
|
||||
|
||||
bool SillMap::readSill(const Face & face)
|
||||
{
|
||||
const Face::Table sill(face, TtfUtil::Tag::Sill);
|
||||
const Face::Table sill(face, TtfUtil::Tag::Sill);
|
||||
const byte *p = sill;
|
||||
|
||||
if (!p) return true;
|
||||
@ -204,6 +215,7 @@ bool SillMap::readSill(const Face & face)
|
||||
uint16 offset = be::read<uint16>(p);
|
||||
if (offset + 8U * numSettings > sill.size() && numSettings > 0) return false;
|
||||
Features* feats = new Features(*m_FeatureMap.m_defaultFeatures);
|
||||
if (!feats) return false;
|
||||
const byte *pLSet = sill + offset;
|
||||
|
||||
// Apply langauge specific settings
|
||||
@ -213,11 +225,11 @@ bool SillMap::readSill(const Face & face)
|
||||
uint16 val = be::read<uint16>(pLSet);
|
||||
pLSet += 2;
|
||||
const FeatureRef* pRef = m_FeatureMap.findFeatureRef(name);
|
||||
if (pRef) pRef->applyValToFeature(val, *feats);
|
||||
if (pRef) pRef->applyValToFeature(val, *feats);
|
||||
}
|
||||
// Add the language id feature which is always feature id 1
|
||||
const FeatureRef* pRef = m_FeatureMap.findFeatureRef(1);
|
||||
if (pRef) pRef->applyValToFeature(langid, *feats);
|
||||
if (pRef) pRef->applyValToFeature(langid, *feats);
|
||||
|
||||
m_langFeats[i].m_lang = langid;
|
||||
m_langFeats[i].m_pFeatures = feats;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2012, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
|
@ -37,7 +37,7 @@ Font::Font(float ppm, const Face & f, const void * appFontHandle, const gr_font_
|
||||
m_hinted(appFontHandle && ops && (ops->glyph_advance_x || ops->glyph_advance_y))
|
||||
{
|
||||
memset(&m_ops, 0, sizeof m_ops);
|
||||
if (m_hinted)
|
||||
if (m_hinted && ops)
|
||||
memcpy(&m_ops, ops, min(sizeof m_ops, ops->size));
|
||||
else
|
||||
m_ops.glyph_advance_x = &Face::default_glyph_advance;
|
||||
@ -47,14 +47,14 @@ Font::Font(float ppm, const Face & f, const void * appFontHandle, const gr_font_
|
||||
if (m_advances)
|
||||
{
|
||||
for (float *advp = m_advances; nGlyphs; --nGlyphs, ++advp)
|
||||
*advp = INVALID_ADVANCE;
|
||||
*advp = INVALID_ADVANCE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ Font::~Font()
|
||||
{
|
||||
free(m_advances);
|
||||
free(m_advances);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2012, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -36,45 +36,45 @@ using namespace graphite2;
|
||||
|
||||
namespace
|
||||
{
|
||||
class glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
|
||||
// Iterator over version 1 or 2 glat entries which consist of a series of
|
||||
// +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// v1 |k|n|v1 |v2 |...|vN | or v2 | k | n |v1 |v2 |...|vN |
|
||||
// +-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// variable length structures.
|
||||
|
||||
template<typename W>
|
||||
class _glat_iterator : public std::iterator<std::input_iterator_tag, std::pair<sparse::key_type, sparse::mapped_type> >
|
||||
{
|
||||
unsigned short key() const { return be::peek<W>(_e) + _n; }
|
||||
unsigned int run() const { return be::peek<W>(_e+sizeof(W)); }
|
||||
void advance_entry() { _n = 0; _e = _v; be::skip<W>(_v,2); }
|
||||
public:
|
||||
glat_iterator(const void * glat=0) : _p(reinterpret_cast<const byte *>(glat)), _n(0) {}
|
||||
_glat_iterator(const void * glat=0) : _e(reinterpret_cast<const byte *>(glat)), _v(_e+2*sizeof(W)), _n(0) {}
|
||||
|
||||
glat_iterator & operator ++ () { ++_v.first; --_n; _p += sizeof(uint16); if (_n == -1) { _p -= 2; _v.first = *_p++; _n = *_p++; } return *this; }
|
||||
glat_iterator operator ++ (int) { glat_iterator tmp(*this); operator++(); return tmp; }
|
||||
_glat_iterator<W> & operator ++ () {
|
||||
++_n; be::skip<uint16>(_v);
|
||||
if (_n == run()) advance_entry();
|
||||
return *this;
|
||||
}
|
||||
_glat_iterator<W> operator ++ (int) { _glat_iterator<W> tmp(*this); operator++(); return tmp; }
|
||||
|
||||
bool operator == (const glat_iterator & rhs) { return _p >= rhs._p || _p + _n*sizeof(uint16) > rhs._p; }
|
||||
bool operator != (const glat_iterator & rhs) { return !operator==(rhs); }
|
||||
// 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 !operator==(rhs); }
|
||||
|
||||
value_type operator * () const {
|
||||
if (_n==0) { _v.first = *_p++; _n = *_p++; }
|
||||
_v.second = be::peek<uint16>(_p);
|
||||
return _v;
|
||||
return value_type(key(), be::peek<uint16>(_v));
|
||||
}
|
||||
const value_type * operator ->() const { operator * (); return &_v; }
|
||||
|
||||
protected:
|
||||
mutable const byte * _p;
|
||||
mutable value_type _v;
|
||||
mutable int _n;
|
||||
const byte * _e, * _v;
|
||||
ptrdiff_t _n;
|
||||
};
|
||||
|
||||
class glat2_iterator : public glat_iterator
|
||||
{
|
||||
public:
|
||||
glat2_iterator(const void * glat) : glat_iterator(glat) {}
|
||||
|
||||
glat2_iterator & operator ++ () { ++_v.first; --_n; _p += sizeof(uint16); if (_n == -1) { _p -= sizeof(uint16)*2; _v.first = be::read<uint16>(_p); _n = be::read<uint16>(_p); } return *this; }
|
||||
glat2_iterator operator ++ (int) { glat2_iterator tmp(*this); operator++(); return tmp; }
|
||||
|
||||
value_type operator * () const {
|
||||
if (_n==0) { _v.first = be::read<uint16>(_p); _n = be::read<uint16>(_p); }
|
||||
_v.second = be::peek<uint16>(_p);
|
||||
return _v;
|
||||
}
|
||||
const value_type * operator ->() const { operator * (); return &_v; }
|
||||
};
|
||||
typedef _glat_iterator<uint8> glat_iterator;
|
||||
typedef _glat_iterator<uint16> glat2_iterator;
|
||||
}
|
||||
|
||||
|
||||
@ -203,7 +203,7 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
|
||||
_num_glyphs_graphics = TtfUtil::GlyphCount(maxp);
|
||||
// This will fail if the number of glyphs is wildly out of range.
|
||||
if (TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
|
||||
if (_glyf && TtfUtil::LocaLookup(_num_glyphs_graphics-1, _loca, _loca.size(), _head) == size_t(-1))
|
||||
{
|
||||
_head = Face::Table();
|
||||
return;
|
||||
@ -244,7 +244,7 @@ GlyphCache::Loader::Loader(const Face & face, const bool dumb_font)
|
||||
inline
|
||||
GlyphCache::Loader::operator bool () const throw()
|
||||
{
|
||||
return _head && _hhea && _hmtx && _glyf && _loca;
|
||||
return _head && _hhea && _hmtx && !(bool(_glyf) != bool(_loca));
|
||||
}
|
||||
|
||||
inline
|
||||
@ -272,16 +272,20 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
|
||||
|
||||
if (glyphid < _num_glyphs_graphics)
|
||||
{
|
||||
int nLsb, xMin, yMin, xMax, yMax;
|
||||
int nLsb;
|
||||
unsigned int nAdvWid;
|
||||
size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
|
||||
void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
|
||||
if (_glyf)
|
||||
{
|
||||
int xMin, yMin, xMax, yMax;
|
||||
size_t locidx = TtfUtil::LocaLookup(glyphid, _loca, _loca.size(), _head);
|
||||
void *pGlyph = TtfUtil::GlyfLookup(_glyf, locidx, _glyf.size());
|
||||
|
||||
if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
|
||||
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);
|
||||
|
||||
if (pGlyph && TtfUtil::GlyfBox(pGlyph, xMin, yMin, xMax, yMax))
|
||||
bbox = Rect(Position(static_cast<float>(xMin), static_cast<float>(yMin)),
|
||||
Position(static_cast<float>(xMax), static_cast<float>(yMax)));
|
||||
}
|
||||
|
||||
if (glyphid < _num_glyphs_attributes)
|
||||
@ -329,7 +333,7 @@ const GlyphFace * GlyphCache::Loader::read_glyph(unsigned short glyphid, GlyphFa
|
||||
new (&glyph) GlyphFace(bbox, advance, glat2_iterator(m_pGlat + glocs), glat2_iterator(m_pGlat + gloce));
|
||||
}
|
||||
|
||||
if (glyph.attrs().capacity() > _num_attrs)
|
||||
if (!glyph.attrs() || glyph.attrs().capacity() > _num_attrs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2012, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -117,6 +117,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
}
|
||||
|
||||
JustifyTotal *stats = new JustifyTotal[numLevels];
|
||||
if (!stats) return -1.0;
|
||||
for (s = pFirst; s != end; s = s->nextSibling())
|
||||
{
|
||||
float w = s->origin().x / scale + s->advance() - base;
|
||||
@ -179,6 +180,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
{
|
||||
m_first = pSlot = addLineEnd(pSlot);
|
||||
m_last = pLast = addLineEnd(end);
|
||||
if (!m_first || !m_last) return -1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -191,7 +193,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
json * const dbgout = m_face->logger();
|
||||
if (dbgout)
|
||||
*dbgout << json::object
|
||||
<< "justifies" << objectid(this)
|
||||
<< "justifies" << objectid(this)
|
||||
<< "passes" << json::array;
|
||||
#endif
|
||||
|
||||
@ -206,8 +208,8 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
Slot *lEnd = pLast->nextSibling();
|
||||
*dbgout << "output" << json::array;
|
||||
for(Slot * t = pSlot; t != lEnd; t = t->next())
|
||||
*dbgout << dslot(this, t);
|
||||
*dbgout << json::close << json::close;
|
||||
*dbgout << dslot(this, t);
|
||||
*dbgout << json::close << json::close;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -226,6 +228,7 @@ float Segment::justify(Slot *pSlot, const Font *font, float width, GR_MAYBE_UNUS
|
||||
Slot *Segment::addLineEnd(Slot *nSlot)
|
||||
{
|
||||
Slot *eSlot = newSlot();
|
||||
if (!eSlot) return NULL;
|
||||
const uint16 gid = silf()->endLineGlyphid();
|
||||
const GlyphFace * theGlyph = m_face->glyphs().glyphSafe(gid);
|
||||
eSlot->setGlyph(this, gid, theGlyph);
|
||||
|
@ -145,6 +145,12 @@ void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint
|
||||
}
|
||||
utf16Length >>= 1; // in utf16 units
|
||||
utf16::codeunit_t * utf16Name = gralloc<utf16::codeunit_t>(utf16Length);
|
||||
if (!utf16Name)
|
||||
{
|
||||
languageId = 0;
|
||||
length = 0;
|
||||
return NULL;
|
||||
}
|
||||
const uint8* pName = m_nameData + offset;
|
||||
for (size_t i = 0; i < utf16Length; i++)
|
||||
{
|
||||
@ -154,28 +160,46 @@ void* NameTable::getName(uint16& languageId, uint16 nameId, gr_encform enc, uint
|
||||
{
|
||||
case gr_utf8:
|
||||
{
|
||||
utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
|
||||
utf8::codeunit_t* uniBuffer = gralloc<utf8::codeunit_t>(3 * utf16Length + 1);
|
||||
if (!uniBuffer)
|
||||
{
|
||||
free(utf16Name);
|
||||
languageId = 0;
|
||||
length = 0;
|
||||
return NULL;
|
||||
}
|
||||
utf8::iterator d = uniBuffer;
|
||||
for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
|
||||
*d = *s;
|
||||
*d = *s;
|
||||
length = d - uniBuffer;
|
||||
uniBuffer[length] = 0;
|
||||
free(utf16Name);
|
||||
return uniBuffer;
|
||||
}
|
||||
case gr_utf16:
|
||||
length = utf16Length;
|
||||
return utf16Name;
|
||||
length = utf16Length;
|
||||
return utf16Name;
|
||||
case gr_utf32:
|
||||
{
|
||||
utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);
|
||||
utf32::iterator d = uniBuffer;
|
||||
for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
|
||||
*d = *s;
|
||||
length = d - uniBuffer;
|
||||
uniBuffer[length] = 0;
|
||||
return uniBuffer;
|
||||
utf32::codeunit_t * uniBuffer = gralloc<utf32::codeunit_t>(utf16Length + 1);
|
||||
if (!uniBuffer)
|
||||
{
|
||||
free(utf16Name);
|
||||
languageId = 0;
|
||||
length = 0;
|
||||
return NULL;
|
||||
}
|
||||
utf32::iterator d = uniBuffer;
|
||||
for (utf16::const_iterator s = utf16Name, e = utf16Name + utf16Length; s != e; ++s, ++d)
|
||||
*d = *s;
|
||||
length = d - uniBuffer;
|
||||
uniBuffer[length] = 0;
|
||||
free(utf16Name);
|
||||
return uniBuffer;
|
||||
}
|
||||
}
|
||||
free(utf16Name);
|
||||
languageId = 0;
|
||||
length = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/Code.h"
|
||||
#include "inc/Rule.h"
|
||||
#include "inc/Error.h"
|
||||
|
||||
using namespace graphite2;
|
||||
using vm::Machine;
|
||||
@ -72,13 +73,13 @@ Pass::~Pass()
|
||||
delete [] m_rules;
|
||||
}
|
||||
|
||||
bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED const Face & face)
|
||||
bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t subtable_base, GR_MAYBE_UNUSED Face & face, Error &e)
|
||||
{
|
||||
const byte * p = pass_start,
|
||||
* const pass_end = p + pass_length;
|
||||
size_t numRanges;
|
||||
|
||||
if (pass_length < 40) return false;
|
||||
if (e.test(pass_length < 40, E_BADPASSLENGTH)) return face.error(e);
|
||||
// Read in basic values
|
||||
m_flags = be::read<byte>(p);
|
||||
m_iMaxLoop = be::read<byte>(p);
|
||||
@ -97,14 +98,14 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
be::skip<uint16>(p, 3); // skip searchRange, entrySelector & rangeShift.
|
||||
assert(p - pass_start == 40);
|
||||
// Perform some sanity checks.
|
||||
if ( m_numTransition > m_numStates
|
||||
|| m_numSuccess > m_numStates
|
||||
|| m_numSuccess + m_numTransition < m_numStates
|
||||
|| numRanges == 0)
|
||||
return false;
|
||||
if ( e.test(m_numTransition > m_numStates, E_BADNUMTRANS)
|
||||
|| e.test(m_numSuccess > m_numStates, E_BADNUMSUCCESS)
|
||||
|| e.test(m_numSuccess + m_numTransition < m_numStates, E_BADNUMSTATES)
|
||||
|| e.test(numRanges == 0, E_NORANGES))
|
||||
return face.error(e);
|
||||
|
||||
m_successStart = m_numStates - m_numSuccess;
|
||||
if (p + numRanges * 6 - 4 > pass_end) return false;
|
||||
if (e.test(p + numRanges * 6 - 4 > pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
m_numGlyphs = be::peek<uint16>(p + numRanges * 6 - 4) + 1;
|
||||
// Calculate the start of various arrays.
|
||||
const byte * const ranges = p;
|
||||
@ -113,17 +114,17 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
be::skip<uint16>(p, m_numSuccess + 1);
|
||||
|
||||
// More sanity checks
|
||||
if (reinterpret_cast<const byte *>(o_rule_map + m_numSuccess*sizeof(uint16)) > pass_end
|
||||
|| p > pass_end)
|
||||
return false;
|
||||
if (e.test(reinterpret_cast<const byte *>(o_rule_map + m_numSuccess*sizeof(uint16)) > pass_end
|
||||
|| p > pass_end, E_BADRULEMAPLEN))
|
||||
return face.error(e);
|
||||
const size_t numEntries = be::peek<uint16>(o_rule_map + m_numSuccess*sizeof(uint16));
|
||||
const byte * const rule_map = p;
|
||||
be::skip<uint16>(p, numEntries);
|
||||
|
||||
if (p + 2*sizeof(uint8) > pass_end) return false;
|
||||
if (e.test(p + 2*sizeof(uint8) > pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
m_minPreCtxt = be::read<uint8>(p);
|
||||
m_maxPreCtxt = be::read<uint8>(p);
|
||||
if (m_minPreCtxt > m_maxPreCtxt) return false;
|
||||
if (e.test(m_minPreCtxt > m_maxPreCtxt, E_BADCTXTLENBOUNDS)) return face.error(e);
|
||||
const byte * const start_states = p;
|
||||
be::skip<int16>(p, m_maxPreCtxt - m_minPreCtxt + 1);
|
||||
const uint16 * const sort_keys = reinterpret_cast<const uint16 *>(p);
|
||||
@ -132,7 +133,7 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
be::skip<byte>(p, m_numRules);
|
||||
be::skip<byte>(p); // skip reserved byte
|
||||
|
||||
if (p + sizeof(uint16) > pass_end) return false;
|
||||
if (e.test(p + sizeof(uint16) > pass_end, E_BADCTXTLENS)) return face.error(e);
|
||||
const size_t pass_constraint_len = be::read<uint16>(p);
|
||||
const uint16 * const o_constraint = reinterpret_cast<const uint16 *>(p);
|
||||
be::skip<uint16>(p, m_numRules + 1);
|
||||
@ -141,31 +142,35 @@ bool Pass::readPass(const byte * const pass_start, size_t pass_length, size_t su
|
||||
const byte * const states = p;
|
||||
be::skip<int16>(p, m_numTransition*m_numColumns);
|
||||
be::skip<byte>(p); // skip reserved byte
|
||||
if (p != pcCode || p >= pass_end) return false;
|
||||
if (e.test(p != pcCode, E_BADPASSCCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
be::skip<byte>(p, pass_constraint_len);
|
||||
if (p != rcCode || p >= pass_end
|
||||
|| size_t(rcCode - pcCode) != pass_constraint_len) return false;
|
||||
if (e.test(p != rcCode, E_BADRULECCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)
|
||||
|| e.test(size_t(rcCode - pcCode) != pass_constraint_len, E_BADCCODELEN)) return face.error(e);
|
||||
be::skip<byte>(p, be::peek<uint16>(o_constraint + m_numRules));
|
||||
if (p != aCode || p >= pass_end) return false;
|
||||
if (e.test(p != aCode, E_BADACTIONCODEPTR) || e.test(p >= pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
be::skip<byte>(p, be::peek<uint16>(o_actions + m_numRules));
|
||||
|
||||
// We should be at the end or within the pass
|
||||
if (p > pass_end) return false;
|
||||
if (e.test(p > pass_end, E_BADPASSLENGTH)) return face.error(e);
|
||||
|
||||
// Load the pass constraint if there is one.
|
||||
if (pass_constraint_len)
|
||||
{
|
||||
face.error_context(face.error_context() + 1);
|
||||
m_cPConstraint = vm::Machine::Code(true, pcCode, pcCode + pass_constraint_len,
|
||||
precontext[0], be::peek<uint16>(sort_keys), *m_silf, face);
|
||||
if (!m_cPConstraint) return false;
|
||||
if (e.test(!m_cPConstraint, E_OUTOFMEM)
|
||||
|| e.test(m_cPConstraint.status(), m_cPConstraint.status() + E_CODEFAILURE))
|
||||
return face.error(e);
|
||||
face.error_context(face.error_context() - 1);
|
||||
}
|
||||
if (!readRanges(ranges, numRanges)) return false;
|
||||
if (!readRanges(ranges, numRanges, e)) return face.error(e);
|
||||
if (!readRules(rule_map, numEntries, precontext, sort_keys,
|
||||
o_constraint, rcCode, o_actions, aCode, face)) return false;
|
||||
o_constraint, rcCode, o_actions, aCode, face, e)) return false;
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _states_cat(face.tele.states);
|
||||
#endif
|
||||
return readStates(start_states, states, o_rule_map, face);
|
||||
return readStates(start_states, states, o_rule_map, face, e);
|
||||
}
|
||||
|
||||
|
||||
@ -173,12 +178,12 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
const byte *precontext, const uint16 * sort_key,
|
||||
const uint16 * o_constraint, const byte *rc_data,
|
||||
const uint16 * o_action, const byte * ac_data,
|
||||
const Face & face)
|
||||
Face & face, Error &e)
|
||||
{
|
||||
const byte * const ac_data_end = ac_data + be::peek<uint16>(o_action + m_numRules);
|
||||
const byte * const rc_data_end = rc_data + be::peek<uint16>(o_constraint + m_numRules);
|
||||
|
||||
if (!(m_rules = new Rule [m_numRules])) return false;
|
||||
if (e.test(!(m_rules = new Rule [m_numRules]), E_OUTOFMEM)) return face.error(e);
|
||||
precontext += m_numRules;
|
||||
sort_key += m_numRules;
|
||||
o_constraint += m_numRules;
|
||||
@ -191,6 +196,7 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
Rule * r = m_rules + m_numRules - 1;
|
||||
for (size_t n = m_numRules; n; --n, --r, ac_end = ac_begin, rc_end = rc_begin)
|
||||
{
|
||||
face.error_context((face.error_context() & 0xFFFF00) + EC_ARULE + ((n - 1) << 24));
|
||||
r->preContext = *--precontext;
|
||||
r->sort = be::peek<uint16>(--sort_key);
|
||||
#ifndef NDEBUG
|
||||
@ -208,19 +214,21 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
r->action = new vm::Machine::Code(false, ac_begin, ac_end, r->preContext, r->sort, *m_silf, face);
|
||||
r->constraint = new vm::Machine::Code(true, rc_begin, rc_end, r->preContext, r->sort, *m_silf, face);
|
||||
|
||||
if (!r->action || !r->constraint
|
||||
|| r->action->status() != Code::loaded
|
||||
|| r->constraint->status() != Code::loaded
|
||||
|| !r->constraint->immutable())
|
||||
return false;
|
||||
if (e.test(!r->action || !r->constraint, E_OUTOFMEM)
|
||||
|| e.test(r->action->status() != Code::loaded, r->action->status() + E_CODEFAILURE)
|
||||
|| e.test(r->constraint->status() != Code::loaded, r->constraint->status() + E_CODEFAILURE)
|
||||
|| e.test(!r->constraint->immutable(), E_MUTABLECCODE))
|
||||
return face.error(e);
|
||||
}
|
||||
|
||||
// Load the rule entries map
|
||||
face.error_context((face.error_context() & 0xFFFF00) + EC_APASS);
|
||||
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)
|
||||
{
|
||||
const ptrdiff_t rn = be::read<uint16>(rule_map);
|
||||
if (rn >= m_numRules) return false;
|
||||
if (e.test(rn >= m_numRules, E_BADRULENUM)) return face.error(e);
|
||||
re->rule = m_rules + rn;
|
||||
}
|
||||
|
||||
@ -230,7 +238,7 @@ bool Pass::readRules(const byte * rule_map, const size_t num_entries,
|
||||
static int cmpRuleEntry(const void *a, const void *b) { return (*(RuleEntry *)a < *(RuleEntry *)b ? -1 :
|
||||
(*(RuleEntry *)b < *(RuleEntry *)a ? 1 : 0)); }
|
||||
|
||||
bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map, GR_MAYBE_UNUSED const Face & face)
|
||||
bool Pass::readStates(const byte * starts, const byte *states, const byte * o_rule_map, GR_MAYBE_UNUSED Face & face, Error &e)
|
||||
{
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::category _states_cat(face.tele.starts);
|
||||
@ -245,13 +253,17 @@ bool Pass::readStates(const byte * starts, const byte *states, const byte * o_ru
|
||||
#endif
|
||||
m_transitions = gralloc<uint16>(m_numTransition * m_numColumns);
|
||||
|
||||
if (!m_startStates || !m_states || !m_transitions) return false;
|
||||
if (e.test(!m_startStates || !m_states || !m_transitions, E_OUTOFMEM)) return face.error(e);
|
||||
// load start states
|
||||
for (uint16 * s = m_startStates,
|
||||
* const s_end = s + m_maxPreCtxt - m_minPreCtxt + 1; s != s_end; ++s)
|
||||
{
|
||||
*s = be::read<uint16>(starts);
|
||||
if (*s >= m_numStates) return false; // true;
|
||||
if (e.test(*s >= m_numStates, E_BADSTATE))
|
||||
{
|
||||
face.error_context((face.error_context() & 0xFFFF00) + EC_ASTARTS + ((s - m_startStates) << 24));
|
||||
return face.error(e); // true;
|
||||
}
|
||||
}
|
||||
|
||||
// load state transition table.
|
||||
@ -259,7 +271,11 @@ bool Pass::readStates(const byte * starts, const byte *states, const byte * o_ru
|
||||
* const t_end = t + m_numTransition*m_numColumns; t != t_end; ++t)
|
||||
{
|
||||
*t = be::read<uint16>(states);
|
||||
if (*t >= m_numStates) return false;
|
||||
if (e.test(*t >= m_numStates, E_BADSTATE))
|
||||
{
|
||||
face.error_context((face.error_context() & 0xFFFF00) + EC_ATRANS + (((t - m_transitions) / m_numColumns) << 24));
|
||||
return face.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
State * s = m_states,
|
||||
@ -270,8 +286,11 @@ bool Pass::readStates(const byte * starts, const byte *states, const byte * o_ru
|
||||
RuleEntry * const begin = s < success_begin ? 0 : m_ruleMap + be::read<uint16>(o_rule_map),
|
||||
* const end = s < success_begin ? 0 : m_ruleMap + be::peek<uint16>(o_rule_map);
|
||||
|
||||
if (begin >= rule_map_end || end > rule_map_end || begin > end)
|
||||
return false;
|
||||
if (e.test(begin >= rule_map_end || end > rule_map_end || begin > end, E_BADRULEMAPPING))
|
||||
{
|
||||
face.error_context((face.error_context() & 0xFFFF00) + EC_ARULEMAP + (n << 24));
|
||||
return face.error(e);
|
||||
}
|
||||
s->rules = begin;
|
||||
s->rules_end = (end - begin <= FiniteStateMachine::MAX_RULES)? end :
|
||||
begin + FiniteStateMachine::MAX_RULES;
|
||||
@ -281,9 +300,10 @@ bool Pass::readStates(const byte * starts, const byte *states, const byte * o_ru
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Pass::readRanges(const byte * ranges, size_t num_ranges)
|
||||
bool Pass::readRanges(const byte * ranges, size_t num_ranges, Error &e)
|
||||
{
|
||||
m_cols = gralloc<uint16>(m_numGlyphs);
|
||||
if (e.test(!m_cols, E_OUTOFMEM)) return false;
|
||||
memset(m_cols, 0xFF, m_numGlyphs * sizeof(uint16));
|
||||
for (size_t n = num_ranges; n; --n)
|
||||
{
|
||||
@ -291,14 +311,14 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges)
|
||||
* ci_end = m_cols + be::read<uint16>(ranges) + 1,
|
||||
col = be::read<uint16>(ranges);
|
||||
|
||||
if (ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_numColumns)
|
||||
if (e.test(ci >= ci_end || ci_end > m_cols+m_numGlyphs || col >= m_numColumns, E_BADRANGE))
|
||||
return false;
|
||||
|
||||
// A glyph must only belong to one column at a time
|
||||
while (ci != ci_end && *ci == 0xffff)
|
||||
*ci++ = col;
|
||||
|
||||
if (ci != ci_end)
|
||||
if (e.test(ci != ci_end, E_BADRANGE))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -307,13 +327,13 @@ bool Pass::readRanges(const byte * ranges, size_t num_ranges)
|
||||
|
||||
void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const
|
||||
{
|
||||
Slot *s = m.slotMap().segment.first();
|
||||
if (!s || !testPassConstraint(m)) return;
|
||||
Slot *s = m.slotMap().segment.first();
|
||||
if (!s || !testPassConstraint(m)) return;
|
||||
Slot *currHigh = s->next();
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (fsm.dbgout) *fsm.dbgout << "rules" << json::array;
|
||||
json::closer rules_array_closer(fsm.dbgout);
|
||||
if (fsm.dbgout) *fsm.dbgout << "rules" << json::array;
|
||||
json::closer rules_array_closer(fsm.dbgout);
|
||||
#endif
|
||||
|
||||
m.slotMap().highwater(currHigh);
|
||||
@ -322,21 +342,21 @@ void Pass::runGraphite(Machine & m, FiniteStateMachine & fsm) const
|
||||
{
|
||||
findNDoRule(s, m, fsm);
|
||||
if (s && (m.slotMap().highpassed() || s == m.slotMap().highwater() || --lc == 0)) {
|
||||
if (!lc)
|
||||
{
|
||||
// if (dbgout) *dbgout << json::item << json::flat << rule_event(-1, s, 1);
|
||||
s = m.slotMap().highwater();
|
||||
}
|
||||
lc = m_iMaxLoop;
|
||||
if (!lc)
|
||||
{
|
||||
// if (dbgout) *dbgout << json::item << json::flat << rule_event(-1, s, 1);
|
||||
s = m.slotMap().highwater();
|
||||
}
|
||||
lc = m_iMaxLoop;
|
||||
if (s)
|
||||
m.slotMap().highwater(s->next());
|
||||
m.slotMap().highwater(s->next());
|
||||
}
|
||||
} while (s);
|
||||
}
|
||||
|
||||
bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const
|
||||
{
|
||||
fsm.reset(slot, m_maxPreCtxt);
|
||||
fsm.reset(slot, m_maxPreCtxt);
|
||||
if (fsm.slots.context() < m_minPreCtxt)
|
||||
return false;
|
||||
|
||||
@ -368,17 +388,17 @@ bool Pass::runFSM(FiniteStateMachine& fsm, Slot * slot) const
|
||||
inline
|
||||
Slot * input_slot(const SlotMap & slots, const int n)
|
||||
{
|
||||
Slot * s = slots[slots.context() + n];
|
||||
if (!s->isCopied()) return s;
|
||||
Slot * s = slots[slots.context() + n];
|
||||
if (!s->isCopied()) return s;
|
||||
|
||||
return s->prev() ? s->prev()->next() : (s->next() ? s->next()->prev() : slots.segment.last());
|
||||
return s->prev() ? s->prev()->next() : (s->next() ? s->next()->prev() : slots.segment.last());
|
||||
}
|
||||
|
||||
inline
|
||||
Slot * output_slot(const SlotMap & slots, const int n)
|
||||
{
|
||||
Slot * s = slots[slots.context() + n - 1];
|
||||
return s ? s->next() : slots.segment.first();
|
||||
Slot * s = slots[slots.context() + n - 1];
|
||||
return s ? s->next() : slots.segment.first();
|
||||
}
|
||||
|
||||
#endif //!defined GRAPHITE2_NTRACING
|
||||
@ -397,40 +417,40 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (fsm.dbgout)
|
||||
{
|
||||
if (fsm.rules.size() != 0)
|
||||
{
|
||||
*fsm.dbgout << json::item << json::object;
|
||||
dumpRuleEventConsidered(fsm, *r);
|
||||
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();
|
||||
adjustSlot(adv, slot, fsm.slots);
|
||||
*fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
|
||||
<< json::close; // Close RuelEvent object
|
||||
if (fsm.rules.size() != 0)
|
||||
{
|
||||
*fsm.dbgout << json::item << json::object;
|
||||
dumpRuleEventConsidered(fsm, *r);
|
||||
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();
|
||||
adjustSlot(adv, slot, fsm.slots);
|
||||
*fsm.dbgout << "cursor" << objectid(dslot(&fsm.slots.segment, slot))
|
||||
<< json::close; // Close RuelEvent object
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
*fsm.dbgout << json::close // close "considered" array
|
||||
<< "output" << json::null
|
||||
<< "cursor" << objectid(dslot(&fsm.slots.segment, slot->next()))
|
||||
<< json::close;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
*fsm.dbgout << json::close // close "considered" array
|
||||
<< "output" << json::null
|
||||
<< "cursor" << objectid(dslot(&fsm.slots.segment, slot->next()))
|
||||
<< json::close;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (r != re)
|
||||
{
|
||||
const int adv = doAction(r->rule->action, slot, m);
|
||||
if (r->rule->action->deletes()) fsm.slots.collectGarbage();
|
||||
adjustSlot(adv, slot, fsm.slots);
|
||||
return;
|
||||
}
|
||||
if (r != re)
|
||||
{
|
||||
const int adv = doAction(r->rule->action, slot, m);
|
||||
if (r->rule->action->deletes()) fsm.slots.collectGarbage();
|
||||
adjustSlot(adv, slot, fsm.slots);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -441,47 +461,47 @@ void Pass::findNDoRule(Slot * & slot, Machine &m, FiniteStateMachine & fsm) cons
|
||||
|
||||
void Pass::dumpRuleEventConsidered(const FiniteStateMachine & fsm, const RuleEntry & re) const
|
||||
{
|
||||
*fsm.dbgout << "considered" << json::array;
|
||||
for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r)
|
||||
{
|
||||
if (r->rule->preContext > fsm.slots.context()) continue;
|
||||
*fsm.dbgout << json::flat << json::object
|
||||
<< "id" << r->rule - m_rules
|
||||
<< "failed" << true
|
||||
<< "input" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
|
||||
<< "length" << r->rule->sort
|
||||
<< json::close // close "input"
|
||||
<< json::close; // close Rule object
|
||||
}
|
||||
*fsm.dbgout << "considered" << json::array;
|
||||
for (const RuleEntry *r = fsm.rules.begin(); r != &re; ++r)
|
||||
{
|
||||
if (r->rule->preContext > fsm.slots.context()) continue;
|
||||
*fsm.dbgout << json::flat << json::object
|
||||
<< "id" << r->rule - m_rules
|
||||
<< "failed" << true
|
||||
<< "input" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, -r->rule->preContext)))
|
||||
<< "length" << r->rule->sort
|
||||
<< json::close // close "input"
|
||||
<< json::close; // close Rule object
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Pass::dumpRuleEventOutput(const FiniteStateMachine & fsm, const Rule & r, Slot * const last_slot) const
|
||||
{
|
||||
*fsm.dbgout << json::item << json::flat << json::object
|
||||
<< "id" << &r - m_rules
|
||||
<< "failed" << false
|
||||
<< "input" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
|
||||
<< "length" << r.sort - r.preContext
|
||||
<< json::close // close "input"
|
||||
<< json::close // close Rule object
|
||||
<< json::close // close considered array
|
||||
<< "output" << json::object
|
||||
<< "range" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
|
||||
<< "end" << objectid(dslot(&fsm.slots.segment, last_slot))
|
||||
<< 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.dbgout << json::item << json::flat << json::object
|
||||
<< "id" << &r - m_rules
|
||||
<< "failed" << false
|
||||
<< "input" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
|
||||
<< "length" << r.sort - r.preContext
|
||||
<< json::close // close "input"
|
||||
<< json::close // close Rule object
|
||||
<< json::close // close considered array
|
||||
<< "output" << json::object
|
||||
<< "range" << json::flat << json::object
|
||||
<< "start" << objectid(dslot(&fsm.slots.segment, input_slot(fsm.slots, 0)))
|
||||
<< "end" << objectid(dslot(&fsm.slots.segment, last_slot))
|
||||
<< 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);
|
||||
|
||||
for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
|
||||
*fsm.dbgout << dslot(&fsm.slots.segment, slot);
|
||||
*fsm.dbgout << json::close // close "slots"
|
||||
<< "postshift" << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos
|
||||
<< json::close; // close "output" object
|
||||
for(Slot * slot = output_slot(fsm.slots, 0); slot != last_slot; slot = slot->next())
|
||||
*fsm.dbgout << dslot(&fsm.slots.segment, slot);
|
||||
*fsm.dbgout << json::close // close "slots"
|
||||
<< "postshift" << (last_slot ? last_slot->origin() : fsm.slots.segment.advance()) - rsb_prepos
|
||||
<< json::close; // close "output" object
|
||||
|
||||
}
|
||||
|
||||
@ -503,7 +523,7 @@ bool Pass::testPassConstraint(Machine & m) const
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
json * const dbgout = m.slotMap().segment.getFace()->logger();
|
||||
if (dbgout)
|
||||
*dbgout << "constraint" << (ret && m.status() == Machine::finished);
|
||||
*dbgout << "constraint" << (ret && m.status() == Machine::finished);
|
||||
#endif
|
||||
|
||||
return ret && m.status() == Machine::finished;
|
||||
@ -512,16 +532,16 @@ bool Pass::testPassConstraint(Machine & m) const
|
||||
|
||||
bool Pass::testConstraint(const Rule & r, Machine & m) const
|
||||
{
|
||||
const uint16 curr_context = m.slotMap().context();
|
||||
const uint16 curr_context = m.slotMap().context();
|
||||
if (unsigned(r.sort - r.preContext) > m.slotMap().size() - curr_context
|
||||
|| curr_context - r.preContext < 0) return false;
|
||||
|| curr_context - r.preContext < 0) return false;
|
||||
if (!*r.constraint) return true;
|
||||
assert(r.constraint->constraint());
|
||||
|
||||
vm::slotref * map = m.slotMap().begin() + curr_context - r.preContext;
|
||||
for (int n = r.sort; n && map; --n, ++map)
|
||||
{
|
||||
if (!*map) continue;
|
||||
if (!*map) continue;
|
||||
const int32 ret = r.constraint->run(m, map);
|
||||
if (!ret || m.status() != Machine::finished)
|
||||
return false;
|
||||
@ -554,9 +574,9 @@ int Pass::doAction(const Code *codeptr, Slot * & slot_out, vm::Machine & m) cons
|
||||
|
||||
if (m.status() != Machine::finished)
|
||||
{
|
||||
slot_out = NULL;
|
||||
smap.highwater(0);
|
||||
return 0;
|
||||
slot_out = NULL;
|
||||
smap.highwater(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
slot_out = *map;
|
||||
@ -573,12 +593,12 @@ void Pass::adjustSlot(int delta, Slot * & slot_out, SlotMap & smap) const
|
||||
slot_out = smap.segment.last();
|
||||
++delta;
|
||||
if (smap.highpassed() && !smap.highwater())
|
||||
smap.highpassed(false);
|
||||
smap.highpassed(false);
|
||||
}
|
||||
while (++delta <= 0 && slot_out)
|
||||
{
|
||||
if (smap.highpassed() && smap.highwater() == slot_out)
|
||||
smap.highpassed(false);
|
||||
smap.highpassed(false);
|
||||
slot_out = slot_out->prev();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
|
@ -41,12 +41,13 @@ SegCacheEntry::SegCacheEntry(const uint16* cmapGlyphs, size_t length, Segment *
|
||||
m_attr(NULL), m_justs(NULL),
|
||||
m_accessCount(0), m_lastAccess(cacheTime)
|
||||
{
|
||||
for (uint16 i = 0; i < length; i++)
|
||||
{
|
||||
m_unicode[i] = cmapGlyphs[i];
|
||||
}
|
||||
if (m_unicode)
|
||||
for (uint16 i = 0; i < length; i++)
|
||||
m_unicode[i] = cmapGlyphs[i];
|
||||
|
||||
const size_t glyphCount = seg->slotCount(),
|
||||
sizeof_sjust = SlotJustify::size_of(seg->silf()->numJustLevels());
|
||||
if (!glyphCount) return;
|
||||
size_t num_justs = 0,
|
||||
justs_pos = 0;
|
||||
if (seg->hasJustification())
|
||||
@ -61,6 +62,7 @@ SegCacheEntry::SegCacheEntry(const uint16* cmapGlyphs, size_t length, Segment *
|
||||
const Slot * slot = seg->first();
|
||||
m_glyph = new Slot[glyphCount];
|
||||
m_attr = gralloc<int16>(glyphCount * seg->numAttrs());
|
||||
if (!m_glyph || (!m_attr && seg->numAttrs())) return;
|
||||
m_glyphLength = glyphCount;
|
||||
Slot * slotCopy = m_glyph;
|
||||
m_glyph->prev(NULL);
|
||||
@ -70,14 +72,14 @@ SegCacheEntry::SegCacheEntry(const uint16* cmapGlyphs, size_t length, Segment *
|
||||
{
|
||||
slotCopy->userAttrs(m_attr + pos * seg->numAttrs());
|
||||
slotCopy->m_justs = m_justs ? reinterpret_cast<SlotJustify *>(m_justs + justs_pos++ * sizeof_sjust) : 0;
|
||||
slotCopy->set(*slot, -static_cast<int32>(charOffset), seg->numAttrs(), seg->silf()->numJustLevels());
|
||||
slotCopy->set(*slot, -static_cast<int32>(charOffset), seg->numAttrs(), seg->silf()->numJustLevels(), length);
|
||||
slotCopy->index(pos);
|
||||
if (slot->firstChild())
|
||||
slotCopy->m_child = m_glyph + slot->firstChild()->index();
|
||||
slotCopy->m_child = m_glyph + slot->firstChild()->index();
|
||||
if (slot->attachedTo())
|
||||
slotCopy->attachTo(m_glyph + slot->attachedTo()->index());
|
||||
slotCopy->attachTo(m_glyph + slot->attachedTo()->index());
|
||||
if (slot->nextSibling())
|
||||
slotCopy->m_sibling = m_glyph + slot->nextSibling()->index();
|
||||
slotCopy->m_sibling = m_glyph + slot->nextSibling()->index();
|
||||
slot = slot->next();
|
||||
++slotCopy;
|
||||
++pos;
|
||||
|
@ -36,6 +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 "graphite2/Segment.h"
|
||||
|
||||
|
||||
@ -106,15 +107,15 @@ void Segment::removeScope(SegmentScopeState & state)
|
||||
m_defaultOriginal = 0;
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
void Segment::append(const Segment &other)
|
||||
{
|
||||
Rect bbox = other.m_bbox + m_advance;
|
||||
|
||||
m_slots.insert(m_slots.end(), other.m_slots.begin(), other.m_slots.end());
|
||||
CharInfo* pNewCharInfo = new CharInfo[m_numCharinfo+other.m_numCharinfo]; //since CharInfo has no constructor, this doesn't do much
|
||||
CharInfo* pNewCharInfo = new CharInfo[m_numCharinfo+other.m_numCharinfo]; //since CharInfo has no constructor, this doesn't do much
|
||||
for (unsigned int i=0 ; i<m_numCharinfo ; ++i)
|
||||
pNewCharInfo[i] = m_charinfo[i];
|
||||
pNewCharInfo[i] = m_charinfo[i];
|
||||
m_last->next(other.m_first);
|
||||
other.m_last->prev(m_last);
|
||||
m_userAttrs.insert(m_userAttrs.end(), other.m_userAttrs.begin(), other.m_userAttrs.end());
|
||||
@ -131,12 +132,14 @@ void Segment::append(const Segment &other)
|
||||
m_bbox = m_bbox.widen(bbox);
|
||||
m_passBits &= other.passBits();
|
||||
}
|
||||
#endif
|
||||
#endif // GRAPHITE2_NSEGCACHE
|
||||
|
||||
void Segment::appendSlot(int id, int cid, int gid, int iFeats, size_t coffset)
|
||||
{
|
||||
Slot *aSlot = newSlot();
|
||||
|
||||
if (!aSlot) return;
|
||||
m_charinfo[id].init(cid);
|
||||
m_charinfo[id].feats(iFeats);
|
||||
m_charinfo[id].base(coffset);
|
||||
@ -167,14 +170,15 @@ Slot *Segment::newSlot()
|
||||
#endif
|
||||
Slot *newSlots = grzeroalloc<Slot>(m_bufSize);
|
||||
int16 *newAttrs = grzeroalloc<int16>(numUser * m_bufSize);
|
||||
newSlots[0].userAttrs(newAttrs);
|
||||
for (size_t i = 1; i < m_bufSize - 1; i++)
|
||||
if (!newSlots || !newAttrs) return NULL;
|
||||
for (size_t i = 0; i < m_bufSize; i++)
|
||||
{
|
||||
newSlots[i].next(newSlots + i + 1);
|
||||
newSlots[i].userAttrs(newAttrs + i * numUser);
|
||||
newSlots[i].setBidiClass(-1);
|
||||
}
|
||||
newSlots[m_bufSize - 1].userAttrs(newAttrs + (m_bufSize - 1) * numUser);
|
||||
newSlots[m_bufSize - 1].next(NULL);
|
||||
newSlots[0].next(NULL);
|
||||
m_slots.push_back(newSlots);
|
||||
m_userAttrs.push_back(newAttrs);
|
||||
m_freeSlots = (m_bufSize > 1)? newSlots + 1 : NULL;
|
||||
@ -219,6 +223,7 @@ SlotJustify *Segment::newJustify()
|
||||
{
|
||||
const size_t justSize = SlotJustify::size_of(m_silf->numJustLevels());
|
||||
byte *justs = grzeroalloc<byte>(justSize * m_bufSize);
|
||||
if (!justs) return NULL;
|
||||
for (int i = m_bufSize - 2; i >= 0; --i)
|
||||
{
|
||||
SlotJustify *p = reinterpret_cast<SlotJustify *>(justs + justSize * i);
|
||||
@ -248,6 +253,7 @@ void Segment::splice(size_t offset, size_t length, Slot * const startSlot,
|
||||
Slot * endSlot, const Slot * srcSlot,
|
||||
const size_t numGlyphs)
|
||||
{
|
||||
size_t numChars = length;
|
||||
extendLength(numGlyphs - length);
|
||||
// remove any extra
|
||||
if (numGlyphs < length)
|
||||
@ -268,6 +274,7 @@ void Segment::splice(size_t offset, size_t length, Slot * const startSlot,
|
||||
while (numGlyphs > length)
|
||||
{
|
||||
Slot * extra = newSlot();
|
||||
if (!extra) return;
|
||||
extra->prev(endSlot);
|
||||
extra->next(endSlot->next());
|
||||
endSlot->next(extra);
|
||||
@ -282,60 +289,60 @@ void Segment::splice(size_t offset, size_t length, Slot * const startSlot,
|
||||
|
||||
endSlot = endSlot->next();
|
||||
assert(numGlyphs == length);
|
||||
assert(offset + numChars <= m_numCharinfo);
|
||||
Slot * indexmap[eMaxSpliceSize*3];
|
||||
assert(numGlyphs < sizeof indexmap/sizeof *indexmap);
|
||||
Slot * slot = startSlot;
|
||||
for (uint16 i=0; i < numGlyphs; slot = slot->next(), ++i)
|
||||
indexmap[i] = slot;
|
||||
indexmap[i] = slot;
|
||||
|
||||
slot = startSlot;
|
||||
for (slot=startSlot; slot != endSlot; slot = slot->next(), srcSlot = srcSlot->next())
|
||||
for (slot = startSlot; slot != endSlot; slot = slot->next(), srcSlot = srcSlot->next())
|
||||
{
|
||||
slot->set(*srcSlot, offset, m_silf->numUser(), m_silf->numJustLevels());
|
||||
if (srcSlot->attachedTo()) slot->attachTo(indexmap[srcSlot->attachedTo()->index()]);
|
||||
if (srcSlot->nextSibling()) slot->m_sibling = indexmap[srcSlot->nextSibling()->index()];
|
||||
if (srcSlot->firstChild()) slot->m_child = indexmap[srcSlot->firstChild()->index()];
|
||||
slot->set(*srcSlot, offset, m_silf->numUser(), m_silf->numJustLevels(), numChars);
|
||||
if (srcSlot->attachedTo()) slot->attachTo(indexmap[srcSlot->attachedTo()->index()]);
|
||||
if (srcSlot->nextSibling()) slot->m_sibling = indexmap[srcSlot->nextSibling()->index()];
|
||||
if (srcSlot->firstChild()) slot->m_child = indexmap[srcSlot->firstChild()->index()];
|
||||
}
|
||||
}
|
||||
#endif // GRAPHITE2_NSEGCACHE
|
||||
|
||||
void Segment::linkClusters(Slot *s, Slot * end)
|
||||
{
|
||||
end = end->next();
|
||||
end = end->next();
|
||||
|
||||
for (; s != end && !s->isBase(); s = s->next());
|
||||
Slot * ls = s;
|
||||
for (; s != end && !s->isBase(); s = s->next());
|
||||
Slot * ls = s;
|
||||
|
||||
if (m_dir & 1)
|
||||
{
|
||||
for (; s != end; s = s->next())
|
||||
{
|
||||
if (!s->isBase()) continue;
|
||||
if (m_dir & 1)
|
||||
{
|
||||
for (; s != end; s = s->next())
|
||||
{
|
||||
if (!s->isBase()) continue;
|
||||
|
||||
s->sibling(ls);
|
||||
ls = s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; s != end; s = s->next())
|
||||
{
|
||||
if (!s->isBase()) continue;
|
||||
s->sibling(ls);
|
||||
ls = s;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; s != end; s = s->next())
|
||||
{
|
||||
if (!s->isBase()) continue;
|
||||
|
||||
ls->sibling(s);
|
||||
ls = s;
|
||||
}
|
||||
}
|
||||
ls->sibling(s);
|
||||
ls = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
|
||||
{
|
||||
Position currpos(0., 0.);
|
||||
Rect bbox;
|
||||
float clusterMin = 0.;
|
||||
Rect bbox;
|
||||
|
||||
if (!iStart) iStart = m_first;
|
||||
if (!iEnd) iEnd = m_last;
|
||||
if (!iStart) iStart = m_first;
|
||||
if (!iEnd) iEnd = m_last;
|
||||
|
||||
if (m_dir & 1)
|
||||
{
|
||||
@ -357,20 +364,39 @@ Position Segment::positionSlots(const Font *font, Slot * iStart, Slot * iEnd)
|
||||
}
|
||||
|
||||
|
||||
void Segment::associateChars()
|
||||
void Segment::associateChars(int offset, int numChars)
|
||||
{
|
||||
int i = 0;
|
||||
int i = 0, j = 0;
|
||||
CharInfo *c, *cend;
|
||||
for (c = m_charinfo + offset, cend = m_charinfo + offset + numChars; c != cend; ++c)
|
||||
{
|
||||
c->before(-1);
|
||||
c->after(-1);
|
||||
}
|
||||
for (Slot * s = m_first; s; s->index(i++), s = s->next())
|
||||
{
|
||||
int j = s->before();
|
||||
if (j < 0) continue;
|
||||
j = s->before();
|
||||
if (j < 0) continue;
|
||||
|
||||
for (const int after = s->after(); j <= after; ++j)
|
||||
{
|
||||
CharInfo & c = *charinfo(j);
|
||||
if (c.before() == -1 || i < c.before()) c.before(i);
|
||||
if (c.after() < i) c.after(i);
|
||||
}
|
||||
{
|
||||
c = charinfo(j);
|
||||
if (c->before() == -1 || i < c->before()) c->before(i);
|
||||
if (c->after() < i) c->after(i);
|
||||
}
|
||||
}
|
||||
for (Slot *s = m_first; s; s = s->next())
|
||||
{
|
||||
int a;
|
||||
for (a = s->after() + 1; a < offset + numChars && charinfo(a)->after() < 0; ++a)
|
||||
{ charinfo(a)->after(s->index()); }
|
||||
--a;
|
||||
s->after(a);
|
||||
|
||||
for (a = s->before() - 1; a >= offset && charinfo(a)->before() < 0; --a)
|
||||
{ charinfo(a)->before(s->index()); }
|
||||
++a;
|
||||
s->before(a);
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,31 +404,34 @@ void Segment::associateChars()
|
||||
template <typename utf_iter>
|
||||
inline void process_utf_data(Segment & seg, const Face & face, const int fid, utf_iter c, size_t n_chars)
|
||||
{
|
||||
const Cmap & cmap = face.cmap();
|
||||
int slotid = 0;
|
||||
const Cmap & cmap = face.cmap();
|
||||
int slotid = 0;
|
||||
|
||||
const typename utf_iter::codeunit_type * const base = c;
|
||||
for (; n_chars; --n_chars, ++c, ++slotid)
|
||||
{
|
||||
const uint32 usv = *c;
|
||||
uint16 gid = cmap[usv];
|
||||
if (!gid) gid = face.findPseudo(usv);
|
||||
seg.appendSlot(slotid, usv, gid, fid, c - base);
|
||||
}
|
||||
const typename utf_iter::codeunit_type * const base = c;
|
||||
for (; n_chars; --n_chars, ++c, ++slotid)
|
||||
{
|
||||
const uint32 usv = *c;
|
||||
uint16 gid = cmap[usv];
|
||||
if (!gid) gid = face.findPseudo(usv);
|
||||
seg.appendSlot(slotid, usv, gid, fid, c - base);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
|
||||
bool Segment::read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void* pStart, size_t nChars)
|
||||
{
|
||||
assert(face);
|
||||
assert(pFeats);
|
||||
assert(face);
|
||||
assert(pFeats);
|
||||
if (!m_charinfo) return false;
|
||||
|
||||
switch (enc)
|
||||
{
|
||||
case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
|
||||
case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
|
||||
case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
|
||||
}
|
||||
// utf iterator is self recovering so we don't care about the error state of the iterator.
|
||||
switch (enc)
|
||||
{
|
||||
case gr_utf8: process_utf_data(*this, *face, addFeatures(*pFeats), utf8::const_iterator(pStart), nChars); break;
|
||||
case gr_utf16: process_utf_data(*this, *face, addFeatures(*pFeats), utf16::const_iterator(pStart), nChars); break;
|
||||
case gr_utf32: process_utf_data(*this, *face, addFeatures(*pFeats), utf32::const_iterator(pStart), nChars); break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Segment::prepare_pos(const Font * /*font*/)
|
||||
@ -410,41 +439,48 @@ void Segment::prepare_pos(const Font * /*font*/)
|
||||
// copy key changeable metrics into slot (if any);
|
||||
}
|
||||
|
||||
Slot *resolveExplicit(int level, int dir, Slot *s, int nNest = 0);
|
||||
void resolveWeak(int baseLevel, Slot *s);
|
||||
void resolveNeutrals(int baseLevel, Slot *s);
|
||||
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, Segment *seg, uint8 aBidi, Slot *s);
|
||||
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)
|
||||
{
|
||||
if (slotCount() == 0)
|
||||
return;
|
||||
if (slotCount() == 0)
|
||||
return;
|
||||
|
||||
Slot *s;
|
||||
int baseLevel = paradir ? 1 : 0;
|
||||
unsigned int bmask = 0;
|
||||
unsigned int ssize = 0;
|
||||
for (s = first(); s; s = s->next())
|
||||
{
|
||||
unsigned int bAttr = glyphAttr(s->gid(), aBidi);
|
||||
s->setBidiClass((bAttr <= 16) * bAttr);
|
||||
if (s->getBidiClass() == -1)
|
||||
{
|
||||
unsigned int bAttr = glyphAttr(s->gid(), aBidi);
|
||||
s->setBidiClass((bAttr <= 22) * bAttr);
|
||||
}
|
||||
bmask |= (1 << s->getBidiClass());
|
||||
s->setBidiLevel(baseLevel);
|
||||
if (glyphAttr(s->gid(), aMirror) && s->getBidiClass() == 21)
|
||||
++ssize;
|
||||
}
|
||||
if (bmask & (paradir ? 0x92 : 0x9C))
|
||||
|
||||
BracketPairStack bstack(ssize);
|
||||
if (bmask & (paradir ? 0x2E7892 : 0x2E789C))
|
||||
{
|
||||
if (bmask & 0xF800)
|
||||
resolveExplicit(baseLevel, 0, first(), 0);
|
||||
if (bmask & 0x10178)
|
||||
resolveWeak(baseLevel, first());
|
||||
if (bmask & 0x361)
|
||||
resolveNeutrals(baseLevel, first());
|
||||
// O(8N) algorithm, with no working data beyond what is needed for processParens
|
||||
int nextLevel = paradir;
|
||||
int e, i, c;
|
||||
process_bidi(first(), baseLevel, paradir, nextLevel, 0, 0, c = 0, i = 0, e = 0, 1, this, aMirror, bstack);
|
||||
resolveImplicit(first(), this, aMirror);
|
||||
resolveWhitespace(baseLevel, this, aBidi, last());
|
||||
resolveWhitespace(baseLevel, last());
|
||||
s = resolveOrder(s = first(), baseLevel != 0);
|
||||
first(s); last(s->prev());
|
||||
s->prev()->next(0); s->prev(0);
|
||||
if (s)
|
||||
{
|
||||
first(s); last(s->prev());
|
||||
s->prev()->next(0); s->prev(0);
|
||||
}
|
||||
}
|
||||
else if (!(dir() & 4) && baseLevel && aMirror)
|
||||
{
|
||||
|
@ -31,6 +31,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/Silf.h"
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/Rule.h"
|
||||
#include "inc/Error.h"
|
||||
|
||||
|
||||
using namespace graphite2;
|
||||
@ -86,18 +87,19 @@ void Silf::releaseBuffers() throw()
|
||||
}
|
||||
|
||||
|
||||
bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, const Face& face, uint32 version)
|
||||
bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, Face& face, uint32 version)
|
||||
{
|
||||
const byte * p = silf_start,
|
||||
* const silf_end = p + lSilf;
|
||||
* const silf_end = p + lSilf;
|
||||
Error e;
|
||||
|
||||
if (version >= 0x00030000)
|
||||
{
|
||||
if (lSilf < 28) { releaseBuffers(); return false; }
|
||||
be::skip<int32>(p); // ruleVersion
|
||||
if (e.test(lSilf < 28, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
|
||||
be::skip<int32>(p); // ruleVersion
|
||||
be::skip<uint16>(p,2); // passOffset & pseudosOffset
|
||||
}
|
||||
else if (lSilf < 20) { releaseBuffers(); return false; }
|
||||
else if (e.test(lSilf < 20, E_BADSIZE)) { releaseBuffers(); return face.error(e); }
|
||||
const uint16 maxGlyph = be::read<uint16>(p);
|
||||
m_silfinfo.extra_ascent = be::read<uint16>(p);
|
||||
m_silfinfo.extra_descent = be::read<uint16>(p);
|
||||
@ -116,45 +118,59 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, const Face&
|
||||
|
||||
// Read Justification levels.
|
||||
m_numJusts = be::read<uint8>(p);
|
||||
if (maxGlyph >= face.glyphs().numGlyphs()
|
||||
|| p + m_numJusts * 8 >= silf_end) { releaseBuffers(); return false; }
|
||||
m_justs = gralloc<Justinfo>(m_numJusts);
|
||||
for (uint8 i = 0; i < m_numJusts; i++)
|
||||
if (e.test(maxGlyph >= face.glyphs().numGlyphs(), E_BADMAXGLYPH)
|
||||
|| e.test(p + m_numJusts * 8 >= silf_end, E_BADNUMJUSTS))
|
||||
{
|
||||
::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
|
||||
be::skip<byte>(p,8);
|
||||
releaseBuffers(); return face.error(e);
|
||||
}
|
||||
|
||||
if (p + sizeof(uint16) + sizeof(uint8)*8 >= silf_end) { releaseBuffers(); return false; }
|
||||
if (m_numJusts)
|
||||
{
|
||||
m_justs = gralloc<Justinfo>(m_numJusts);
|
||||
if (e.test(!m_justs, E_OUTOFMEM)) return face.error(e);
|
||||
|
||||
for (uint8 i = 0; i < m_numJusts; i++)
|
||||
{
|
||||
::new(m_justs + i) Justinfo(p[0], p[1], p[2], p[3]);
|
||||
be::skip<byte>(p,8);
|
||||
}
|
||||
}
|
||||
|
||||
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,5); // direction and 4 reserved bytes
|
||||
be::skip<uint16>(p, be::read<uint8>(p)); // don't need critical features yet
|
||||
be::skip<byte>(p); // reserved
|
||||
if (p >= silf_end) { releaseBuffers(); return false; }
|
||||
be::skip<uint32>(p, be::read<uint8>(p)); // don't use scriptTag array.
|
||||
if (p + sizeof(uint16) + sizeof(uint32) >= silf_end) { releaseBuffers(); return false; }
|
||||
be::skip<byte>(p,5); // direction and 4 reserved bytes
|
||||
be::skip<uint16>(p, be::read<uint8>(p)); // don't need critical features yet
|
||||
be::skip<byte>(p); // reserved
|
||||
if (e.test(p >= silf_end, E_BADCRITFEATURES)) { releaseBuffers(); return face.error(e); }
|
||||
be::skip<uint32>(p, be::read<uint8>(p)); // don't use scriptTag array.
|
||||
if (e.test(p + sizeof(uint16) + sizeof(uint32) >= silf_end, E_BADSCRIPTTAGS)) { releaseBuffers(); return face.error(e); }
|
||||
m_gEndLine = be::read<uint16>(p); // lbGID
|
||||
const byte * o_passes = p,
|
||||
* const passes_start = silf_start + be::read<uint32>(p);
|
||||
|
||||
const size_t num_attrs = face.glyphs().numAttrs();
|
||||
if (m_aPseudo >= num_attrs
|
||||
|| m_aBreak >= num_attrs
|
||||
|| m_aBidi >= num_attrs
|
||||
|| m_aMirror>= num_attrs
|
||||
|| m_numPasses > 128 || passes_start >= silf_end
|
||||
|| m_pPass < m_sPass || m_pPass > m_numPasses || m_sPass > m_numPasses
|
||||
|| m_jPass < m_pPass || m_jPass > m_numPasses
|
||||
|| (m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses))
|
||||
|| m_aLig > 127) { releaseBuffers(); return false; }
|
||||
if (e.test(m_aPseudo >= num_attrs, E_BADAPSEUDO)
|
||||
|| e.test(m_aBreak >= num_attrs, E_BADABREAK)
|
||||
|| e.test(m_aBidi >= num_attrs, E_BADABIDI)
|
||||
|| e.test(m_aMirror>= num_attrs, E_BADAMIRROR)
|
||||
|| e.test(m_numPasses > 128, E_BADNUMPASSES) || e.test(passes_start >= silf_end, E_BADPASSESSTART)
|
||||
|| e.test(m_pPass < m_sPass, E_BADPASSBOUND) || e.test(m_pPass > m_numPasses, E_BADPPASS) || e.test(m_sPass > m_numPasses, E_BADSPASS)
|
||||
|| e.test(m_jPass < m_pPass, E_BADJPASSBOUND) || e.test(m_jPass > m_numPasses, E_BADJPASS)
|
||||
|| e.test((m_bPass != 0xFF && (m_bPass < m_jPass || m_bPass > m_numPasses)), E_BADBPASS)
|
||||
|| e.test(m_aLig > 127, E_BADALIG))
|
||||
{
|
||||
releaseBuffers();
|
||||
return face.error(e);
|
||||
}
|
||||
be::skip<uint32>(p, m_numPasses);
|
||||
if (p + sizeof(uint16) >= passes_start) { releaseBuffers(); return false; }
|
||||
if (e.test(p + sizeof(uint16) >= passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
|
||||
m_numPseudo = be::read<uint16>(p);
|
||||
be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
|
||||
if (p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start) {
|
||||
releaseBuffers(); return false;
|
||||
be::skip<uint16>(p, 3); // searchPseudo, pseudoSelector, pseudoShift
|
||||
if (e.test(p + m_numPseudo*(sizeof(uint32) + sizeof(uint16)) >= passes_start, E_BADNUMPSEUDO))
|
||||
{
|
||||
releaseBuffers(); return face.error(e);
|
||||
}
|
||||
m_pseudos = new Pseudo[m_numPseudo];
|
||||
for (int i = 0; i < m_numPseudo; i++)
|
||||
@ -163,23 +179,24 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, const Face&
|
||||
m_pseudos[i].gid = be::read<uint16>(p);
|
||||
}
|
||||
|
||||
const size_t clen = readClassMap(p, passes_start - p, version);
|
||||
if (clen == ERROROFFSET || p + clen > passes_start) { releaseBuffers(); return false; }
|
||||
const size_t clen = readClassMap(p, passes_start - p, version, e);
|
||||
if (e || e.test(p + clen > passes_start, E_BADPASSESSTART)) { releaseBuffers(); return face.error(e); }
|
||||
|
||||
m_passes = new Pass[m_numPasses];
|
||||
for (size_t i = 0; i < m_numPasses; ++i)
|
||||
{
|
||||
const byte * const pass_start = silf_start + be::read<uint32>(o_passes),
|
||||
* const pass_end = silf_start + be::peek<uint32>(o_passes);
|
||||
if (pass_start > pass_end || pass_end > silf_end) {
|
||||
releaseBuffers(); return false;
|
||||
* 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)) {
|
||||
releaseBuffers(); return face.error(e);
|
||||
}
|
||||
|
||||
m_passes[i].init(this);
|
||||
if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face))
|
||||
if (!m_passes[i].readPass(pass_start, pass_end - pass_start, pass_start - silf_start, face, e))
|
||||
{
|
||||
releaseBuffers();
|
||||
return false;
|
||||
releaseBuffers();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,69 +209,71 @@ bool Silf::readGraphite(const byte * const silf_start, size_t lSilf, const Face&
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len)
|
||||
template<typename T> inline uint32 Silf::readClassOffsets(const byte *&p, size_t data_len, Error &e)
|
||||
{
|
||||
const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
|
||||
const size_t max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
|
||||
// Check that the last+1 offset is less than or equal to the class map length.
|
||||
if (be::peek<T>(p) != cls_off || max_off > (data_len - cls_off)/sizeof(uint16))
|
||||
return ERROROFFSET;
|
||||
const T cls_off = 2*sizeof(uint16) + sizeof(T)*(m_nClass+1);
|
||||
const size_t max_off = (be::peek<T>(p + sizeof(T)*m_nClass) - cls_off)/sizeof(uint16);
|
||||
// Check that the last+1 offset is less than or equal to the class map length.
|
||||
if (e.test(be::peek<T>(p) != cls_off, E_MISALIGNEDCLASSES)
|
||||
|| e.test(max_off > (data_len - cls_off)/sizeof(uint16), E_HIGHCLASSOFFSET))
|
||||
return ERROROFFSET;
|
||||
|
||||
// Read in all the offsets.
|
||||
m_classOffsets = gralloc<uint32>(m_nClass+1);
|
||||
for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
|
||||
{
|
||||
*o = (be::read<T>(p) - cls_off)/sizeof(uint16);
|
||||
if (*o > max_off)
|
||||
return ERROROFFSET;
|
||||
}
|
||||
// Read in all the offsets.
|
||||
m_classOffsets = gralloc<uint32>(m_nClass+1);
|
||||
if (e.test(!m_classOffsets, E_OUTOFMEM)) return ERROROFFSET;
|
||||
for (uint32 * o = m_classOffsets, * const o_end = o + m_nClass + 1; o != o_end; ++o)
|
||||
{
|
||||
*o = (be::read<T>(p) - cls_off)/sizeof(uint16);
|
||||
if (e.test(*o > max_off, E_HIGHCLASSOFFSET))
|
||||
return ERROROFFSET;
|
||||
}
|
||||
return max_off;
|
||||
}
|
||||
|
||||
size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version)
|
||||
size_t Silf::readClassMap(const byte *p, size_t data_len, uint32 version, Error &e)
|
||||
{
|
||||
if (data_len < sizeof(uint16)*2) return ERROROFFSET;
|
||||
if (e.test(data_len < sizeof(uint16)*2, E_BADCLASSSIZE)) return ERROROFFSET;
|
||||
|
||||
m_nClass = be::read<uint16>(p);
|
||||
m_nLinear = be::read<uint16>(p);
|
||||
m_nClass = be::read<uint16>(p);
|
||||
m_nLinear = be::read<uint16>(p);
|
||||
|
||||
// Check that numLinear < numClass,
|
||||
// that there is at least enough data for numClasses offsets.
|
||||
if (m_nLinear > m_nClass
|
||||
|| (m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16))> (data_len - 4))
|
||||
return ERROROFFSET;
|
||||
// Check that numLinear < numClass,
|
||||
// that there is at least enough data for numClasses offsets.
|
||||
if (e.test(m_nLinear > m_nClass, E_TOOMANYLINEAR)
|
||||
|| e.test((m_nClass + 1) * (version >= 0x00040000 ? sizeof(uint32) : sizeof(uint16)) > (data_len - 4), E_CLASSESTOOBIG))
|
||||
return ERROROFFSET;
|
||||
|
||||
|
||||
uint32 max_off;
|
||||
if (version >= 0x00040000)
|
||||
max_off = readClassOffsets<uint32>(p, data_len);
|
||||
max_off = readClassOffsets<uint32>(p, data_len, e);
|
||||
else
|
||||
max_off = readClassOffsets<uint16>(p, data_len);
|
||||
max_off = readClassOffsets<uint16>(p, data_len, e);
|
||||
|
||||
if (max_off == ERROROFFSET) 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 (o[0] > o[1])
|
||||
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))
|
||||
return ERROROFFSET;
|
||||
|
||||
// Fortunately the class data is all uint16s so we can decode these now
|
||||
// Fortunately the class data is all uint16s so we can decode these now
|
||||
m_classData = gralloc<uint16>(max_off);
|
||||
if (e.test(!m_classData, E_OUTOFMEM)) return ERROROFFSET;
|
||||
for (uint16 *d = m_classData, * const d_end = d + max_off; d != d_end; ++d)
|
||||
*d = be::read<uint16>(p);
|
||||
|
||||
// Check the lookup class invariants for each non-linear class
|
||||
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 (*o > max_off - 4 // LookupClass doesn't stretch over max_off
|
||||
|| 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]) // rangeShift: numIDs - searchRange
|
||||
return ERROROFFSET;
|
||||
}
|
||||
// Check the lookup class invariants for each non-linear class
|
||||
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
|
||||
|| 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
|
||||
return ERROROFFSET;
|
||||
}
|
||||
|
||||
return max_off;
|
||||
return max_off;
|
||||
}
|
||||
|
||||
uint16 Silf::findPseudo(uint32 uid) const
|
||||
@ -277,13 +296,13 @@ uint16 Silf::findClassIndex(uint16 cid, uint16 gid) const
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint16 * min = cls + 4, // lookups array
|
||||
* max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
|
||||
do
|
||||
const uint16 * min = cls + 4, // lookups array
|
||||
* max = min + cls[0]*2; // lookups aray is numIDs (cls[0]) uint16 pairs long
|
||||
do
|
||||
{
|
||||
const uint16 * p = min + (-2 & ((max-min)/2));
|
||||
if (p[0] > gid) max = p;
|
||||
else min = p;
|
||||
const uint16 * p = min + (-2 & ((max-min)/2));
|
||||
if (p[0] > gid) max = p;
|
||||
else min = p;
|
||||
}
|
||||
while (max - min > 2);
|
||||
return min[0] == gid ? min[1] : -1;
|
||||
@ -309,47 +328,52 @@ uint16 Silf::getClassGlyph(uint16 cid, unsigned int index) const
|
||||
}
|
||||
|
||||
|
||||
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const
|
||||
bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass, int dobidi) const
|
||||
{
|
||||
assert(seg != 0);
|
||||
SlotMap map(*seg);
|
||||
FiniteStateMachine fsm(map, seg->getFace()->logger());
|
||||
vm::Machine m(map);
|
||||
unsigned int initSize = seg->slotCount();
|
||||
uint8 lbidi = m_bPass;
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
json * const dbgout = seg->getFace()->logger();
|
||||
#endif
|
||||
|
||||
if (lastPass == 0)
|
||||
{
|
||||
if (firstPass == lastPass)
|
||||
if (firstPass == lastPass && lbidi == 0xFF)
|
||||
return true;
|
||||
lastPass = m_numPasses;
|
||||
}
|
||||
if (firstPass <= lbidi && lastPass >= lbidi && dobidi)
|
||||
lastPass++;
|
||||
else
|
||||
lbidi = 0xFF;
|
||||
|
||||
for (size_t i = firstPass; i < lastPass; ++i)
|
||||
{
|
||||
// bidi and mirroring
|
||||
if (i == m_bPass)
|
||||
// bidi and mirroring
|
||||
if (i == lbidi)
|
||||
{
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::item << json::object
|
||||
<< "id" << -1
|
||||
<< "slots" << json::array;
|
||||
seg->positionSlots(0);
|
||||
for(Slot * s = seg->first(); s; s = s->next())
|
||||
*dbgout << dslot(seg, s);
|
||||
*dbgout << json::close
|
||||
<< "rules" << json::array << json::close
|
||||
<< json::close;
|
||||
}
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::item << json::object
|
||||
<< "id" << -1
|
||||
<< "slots" << json::array;
|
||||
seg->positionSlots(0);
|
||||
for(Slot * s = seg->first(); s; s = s->next())
|
||||
*dbgout << dslot(seg, s);
|
||||
*dbgout << json::close
|
||||
<< "rules" << json::array << json::close
|
||||
<< json::close;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(seg->dir() & 2))
|
||||
seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
|
||||
else if (m_aMirror)
|
||||
if (!(seg->dir() & 2))
|
||||
seg->bidiPass(m_aBidi, seg->dir() & 1, m_aMirror);
|
||||
else if (m_aMirror)
|
||||
{
|
||||
Slot * s;
|
||||
for (s = seg->first(); s; s = s->next())
|
||||
@ -359,19 +383,23 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const
|
||||
s->setGlyph(seg, g);
|
||||
}
|
||||
}
|
||||
--i;
|
||||
--lastPass;
|
||||
lbidi = 0xFF;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::item << json::object
|
||||
<< "id" << i+1
|
||||
<< "slots" << json::array;
|
||||
seg->positionSlots(0);
|
||||
for(Slot * s = seg->first(); s; s = s->next())
|
||||
*dbgout << dslot(seg, s);
|
||||
*dbgout << json::close;
|
||||
}
|
||||
if (dbgout)
|
||||
{
|
||||
*dbgout << json::item << json::object
|
||||
<< "id" << i+1
|
||||
<< "slots" << json::array;
|
||||
seg->positionSlots(0);
|
||||
for(Slot * s = seg->first(); s; s = s->next())
|
||||
*dbgout << dslot(seg, s);
|
||||
*dbgout << json::close;
|
||||
}
|
||||
#endif
|
||||
|
||||
// test whether to reorder, prepare for positioning
|
||||
@ -379,7 +407,7 @@ bool Silf::runGraphite(Segment *seg, uint8 firstPass, uint8 lastPass) const
|
||||
m_passes[i].runGraphite(m, fsm);
|
||||
// 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
|
||||
|| (i < m_pPass && (seg->slotCount() > initSize * MAX_SEG_GROWTH_FACTOR
|
||||
|| (seg->slotCount() && seg->slotCount() * MAX_SEG_GROWTH_FACTOR < initSize))))
|
||||
return false;
|
||||
}
|
||||
|
@ -37,23 +37,29 @@ Slot::Slot() :
|
||||
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(-1, -1),
|
||||
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(0), m_bidiLevel(0), m_justs(NULL)
|
||||
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
|
||||
{
|
||||
}
|
||||
|
||||
// take care, this does not copy any of the GrSlot pointer fields
|
||||
void Slot::set(const Slot & orig, int charOffset, size_t numUserAttr, size_t justLevels)
|
||||
void Slot::set(const Slot & orig, int charOffset, size_t numUserAttr, size_t justLevels, size_t numChars)
|
||||
{
|
||||
// leave m_next and m_prev unchanged
|
||||
m_glyphid = orig.m_glyphid;
|
||||
m_realglyphid = orig.m_realglyphid;
|
||||
m_original = orig.m_original + charOffset;
|
||||
m_before = orig.m_before + charOffset;
|
||||
m_after = orig.m_after + charOffset;
|
||||
if (charOffset + int(orig.m_before) < 0)
|
||||
m_before = 0;
|
||||
else
|
||||
m_before = orig.m_before + charOffset;
|
||||
if (charOffset <= 0 && orig.m_after + charOffset >= numChars)
|
||||
m_after = numChars - 1;
|
||||
else
|
||||
m_after = orig.m_after + charOffset;
|
||||
m_parent = NULL;
|
||||
m_child = NULL;
|
||||
m_sibling = NULL;
|
||||
@ -67,13 +73,9 @@ void Slot::set(const Slot & orig, int charOffset, size_t numUserAttr, size_t jus
|
||||
m_bidiCls = orig.m_bidiCls;
|
||||
m_bidiLevel = orig.m_bidiLevel;
|
||||
if (m_userAttr && orig.m_userAttr)
|
||||
{
|
||||
memcpy(m_userAttr, orig.m_userAttr, numUserAttr * sizeof(*m_userAttr));
|
||||
}
|
||||
if (m_justs && orig.m_justs)
|
||||
{
|
||||
memcpy(m_justs, orig.m_justs, SlotJustify::size_of(justLevels));
|
||||
}
|
||||
}
|
||||
|
||||
void Slot::update(int /*numGrSlots*/, int numCharInfo, Position &relpos)
|
||||
@ -194,32 +196,35 @@ int Slot::getAttr(const Segment *seg, attrCode ind, uint8 subindex) const
|
||||
|
||||
switch (ind)
|
||||
{
|
||||
case gr_slatAdvX : return int(m_advance.x);
|
||||
case gr_slatAdvY : return int(m_advance.y);
|
||||
case gr_slatAttTo : return m_parent ? 1 : 0;
|
||||
case gr_slatAttX : return int(m_attach.x);
|
||||
case gr_slatAttY : return int(m_attach.y);
|
||||
case gr_slatAdvX : return int(m_advance.x);
|
||||
case gr_slatAdvY : return int(m_advance.y);
|
||||
case gr_slatAttTo : return m_parent ? 1 : 0;
|
||||
case gr_slatAttX : return int(m_attach.x);
|
||||
case gr_slatAttY : return int(m_attach.y);
|
||||
case gr_slatAttXOff :
|
||||
case gr_slatAttYOff : return 0;
|
||||
case gr_slatAttYOff : return 0;
|
||||
case gr_slatAttWithX : return int(m_with.x);
|
||||
case gr_slatAttWithY : return int(m_with.y);
|
||||
case gr_slatAttWithXOff:
|
||||
case gr_slatAttWithYOff:return 0;
|
||||
case gr_slatAttLevel : return m_attLevel;
|
||||
case gr_slatBreak : return seg->charinfo(m_original)->breakWeight();
|
||||
case gr_slatCompRef : return 0;
|
||||
case gr_slatDir : return seg->dir();
|
||||
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);
|
||||
case gr_slatShiftX : return int(m_shift.x);
|
||||
case gr_slatShiftY : return int(m_shift.y);
|
||||
case gr_slatMeasureSol: return -1; // err what's this?
|
||||
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(seg->glyphAttr(gid(), seg->silf()->aBidi()));
|
||||
return m_bidiCls;
|
||||
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);
|
||||
case gr_slatShiftX : return int(m_shift.x);
|
||||
case gr_slatShiftY : return int(m_shift.y);
|
||||
case gr_slatMeasureSol: return -1; // err what's this?
|
||||
case gr_slatMeasureEol: return -1;
|
||||
case gr_slatJWidth: return m_just;
|
||||
case gr_slatUserDefn : return m_userAttr[subindex];
|
||||
case gr_slatJWidth: return int(m_just);
|
||||
case gr_slatUserDefn : return m_userAttr[subindex];
|
||||
case gr_slatSegSplit : return seg->charinfo(m_original)->flags() & 3;
|
||||
default : return 0;
|
||||
case gr_slatBidiLevel: return m_bidiLevel;
|
||||
default : return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,8 +244,8 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
|
||||
|
||||
switch (ind)
|
||||
{
|
||||
case gr_slatAdvX : m_advance.x = value; break;
|
||||
case gr_slatAdvY : m_advance.y = value; break;
|
||||
case gr_slatAdvX : m_advance.x = value; break;
|
||||
case gr_slatAdvY : m_advance.y = value; break;
|
||||
case gr_slatAttTo :
|
||||
{
|
||||
const uint16 idx = uint16(value);
|
||||
@ -260,36 +265,36 @@ void Slot::setAttr(Segment *seg, attrCode ind, uint8 subindex, int16 value, cons
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gr_slatAttX : m_attach.x = value; break;
|
||||
case gr_slatAttY : m_attach.y = value; break;
|
||||
case gr_slatAttX : m_attach.x = value; break;
|
||||
case gr_slatAttY : m_attach.y = value; break;
|
||||
case gr_slatAttXOff :
|
||||
case gr_slatAttYOff : break;
|
||||
case gr_slatAttWithX : m_with.x = value; break;
|
||||
case gr_slatAttWithY : m_with.y = value; break;
|
||||
case gr_slatAttYOff : break;
|
||||
case gr_slatAttWithX : m_with.x = value; break;
|
||||
case gr_slatAttWithY : m_with.y = value; break;
|
||||
case gr_slatAttWithXOff :
|
||||
case gr_slatAttWithYOff : break;
|
||||
case gr_slatAttWithYOff : break;
|
||||
case gr_slatAttLevel :
|
||||
m_attLevel = byte(value);
|
||||
break;
|
||||
case gr_slatBreak :
|
||||
seg->charinfo(m_original)->breakWeight(value);
|
||||
break;
|
||||
case gr_slatCompRef : break; // not sure what to do here
|
||||
case gr_slatDir : break; // read only
|
||||
case gr_slatCompRef : break; // not sure what to do here
|
||||
case gr_slatDir : m_bidiCls = value; break;
|
||||
case gr_slatInsert :
|
||||
markInsertBefore(value? true : false);
|
||||
break;
|
||||
case gr_slatPosX : break; // can't set these here
|
||||
case gr_slatPosY : break;
|
||||
case gr_slatShiftX : m_shift.x = value; break;
|
||||
case gr_slatPosX : break; // can't set these here
|
||||
case gr_slatPosY : break;
|
||||
case gr_slatShiftX : m_shift.x = value; break;
|
||||
case gr_slatShiftY : m_shift.y = value; break;
|
||||
case gr_slatMeasureSol : break;
|
||||
case gr_slatMeasureEol : break;
|
||||
case gr_slatJWidth : just(value); break;
|
||||
case gr_slatMeasureSol : break;
|
||||
case gr_slatMeasureEol : break;
|
||||
case gr_slatJWidth : just(value); break;
|
||||
case gr_slatSegSplit : seg->charinfo(m_original)->addflags(value & 3); break;
|
||||
case gr_slatUserDefn : m_userAttr[subindex] = value; break;
|
||||
default :
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,6 +324,7 @@ void Slot::setJustify(Segment *seg, uint8 level, uint8 subindex, int16 value)
|
||||
if (!m_justs)
|
||||
{
|
||||
SlotJustify *j = seg->newJustify();
|
||||
if (!j) return;
|
||||
j->LoadSlot(this, seg);
|
||||
m_justs = j;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -30,31 +30,33 @@ of the License or (at your option) any later version.
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
sparse::chunk sparse::empty_chunk = {0,0};
|
||||
|
||||
sparse::~sparse() throw()
|
||||
{
|
||||
free(m_array.values);
|
||||
if (m_array.map == &empty_chunk) return;
|
||||
free(m_array.values);
|
||||
}
|
||||
|
||||
|
||||
sparse::mapped_type sparse::operator [] (const key_type k) const throw()
|
||||
{
|
||||
mapped_type g = key_type(k/SIZEOF_CHUNK - m_nchunks) >> (sizeof k*8 - 1);
|
||||
const chunk & c = m_array.map[g*k/SIZEOF_CHUNK];
|
||||
const mask_t m = c.mask >> (SIZEOF_CHUNK - 1 - (k%SIZEOF_CHUNK));
|
||||
g *= m & 1;
|
||||
const chunk & c = m_array.map[g*k/SIZEOF_CHUNK];
|
||||
const mask_t m = c.mask >> (SIZEOF_CHUNK - 1 - (k%SIZEOF_CHUNK));
|
||||
g *= m & 1;
|
||||
|
||||
return g*m_array.values[g*(c.offset + bit_set_count(m >> 1))];
|
||||
return g*m_array.values[g*(c.offset + bit_set_count(m >> 1))];
|
||||
}
|
||||
|
||||
|
||||
size_t sparse::capacity() const throw()
|
||||
{
|
||||
size_t n = m_nchunks,
|
||||
s = 0;
|
||||
size_t n = m_nchunks,
|
||||
s = 0;
|
||||
|
||||
for (const chunk *ci=m_array.map; n; --n, ++ci)
|
||||
s += bit_set_count(ci->mask);
|
||||
for (const chunk *ci=m_array.map; n; --n, ++ci)
|
||||
s += bit_set_count(ci->mask);
|
||||
|
||||
return s;
|
||||
return s;
|
||||
}
|
||||
|
@ -35,11 +35,11 @@ using namespace graphite2;
|
||||
|
||||
const int8 _utf_codec<8>::sz_lut[16] =
|
||||
{
|
||||
1,1,1,1,1,1,1,1, // 1 byte
|
||||
0,0,0,0, // trailing byte
|
||||
2,2, // 2 bytes
|
||||
3, // 3 bytes
|
||||
4 // 4 bytes
|
||||
1,1,1,1,1,1,1,1, // 1 byte
|
||||
0,0,0,0, // trailing byte
|
||||
2,2, // 2 bytes
|
||||
3, // 3 bytes
|
||||
4 // 4 bytes
|
||||
};
|
||||
|
||||
const byte _utf_codec<8>::mask_lut[5] = {0x7f, 0xff, 0x3f, 0x1f, 0x0f};
|
||||
|
@ -50,7 +50,7 @@ of the License or (at your option) any later version.
|
||||
vm::Machine::stack_t * const sb, regbank & reg
|
||||
|
||||
// These are required by opcodes.h and should not be changed
|
||||
#define STARTOP(name) bool name(registers) REGPARM(4);\
|
||||
#define STARTOP(name) bool name(registers) REGPARM(4);\
|
||||
bool name(registers) {
|
||||
#define ENDOP return (sp - sb)/Machine::STACK_MAX==0; \
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
# GRAPHITE2 LICENSING
|
||||
#
|
||||
# Copyright 2010, SIL International
|
||||
# Copyright 2011, SIL International
|
||||
# All rights reserved.
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or modify
|
||||
@ -43,7 +43,7 @@ $(_NS)_SOURCES = \
|
||||
$($(_NS)_BASE)/src/gr_face.cpp \
|
||||
$($(_NS)_BASE)/src/gr_features.cpp \
|
||||
$($(_NS)_BASE)/src/gr_font.cpp \
|
||||
$($(_NS)_BASE)/src/gr_logging.cpp \
|
||||
$($(_NS)_BASE)/src/gr_logging.cpp \
|
||||
$($(_NS)_BASE)/src/gr_segment.cpp \
|
||||
$($(_NS)_BASE)/src/gr_slot.cpp \
|
||||
$($(_NS)_BASE)/src/json.cpp \
|
||||
@ -79,6 +79,7 @@ $(_NS)_PRIVATE_HEADERS = \
|
||||
$($(_NS)_BASE)/src/inc/CmapCache.h \
|
||||
$($(_NS)_BASE)/src/inc/Code.h \
|
||||
$($(_NS)_BASE)/src/inc/Endian.h \
|
||||
$($(_NS)_BASE)/src/inc/Error.h \
|
||||
$($(_NS)_BASE)/src/inc/Face.h \
|
||||
$($(_NS)_BASE)/src/inc/FeatureMap.h \
|
||||
$($(_NS)_BASE)/src/inc/FeatureVal.h \
|
||||
|
@ -31,9 +31,14 @@ of the License or (at your option) any later version.
|
||||
#include "inc/CachedFace.h"
|
||||
#include "inc/CmapCache.h"
|
||||
#include "inc/Silf.h"
|
||||
#include "inc/json.h"
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
extern json *global_log;
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
bool load_face(Face & face, unsigned int options)
|
||||
@ -49,8 +54,27 @@ namespace
|
||||
if (!face.readGlyphs(options))
|
||||
return false;
|
||||
|
||||
return silf ? face.readFeatures() && face.readGraphite(silf)
|
||||
: options & gr_face_dumbRendering;
|
||||
if (silf)
|
||||
{
|
||||
if (!face.readFeatures() || !face.readGraphite(silf))
|
||||
{
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (global_log)
|
||||
{
|
||||
*global_log << json::object
|
||||
<< "type" << "fontload"
|
||||
<< "failure" << face.error()
|
||||
<< "context" << face.error_context()
|
||||
<< json::close;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return options & gr_face_dumbRendering;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +83,7 @@ extern "C" {
|
||||
gr_face* gr_make_face_with_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int faceOptions)
|
||||
//the appFaceHandle must stay alive all the time when the gr_face is alive. When finished with the gr_face, call destroy_face
|
||||
{
|
||||
if (ops == 0) return 0;
|
||||
if (ops == 0) return 0;
|
||||
|
||||
Face *res = new Face(appFaceHandle, *ops);
|
||||
if (res && load_face(*res, faceOptions))
|
||||
@ -79,7 +103,7 @@ gr_face* gr_make_face(const void* appFaceHandle/*non-NULL*/, gr_get_table_fn tab
|
||||
gr_face* gr_make_face_with_seg_cache_and_ops(const void* appFaceHandle/*non-NULL*/, const gr_face_ops *ops, unsigned int cacheSize, unsigned int faceOptions)
|
||||
//the appFaceHandle must stay alive all the time when the GrFace is alive. When finished with the GrFace, call destroy_face
|
||||
{
|
||||
if (ops == 0) return 0;
|
||||
if (ops == 0) return 0;
|
||||
|
||||
CachedFace *res = new CachedFace(appFaceHandle, *ops);
|
||||
if (res && load_face(*res, faceOptions)
|
||||
@ -120,17 +144,17 @@ void gr_tag_to_str(gr_uint32 tag, char *str)
|
||||
inline
|
||||
uint32 zeropad(const uint32 x)
|
||||
{
|
||||
if (x == 0x20202020) return 0;
|
||||
if ((x & 0x00FFFFFF) == 0x00202020) return x & 0xFF000000;
|
||||
if ((x & 0x0000FFFF) == 0x00002020) return x & 0xFFFF0000;
|
||||
if ((x & 0x000000FF) == 0x00000020) return x & 0xFFFFFF00;
|
||||
return x;
|
||||
if (x == 0x20202020) return 0;
|
||||
if ((x & 0x00FFFFFF) == 0x00202020) return x & 0xFF000000;
|
||||
if ((x & 0x0000FFFF) == 0x00002020) return x & 0xFFFF0000;
|
||||
if ((x & 0x000000FF) == 0x00000020) return x & 0xFFFFFF00;
|
||||
return x;
|
||||
}
|
||||
|
||||
gr_feature_val* gr_face_featureval_for_lang(const gr_face* pFace, gr_uint32 langname/*0 means clone default*/) //clones the features. if none for language, clones the default
|
||||
{
|
||||
assert(pFace);
|
||||
zeropad(langname);
|
||||
langname = zeropad(langname);
|
||||
return static_cast<gr_feature_val *>(pFace->theSill().cloneFeatures(langname));
|
||||
}
|
||||
|
||||
@ -138,7 +162,7 @@ gr_feature_val* gr_face_featureval_for_lang(const gr_face* pFace, gr_uint32 lang
|
||||
const gr_feature_ref* gr_face_find_fref(const gr_face* pFace, gr_uint32 featId) //When finished with the FeatureRef, call destroy_FeatureRef
|
||||
{
|
||||
assert(pFace);
|
||||
zeropad(featId);
|
||||
featId = zeropad(featId);
|
||||
const FeatureRef* pRef = pFace->featureById(featId);
|
||||
return static_cast<const gr_feature_ref*>(pRef);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ extern "C" {
|
||||
|
||||
gr_uint16 gr_fref_feature_value(const gr_feature_ref* pfeatureref, const gr_feature_val* feats) //returns 0 if either pointer is NULL
|
||||
{
|
||||
if (!pfeatureref || !feats) return 0;
|
||||
if (!pfeatureref || !feats) return 0;
|
||||
|
||||
return pfeatureref->getFeatureVal(*feats);
|
||||
}
|
||||
@ -45,7 +45,7 @@ gr_uint16 gr_fref_feature_value(const gr_feature_ref* pfeatureref, const gr_feat
|
||||
|
||||
int gr_fref_set_feature_value(const gr_feature_ref* pfeatureref, gr_uint16 val, gr_feature_val* pDest)
|
||||
{
|
||||
if (!pfeatureref || !pDest) return 0;
|
||||
if (!pfeatureref || !pDest) return 0;
|
||||
|
||||
return pfeatureref->applyValToFeature(val, *pDest);
|
||||
}
|
||||
@ -121,7 +121,7 @@ void* gr_fref_value_label(const gr_feature_ref*pfeatureref, gr_uint16 setting,
|
||||
|
||||
void gr_label_destroy(void * label)
|
||||
{
|
||||
free(label);
|
||||
free(label);
|
||||
}
|
||||
|
||||
gr_feature_val* gr_featureval_clone(const gr_feature_val* pfeatures/*may be NULL*/)
|
||||
|
@ -47,9 +47,9 @@ gr_font* gr_make_font(float ppm/*pixels per em*/, const gr_face *face)
|
||||
|
||||
gr_font* gr_make_font_with_ops(float ppm/*pixels per em*/, const void* appFontHandle/*non-NULL*/, const gr_font_ops * font_ops, const gr_face * face/*needed for scaling*/)
|
||||
{ //the appFontHandle must stay alive all the time when the gr_font is alive. When finished with the gr_font, call destroy_gr_font
|
||||
if (face == 0) return 0;
|
||||
if (face == 0) return 0;
|
||||
|
||||
Font * const res = new Font(ppm, *face, appFontHandle, font_ops);
|
||||
Font * const res = new Font(ppm, *face, appFontHandle, font_ops);
|
||||
return static_cast<gr_font*>(res);
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/CharInfo.h"
|
||||
#include "inc/Slot.h"
|
||||
#include "inc/Segment.h"
|
||||
#include "inc/json.h"
|
||||
|
||||
#if defined _WIN32
|
||||
#include "windows.h"
|
||||
@ -38,48 +39,60 @@ of the License or (at your option) any later version.
|
||||
|
||||
using namespace graphite2;
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
bool gr_start_logging(gr_face * face, const char *log_path)
|
||||
{
|
||||
if (!face || !log_path) return false;
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
gr_stop_logging(face);
|
||||
#if defined _WIN32
|
||||
int n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, 0, 0);
|
||||
if (n == 0 || n > MAX_PATH - 12) return false;
|
||||
|
||||
LPWSTR wlog_path = gralloc<WCHAR>(n);
|
||||
FILE *log = 0;
|
||||
if (wlog_path && MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, wlog_path, n))
|
||||
log = _wfopen(wlog_path, L"wt");
|
||||
|
||||
free(wlog_path);
|
||||
#else // _WIN32
|
||||
FILE *log = fopen(log_path, "wt");
|
||||
#endif // _WIN32
|
||||
if (!log) return false;
|
||||
|
||||
face->setLogger(log);
|
||||
if (!face->logger()) return false;
|
||||
|
||||
*face->logger() << json::array;
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
*face->logger() << face->tele;
|
||||
json *global_log = NULL;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
extern "C" {
|
||||
|
||||
bool gr_start_logging(GR_MAYBE_UNUSED gr_face * face, const char *log_path)
|
||||
{
|
||||
if (!log_path) return false;
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
gr_stop_logging(face);
|
||||
#if defined _WIN32
|
||||
int n = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, 0, 0);
|
||||
if (n == 0 || n > MAX_PATH - 12) return false;
|
||||
|
||||
LPWSTR wlog_path = gralloc<WCHAR>(n);
|
||||
if (!wlog_path) return false;
|
||||
FILE *log = 0;
|
||||
if (wlog_path && MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, log_path, -1, wlog_path, n))
|
||||
log = _wfopen(wlog_path, L"wt");
|
||||
|
||||
free(wlog_path);
|
||||
#else // _WIN32
|
||||
FILE *log = fopen(log_path, "wt");
|
||||
#endif // _WIN32
|
||||
if (!log) return false;
|
||||
|
||||
if (face)
|
||||
{
|
||||
face->setLogger(log);
|
||||
if (!face->logger()) return false;
|
||||
|
||||
*face->logger() << json::array;
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
*face->logger() << face->tele;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
global_log = new json(log);
|
||||
*global_log << json::array;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else // GRAPHITE2_NTRACING
|
||||
return false;
|
||||
return false;
|
||||
#endif // GRAPHITE2_NTRACING
|
||||
}
|
||||
|
||||
bool graphite_start_logging(FILE * /* log */, GrLogMask /* mask */)
|
||||
{
|
||||
//#if !defined GRAPHITE2_NTRACING
|
||||
// graphite_stop_logging();
|
||||
// graphite_stop_logging();
|
||||
//
|
||||
// if (!log) return false;
|
||||
//
|
||||
@ -93,17 +106,21 @@ bool graphite_start_logging(FILE * /* log */, GrLogMask /* mask */)
|
||||
//#endif
|
||||
}
|
||||
|
||||
void gr_stop_logging(gr_face * face)
|
||||
void gr_stop_logging(GR_MAYBE_UNUSED gr_face * face)
|
||||
{
|
||||
if (!face) return;
|
||||
|
||||
#if !defined GRAPHITE2_NTRACING
|
||||
if (face->logger())
|
||||
{
|
||||
FILE * log = face->logger()->stream();
|
||||
face->setLogger(0);
|
||||
fclose(log);
|
||||
}
|
||||
if (face && face->logger())
|
||||
{
|
||||
FILE * log = face->logger()->stream();
|
||||
face->setLogger(0);
|
||||
fclose(log);
|
||||
}
|
||||
else if (!face && global_log)
|
||||
{
|
||||
FILE * log = global_log->stream();
|
||||
delete global_log;
|
||||
fclose(log);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -148,78 +165,78 @@ json & graphite2::operator << (json & j, const telemetry &) throw()
|
||||
|
||||
json & graphite2::operator << (json & j, const CharInfo & ci) throw()
|
||||
{
|
||||
return j << json::object
|
||||
<< "offset" << ci.base()
|
||||
<< "unicode" << ci.unicodeChar()
|
||||
<< "break" << ci.breakWeight()
|
||||
<< "flags" << ci.flags()
|
||||
<< "slot" << json::flat << json::object
|
||||
<< "before" << ci.before()
|
||||
<< "after" << ci.after()
|
||||
<< json::close
|
||||
<< json::close;
|
||||
return j << json::object
|
||||
<< "offset" << ci.base()
|
||||
<< "unicode" << ci.unicodeChar()
|
||||
<< "break" << ci.breakWeight()
|
||||
<< "flags" << ci.flags()
|
||||
<< "slot" << json::flat << json::object
|
||||
<< "before" << ci.before()
|
||||
<< "after" << ci.after()
|
||||
<< json::close
|
||||
<< json::close;
|
||||
}
|
||||
|
||||
|
||||
json & graphite2::operator << (json & j, const dslot & ds) throw()
|
||||
{
|
||||
assert(ds.first);
|
||||
assert(ds.second);
|
||||
const Segment & seg = *ds.first;
|
||||
const Slot & s = *ds.second;
|
||||
assert(ds.first);
|
||||
assert(ds.second);
|
||||
const Segment & seg = *ds.first;
|
||||
const Slot & s = *ds.second;
|
||||
|
||||
j << json::object
|
||||
<< "id" << objectid(ds)
|
||||
<< "gid" << s.gid()
|
||||
<< "charinfo" << json::flat << json::object
|
||||
<< "original" << s.original()
|
||||
<< "before" << s.before()
|
||||
<< "after" << s.after()
|
||||
<< json::close
|
||||
<< "origin" << s.origin()
|
||||
<< "shift" << Position(float(s.getAttr(0, gr_slatShiftX, 0)),
|
||||
float(s.getAttr(0, gr_slatShiftY, 0)))
|
||||
<< "advance" << s.advancePos()
|
||||
<< "insert" << s.isInsertBefore()
|
||||
<< "break" << s.getAttr(&seg, gr_slatBreak, 0);
|
||||
if (s.just() > 0)
|
||||
j << "justification" << s.just();
|
||||
if (s.getBidiLevel() > 0)
|
||||
j << "bidi" << s.getBidiLevel();
|
||||
if (!s.isBase())
|
||||
j << "parent" << json::flat << json::object
|
||||
<< "id" << objectid(dslot(&seg, s.attachedTo()))
|
||||
<< "level" << s.getAttr(0, gr_slatAttLevel, 0)
|
||||
<< "offset" << s.attachOffset()
|
||||
<< json::close;
|
||||
j << "user" << json::flat << json::array;
|
||||
for (int n = 0; n!= seg.numAttrs(); ++n)
|
||||
j << s.userAttrs()[n];
|
||||
j << json::close;
|
||||
if (s.firstChild())
|
||||
{
|
||||
j << "children" << json::flat << json::array;
|
||||
for (const Slot *c = s.firstChild(); c; c = c->nextSibling())
|
||||
j << objectid(dslot(&seg, c));
|
||||
j << json::close;
|
||||
}
|
||||
return j << json::close;
|
||||
j << json::object
|
||||
<< "id" << objectid(ds)
|
||||
<< "gid" << s.gid()
|
||||
<< "charinfo" << json::flat << json::object
|
||||
<< "original" << s.original()
|
||||
<< "before" << s.before()
|
||||
<< "after" << s.after()
|
||||
<< json::close
|
||||
<< "origin" << s.origin()
|
||||
<< "shift" << Position(float(s.getAttr(0, gr_slatShiftX, 0)),
|
||||
float(s.getAttr(0, gr_slatShiftY, 0)))
|
||||
<< "advance" << s.advancePos()
|
||||
<< "insert" << s.isInsertBefore()
|
||||
<< "break" << s.getAttr(&seg, gr_slatBreak, 0);
|
||||
if (s.just() > 0)
|
||||
j << "justification" << s.just();
|
||||
if (s.getBidiLevel() > 0)
|
||||
j << "bidi" << s.getBidiLevel();
|
||||
if (!s.isBase())
|
||||
j << "parent" << json::flat << json::object
|
||||
<< "id" << objectid(dslot(&seg, s.attachedTo()))
|
||||
<< "level" << s.getAttr(0, gr_slatAttLevel, 0)
|
||||
<< "offset" << s.attachOffset()
|
||||
<< json::close;
|
||||
j << "user" << json::flat << json::array;
|
||||
for (int n = 0; n!= seg.numAttrs(); ++n)
|
||||
j << s.userAttrs()[n];
|
||||
j << json::close;
|
||||
if (s.firstChild())
|
||||
{
|
||||
j << "children" << json::flat << json::array;
|
||||
for (const Slot *c = s.firstChild(); c; c = c->nextSibling())
|
||||
j << objectid(dslot(&seg, c));
|
||||
j << json::close;
|
||||
}
|
||||
return j << json::close;
|
||||
}
|
||||
|
||||
|
||||
graphite2::objectid::objectid(const dslot & ds) throw()
|
||||
{
|
||||
const Slot * const p = ds.second;
|
||||
uint32 s = reinterpret_cast<size_t>(p);
|
||||
sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), uint16(p ? p->userAttrs()[ds.first->silf()->numUser()] : 0), uint16(s));
|
||||
name[sizeof name-1] = 0;
|
||||
uint32 s = reinterpret_cast<size_t>(p);
|
||||
sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), uint16(p ? p->userAttrs()[ds.first->silf()->numUser()] : 0), uint16(s));
|
||||
name[sizeof name-1] = 0;
|
||||
}
|
||||
|
||||
graphite2::objectid::objectid(const Segment * const p) throw()
|
||||
{
|
||||
uint32 s = reinterpret_cast<size_t>(p);
|
||||
sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), 0, uint16(s));
|
||||
name[sizeof name-1] = 0;
|
||||
uint32 s = reinterpret_cast<size_t>(p);
|
||||
sprintf(name, "%.4x-%.2x-%.4hx", uint16(s >> 16), 0, uint16(s));
|
||||
name[sizeof name-1] = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -42,8 +42,8 @@ namespace
|
||||
// if (!font) return NULL;
|
||||
Segment* pRes=new Segment(nChars, face, script, dir);
|
||||
|
||||
pRes->read_text(face, pFeats, enc, pStart, nChars);
|
||||
if (!pRes->runGraphite())
|
||||
|
||||
if (!pRes->read_text(face, pFeats, enc, pStart, nChars) || !pRes->runGraphite())
|
||||
{
|
||||
delete pRes;
|
||||
return NULL;
|
||||
@ -64,46 +64,46 @@ namespace
|
||||
template <typename utf_iter>
|
||||
inline size_t count_unicode_chars(utf_iter first, const utf_iter last, const void **error)
|
||||
{
|
||||
size_t n_chars = 0;
|
||||
uint32 usv = 0;
|
||||
size_t n_chars = 0;
|
||||
uint32 usv = 0;
|
||||
|
||||
if (last)
|
||||
{
|
||||
for (;first != last; ++first, ++n_chars)
|
||||
if ((usv = *first) == 0 || first.error()) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((usv = *first) != 0 && !first.error())
|
||||
{
|
||||
++first;
|
||||
++n_chars;
|
||||
}
|
||||
}
|
||||
if (last)
|
||||
{
|
||||
for (;first != last; ++first, ++n_chars)
|
||||
if ((usv = *first) == 0 || first.error()) break;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((usv = *first) != 0 && !first.error())
|
||||
{
|
||||
++first;
|
||||
++n_chars;
|
||||
}
|
||||
}
|
||||
|
||||
if (error) *error = first.error() ? first : 0;
|
||||
return n_chars;
|
||||
if (error) *error = first.error() ? first : 0;
|
||||
return n_chars;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
size_t gr_count_unicode_characters(gr_encform enc, const void* buffer_begin, const void* buffer_end/*don't go on or past end, If NULL then ignored*/, const void** pError) //Also stops on nul. Any nul is not in the count
|
||||
{
|
||||
assert(buffer_begin);
|
||||
assert(buffer_begin);
|
||||
|
||||
switch (enc)
|
||||
{
|
||||
case gr_utf8: return count_unicode_chars<utf8::const_iterator>(buffer_begin, buffer_end, pError); break;
|
||||
case gr_utf16: return count_unicode_chars<utf16::const_iterator>(buffer_begin, buffer_end, pError); break;
|
||||
case gr_utf32: return count_unicode_chars<utf32::const_iterator>(buffer_begin, buffer_end, pError); break;
|
||||
default: return 0;
|
||||
}
|
||||
switch (enc)
|
||||
{
|
||||
case gr_utf8: return count_unicode_chars<utf8::const_iterator>(buffer_begin, buffer_end, pError); break;
|
||||
case gr_utf16: return count_unicode_chars<utf16::const_iterator>(buffer_begin, buffer_end, pError); break;
|
||||
case gr_utf32: return count_unicode_chars<utf32::const_iterator>(buffer_begin, buffer_end, pError); break;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gr_segment* gr_make_seg(const gr_font *font, const gr_face *face, gr_uint32 script, const gr_feature_val* pFeats, gr_encform enc, const void* pStart, size_t nChars, int dir)
|
||||
{
|
||||
const gr_feature_val * tmp_feats = 0;
|
||||
const gr_feature_val * tmp_feats = 0;
|
||||
if (pFeats == 0)
|
||||
pFeats = tmp_feats = static_cast<const gr_feature_val*>(face->theSill().cloneFeatures(0));
|
||||
gr_segment * seg = makeAndInitialize(font, face, script, pFeats, enc, pStart, nChars, dir);
|
||||
|
126
gfx/graphite2/src/inc/Bidi.h
Normal file
@ -0,0 +1,126 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2013, 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
|
||||
|
||||
namespace graphite2
|
||||
{
|
||||
|
||||
class BracketPair
|
||||
{
|
||||
public:
|
||||
BracketPair(uint16 g, Slot *s, uint8 b, BracketPair *p, BracketPair *l) : _open(s), _close(0), _parent(p), _next(0), _prev(l), _gid(g), _mask(0), _before(b) {};
|
||||
uint16 gid() const { return _gid; }
|
||||
Slot *open() const { return _open; }
|
||||
Slot *close() const { return _close; }
|
||||
uint8 mask() const { return _mask; }
|
||||
int8 before() const { return _before; }
|
||||
BracketPair *parent() const { return _parent; }
|
||||
void close(Slot *s) { _close = s; }
|
||||
BracketPair *next() const { return _next; }
|
||||
BracketPair *prev() const { return _prev; }
|
||||
void next(BracketPair *n) { _next = n; }
|
||||
void orin(uint8 m) { _mask |= m; }
|
||||
private:
|
||||
Slot * _open; // Slot of opening paren
|
||||
Slot * _close; // Slot of closing paren
|
||||
BracketPair * _parent; // pair this pair is in or NULL
|
||||
BracketPair * _next; // next pair along the string
|
||||
BracketPair * _prev; // pair that closed last before we opened
|
||||
uint16 _gid; // gid of closing paren
|
||||
uint8 _mask; // bitmap (2 bits) of directions within the pair
|
||||
int8 _before; // most recent strong type (L, R, OPP, CPP)
|
||||
};
|
||||
|
||||
class BracketPairStack
|
||||
{
|
||||
public:
|
||||
BracketPairStack(int s) : _stack(grzeroalloc<BracketPair>(s)), _ip(_stack - 1), _top(0), _last(0), _lastclose(0), _size(s) {}
|
||||
~BracketPairStack() { free(_stack); }
|
||||
|
||||
public:
|
||||
BracketPair *scan(uint16 gid);
|
||||
void close(BracketPair *tos, Slot *s);
|
||||
BracketPair *push(uint16 gid, Slot *pos, uint8 before, int prevopen);
|
||||
void orin(uint8 mask);
|
||||
void clear() { _ip = _stack - 1; _top = 0; _last = 0; _lastclose = 0; }
|
||||
int size() const { return _size; }
|
||||
BracketPair *start() const { return _stack; }
|
||||
|
||||
CLASS_NEW_DELETE
|
||||
|
||||
private:
|
||||
|
||||
BracketPair *_stack; // start of storage
|
||||
BracketPair *_ip; // where to add the next pair
|
||||
BracketPair *_top; // current parent
|
||||
BracketPair *_last; // end of next() chain
|
||||
BracketPair *_lastclose; // last pair to close
|
||||
int _size; // capacity
|
||||
};
|
||||
|
||||
inline BracketPair *BracketPairStack::scan(uint16 gid)
|
||||
{
|
||||
BracketPair *res = _top;
|
||||
while (res >= _stack)
|
||||
{
|
||||
if (res->gid() == gid)
|
||||
return res;
|
||||
res = res->parent();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void BracketPairStack::close(BracketPair *tos, Slot *s)
|
||||
{
|
||||
for ( ; _last && _last != tos && !_last->close(); _last = _last->parent())
|
||||
{ }
|
||||
tos->close(s);
|
||||
_last->next(NULL);
|
||||
_lastclose = tos;
|
||||
_top = tos->parent();
|
||||
}
|
||||
|
||||
inline BracketPair *BracketPairStack::push(uint16 gid, Slot *pos, uint8 before, int prevopen)
|
||||
{
|
||||
if (++_ip - _stack < _size && _stack)
|
||||
{
|
||||
::new (_ip) BracketPair(gid, pos, before, _top, prevopen ? _last : _lastclose);
|
||||
if (_last) _last->next(_ip);
|
||||
_last = _ip;
|
||||
}
|
||||
_top = _ip;
|
||||
return _ip;
|
||||
}
|
||||
|
||||
inline void BracketPairStack::orin(uint8 mask)
|
||||
{
|
||||
BracketPair *t = _top;
|
||||
for ( ; t; t = t->parent())
|
||||
t->orin(mask);
|
||||
}
|
||||
|
||||
}
|
@ -34,7 +34,7 @@ class CharInfo
|
||||
{
|
||||
|
||||
public:
|
||||
CharInfo() : m_char(0), m_before(-1), m_after(0), m_base(0), m_featureid(0), m_break(0), m_flags(0) {}
|
||||
CharInfo() : m_char(0), m_before(-1), m_after(-1), m_base(0), m_featureid(0), m_break(0), m_flags(0) {}
|
||||
void init(int cid) { m_char = cid; }
|
||||
unsigned int unicodeChar() const { return m_char; }
|
||||
void feats(int offset) { m_featureid = offset; }
|
||||
@ -56,8 +56,8 @@ private:
|
||||
int m_before; // slot index before us, comes before
|
||||
int m_after; // slot index after us, comes after
|
||||
size_t m_base; // offset into input string corresponding to this charinfo
|
||||
uint8 m_featureid; // index into features list in the segment
|
||||
int8 m_break; // breakweight coming from lb table
|
||||
uint8 m_featureid; // index into features list in the segment
|
||||
int8 m_break; // breakweight coming from lb table
|
||||
uint8 m_flags; // 0,1 segment split.
|
||||
};
|
||||
|
||||
|
@ -37,13 +37,13 @@ class Cmap
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Cmap() throw() {}
|
||||
virtual ~Cmap() throw() {}
|
||||
|
||||
virtual uint16 operator [] (const uint32) const throw() { return 0; }
|
||||
virtual uint16 operator [] (const uint32) const throw() { return 0; }
|
||||
|
||||
virtual operator bool () const throw() { return false; }
|
||||
virtual operator bool () const throw() { return false; }
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
CLASS_NEW_DELETE;
|
||||
};
|
||||
|
||||
class DirectCmap : public Cmap
|
||||
@ -52,9 +52,9 @@ class DirectCmap : public Cmap
|
||||
DirectCmap & operator = (const DirectCmap &);
|
||||
|
||||
public:
|
||||
DirectCmap(const Face &);
|
||||
virtual uint16 operator [] (const uint32 usv) const throw();
|
||||
virtual operator bool () const throw();
|
||||
DirectCmap(const Face &);
|
||||
virtual uint16 operator [] (const uint32 usv) const throw();
|
||||
virtual operator bool () const throw();
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
private:
|
||||
@ -69,10 +69,10 @@ class CachedCmap : public Cmap
|
||||
CachedCmap & operator = (const CachedCmap &);
|
||||
|
||||
public:
|
||||
CachedCmap(const Face &);
|
||||
virtual ~CachedCmap() throw();
|
||||
virtual uint16 operator [] (const uint32 usv) const throw();
|
||||
virtual operator bool () const throw();
|
||||
CachedCmap(const Face &);
|
||||
virtual ~CachedCmap() throw();
|
||||
virtual uint16 operator [] (const uint32 usv) const throw();
|
||||
virtual operator bool () const throw();
|
||||
CLASS_NEW_DELETE;
|
||||
private:
|
||||
bool m_isBmpOnly;
|
||||
|
@ -168,7 +168,7 @@ inline bool Machine::Code::deletes() const throw()
|
||||
|
||||
inline size_t Machine::Code::maxRef() const throw()
|
||||
{
|
||||
return _max_ref;
|
||||
return _max_ref;
|
||||
}
|
||||
|
||||
} // namespace vm
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
Copyright (C) 2011 SIL International
|
||||
Responsibility: Tim Eves
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2011, 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
|
||||
@ -22,17 +23,21 @@ 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
Description:
|
||||
A set of fast template based decoders for decoding values of any C integer
|
||||
type up to long int size laid out with most significant byte first or least
|
||||
significant byte first (aka big endian or little endian). These are CPU
|
||||
byte order agnostic and will function the same regardless of the CPUs native
|
||||
byte order.
|
||||
Being template based means if the either le or be class is not used then
|
||||
template code of unused functions will not be instantiated by the compiler
|
||||
and thus shouldn't cause any overhead.
|
||||
-----------------------------------------------------------------------------*/
|
||||
A set of fast template based decoders for decoding values of any C integer
|
||||
type up to long int size laid out with most significant byte first or least
|
||||
significant byte first (aka big endian or little endian). These are CPU
|
||||
byte order agnostic and will function the same regardless of the CPUs native
|
||||
byte order.
|
||||
|
||||
Being template based means if the either le or be class is not used then
|
||||
template code of unused functions will not be instantiated by the compiler
|
||||
and thus shouldn't cause any overhead.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#pragma once
|
||||
@ -40,32 +45,32 @@ and thus shouldn't cause any overhead.
|
||||
|
||||
class be
|
||||
{
|
||||
template<int S>
|
||||
inline static unsigned long int _peek(const unsigned char * p) {
|
||||
return _peek<S/2>(p) << (S/2)*8 | _peek<S/2>(p+S/2);
|
||||
}
|
||||
template<int S>
|
||||
inline static unsigned long int _peek(const unsigned char * p) {
|
||||
return _peek<S/2>(p) << (S/2)*8 | _peek<S/2>(p+S/2);
|
||||
}
|
||||
public:
|
||||
template<typename T>
|
||||
inline static T peek(const void * p) {
|
||||
return T(_peek<sizeof(T)>(static_cast<const unsigned char *>(p)));
|
||||
}
|
||||
template<typename T>
|
||||
inline static T peek(const void * p) {
|
||||
return T(_peek<sizeof(T)>(static_cast<const unsigned char *>(p)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static T read(const unsigned char * &p) {
|
||||
const T r = T(_peek<sizeof(T)>(p));
|
||||
p += sizeof r;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static T swap(const T x) {
|
||||
return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
|
||||
}
|
||||
template<typename T>
|
||||
inline static T read(const unsigned char * &p) {
|
||||
const T r = T(_peek<sizeof(T)>(p));
|
||||
p += sizeof r;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static T swap(const T x) {
|
||||
return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static void skip(const unsigned char * &p, size_t n=1) {
|
||||
p += sizeof(T)*n;
|
||||
}
|
||||
template<typename T>
|
||||
inline static void skip(const unsigned char * &p, size_t n=1) {
|
||||
p += sizeof(T)*n;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
@ -74,32 +79,32 @@ inline unsigned long int be::_peek<1>(const unsigned char * p) { return *p; }
|
||||
|
||||
class le
|
||||
{
|
||||
template<int S>
|
||||
inline static unsigned long int _peek(const unsigned char * p) {
|
||||
return _peek<S/2>(p) | _peek<S/2>(p+S/2) << (S/2)*8;
|
||||
}
|
||||
template<int S>
|
||||
inline static unsigned long int _peek(const unsigned char * p) {
|
||||
return _peek<S/2>(p) | _peek<S/2>(p+S/2) << (S/2)*8;
|
||||
}
|
||||
public:
|
||||
template<typename T>
|
||||
inline static T peek(const void * p) {
|
||||
return T(_peek<sizeof(T)>(static_cast<const unsigned char *>(p)));
|
||||
}
|
||||
template<typename T>
|
||||
inline static T peek(const void * p) {
|
||||
return T(_peek<sizeof(T)>(static_cast<const unsigned char *>(p)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static T read(const unsigned char * &p) {
|
||||
const T r = T(_peek<sizeof(T)>(p));
|
||||
p += sizeof r;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static T swap(const T x) {
|
||||
return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
|
||||
}
|
||||
template<typename T>
|
||||
inline static T read(const unsigned char * &p) {
|
||||
const T r = T(_peek<sizeof(T)>(p));
|
||||
p += sizeof r;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static T swap(const T x) {
|
||||
return T(_peek<sizeof(T)>(reinterpret_cast<const unsigned char *>(&x)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline static void skip(const unsigned char * &p, size_t n=1) {
|
||||
p += sizeof(T)*n;
|
||||
}
|
||||
template<typename T>
|
||||
inline static void skip(const unsigned char * &p, size_t n=1) {
|
||||
p += sizeof(T)*n;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
127
gfx/graphite2/src/inc/Error.h
Normal file
@ -0,0 +1,127 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2013, 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
|
||||
|
||||
// numbers are explicitly assigned for future proofing
|
||||
|
||||
namespace graphite2
|
||||
{
|
||||
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error() : _e(0) {};
|
||||
operator bool() { return (_e != 0); }
|
||||
int error() { return _e; }
|
||||
void error(int e) { _e = e; }
|
||||
bool test(bool pr, int err) { return (_e = int(pr) * err); }
|
||||
|
||||
private:
|
||||
int _e;
|
||||
};
|
||||
|
||||
enum errcontext {
|
||||
EC_READGLYPHS = 1, // while reading glyphs
|
||||
EC_READSILF = 2, // in Silf table
|
||||
EC_ASILF = 3, // in Silf %d
|
||||
EC_APASS = 4, // in Silf %d, pass %d
|
||||
EC_PASSCCODE = 5, // in pass constraint code for Silf %d, pass %d
|
||||
EC_ARULE = 6, // in Silf %d, pass %d, rule %d
|
||||
EC_ASTARTS = 7, // in Silf %d, pass %d, start state %d
|
||||
EC_ATRANS = 8, // in Silf %d, pass %d, fsm state %d
|
||||
EC_ARULEMAP = 9 // in Silf %d, pass %d, state %d
|
||||
};
|
||||
|
||||
enum errors {
|
||||
E_OUTOFMEM = 1, // Out of memory
|
||||
E_NOGLYPHS = 2, // There are no glyphs in the font
|
||||
E_BADUPEM = 3, // The units per em for the font is bad (0)
|
||||
E_BADCMAP = 4, // The font does not contain any useful cmaps
|
||||
E_NOSILF = 5, // Missing Silf table
|
||||
E_TOOOLD = 6, // Silf table version is too old
|
||||
E_BADSIZE = 7, // context object has the wrong structural size
|
||||
// Silf Subtable Errors take a Silf subtable number * 256 in the context
|
||||
E_BADMAXGLYPH = 8, // Silf max glyph id is too high
|
||||
E_BADNUMJUSTS = 9, // Number of Silf justification blocks is too high
|
||||
E_BADENDJUSTS = 10, // Silf justification blocks take too much of the Silf table space
|
||||
E_BADCRITFEATURES = 11, // Critical features section in a Silf table is too big
|
||||
E_BADSCRIPTTAGS = 12, // Silf script tags area is too big
|
||||
E_BADAPSEUDO = 13, // The pseudo glyph attribute number is too high
|
||||
E_BADABREAK = 14, // The linebreak glyph attribute number is too high
|
||||
E_BADABIDI = 15, // The bidi glyph attribute number is too high
|
||||
E_BADAMIRROR = 16, // The mirrored glyph attribute number is too high
|
||||
E_BADNUMPASSES = 17, // The number of passes is > 128
|
||||
E_BADPASSESSTART = 18, // The Silf table is too small to hold any passes
|
||||
E_BADPASSBOUND = 19, // The positioning pass number is too low or the substitution pass number is too high
|
||||
E_BADPPASS = 20, // The positioning pass number is too high
|
||||
E_BADSPASS = 21, // the substitution pass number is too high
|
||||
E_BADJPASSBOUND = 22, // the justification pass must be higher than the positioning pass
|
||||
E_BADJPASS = 23, // the justification pass is too high
|
||||
E_BADALIG = 24, // the number of initial ligature component glyph attributes is too high
|
||||
E_BADBPASS = 25, // the bidi pass number is specified and is either too high or too low
|
||||
E_BADNUMPSEUDO = 26, // The number of pseudo glyphs is too high
|
||||
E_BADCLASSSIZE = 27, // The size of the classes block is bad
|
||||
E_TOOMANYLINEAR = 28, // The number of linear classes in the silf table is too high
|
||||
E_CLASSESTOOBIG = 29, // There are too many classes for the space allocated in the Silf subtable
|
||||
E_MISALIGNEDCLASSES = 30, // The class offsets in the class table don't line up with the number of classes
|
||||
E_HIGHCLASSOFFSET = 31, // The class offsets point out of the class table
|
||||
E_BADCLASSOFFSET = 32, // A class offset is less than one following it
|
||||
E_BADCLASSLOOKUPINFO = 33, // The search header info for a non-linear class has wrong values in it
|
||||
// Pass subtable errors. Context has pass number * 65536
|
||||
E_BADPASSSTART = 34, // The start offset for a particular pass is bad
|
||||
E_BADPASSEND = 35, // The end offset for a particular pass is bad
|
||||
E_BADPASSLENGTH = 36, // The length of the pass is too small
|
||||
E_BADNUMTRANS = 37, // The number of transition states in the fsm is bad
|
||||
E_BADNUMSUCCESS = 38, // The number of success states in the fsm is bad
|
||||
E_BADNUMSTATES = 39, // The number of states in the fsm is bad
|
||||
E_NORANGES = 40, // There are no columns in the fsm
|
||||
E_BADRULEMAPLEN = 41, // The size of the success state to rule mapping is bad
|
||||
E_BADCTXTLENBOUNDS = 42, // The precontext maximum is greater than its minimum
|
||||
E_BADCTXTLENS = 43, // The lists of rule lengths or pre context lengths is bad
|
||||
E_BADPASSCCODEPTR = 44, // The pass constraint code position does not align with where the forward reference says it should be
|
||||
E_BADRULECCODEPTR = 45, // The rule constraint code position does not align with where the forward reference says it should be
|
||||
E_BADCCODELEN = 46, // Bad rule/pass constraint code length
|
||||
E_BADACTIONCODEPTR = 47, // The action code position does not align with where the forward reference says it should be
|
||||
E_MUTABLECCODE = 48, // Constraint code edits slots. It shouldn't.
|
||||
E_BADSTATE = 49, // Bad state transition referencing an illegal state
|
||||
E_BADRULEMAPPING = 50, // The structure of the rule mapping is bad
|
||||
E_BADRANGE = 51, // Bad column range structure including a glyph in more than one column
|
||||
E_BADRULENUM = 52, // A reference to a rule is out of range (too high)
|
||||
// Code errors
|
||||
E_CODEFAILURE = 60, // Base code error. The following subcodes must align with Machine::Code::status_t in Code.h
|
||||
E_CODEALLOC = 61, // Out of memory
|
||||
E_INVALIDOPCODE = 62, // Invalid op code
|
||||
E_UNIMPOPCODE = 63, // Unimplemented op code encountered
|
||||
E_OUTOFRANGECODE = 64, // Code argument out of range
|
||||
E_BADJUMPCODE = 65, // Code jumps past end of op codes
|
||||
E_CODEBADARGS = 66, // Code arguments exhausted
|
||||
E_CODENORETURN = 67, // Missing return type op code at end of code
|
||||
E_CODENESTEDCTXT = 68 // Nested context encountered in code
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ of the License or (at your option) any later version.
|
||||
#include "inc/FeatureMap.h"
|
||||
#include "inc/TtfUtil.h"
|
||||
#include "inc/Silf.h"
|
||||
#include "inc/Error.h"
|
||||
|
||||
namespace graphite2 {
|
||||
|
||||
@ -55,7 +56,7 @@ class Face
|
||||
Face& operator=(const Face&);
|
||||
|
||||
public:
|
||||
class Table;
|
||||
class Table;
|
||||
static float default_glyph_advance(const void* face_ptr, gr_uint16 glyphid);
|
||||
|
||||
Face(const void* appFaceHandle/*non-NULL*/, const gr_face_ops & ops);
|
||||
@ -88,6 +89,12 @@ public:
|
||||
uint16 getGlyphMetric(uint16 gid, uint8 metric) const;
|
||||
uint16 findPseudo(uint32 uid) const;
|
||||
|
||||
// Errors
|
||||
unsigned int error() const { return m_error; }
|
||||
bool error(Error e) { m_error = e.error(); return false; }
|
||||
unsigned int error_context() const { return m_error; }
|
||||
void error_context(unsigned int errcntxt) { m_errcntxt = errcntxt; }
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
private:
|
||||
SillMap m_Sill;
|
||||
@ -98,6 +105,8 @@ private:
|
||||
mutable Cmap * m_cmap; // cmap cache if available
|
||||
mutable NameTable * m_pNames;
|
||||
mutable json * m_logger;
|
||||
unsigned int m_error;
|
||||
unsigned int m_errcntxt;
|
||||
protected:
|
||||
Silf * m_silfs; // silf subtables.
|
||||
uint16 m_numSilf; // num silf subtables in the silf table
|
||||
@ -139,7 +148,7 @@ const FeatureRef *Face::feature(uint16 index) const
|
||||
inline
|
||||
const GlyphCache & Face::glyphs() const
|
||||
{
|
||||
return *m_pGlyphFaceCache;
|
||||
return *m_pGlyphFaceCache;
|
||||
}
|
||||
|
||||
inline
|
||||
@ -184,26 +193,26 @@ inline
|
||||
Face::Table::Table(const Table & rhs) throw()
|
||||
: _f(rhs._f), _p(rhs._p), _sz(rhs._sz)
|
||||
{
|
||||
rhs._p = 0;
|
||||
rhs._p = 0;
|
||||
}
|
||||
|
||||
inline
|
||||
Face::Table::~Table() throw()
|
||||
{
|
||||
if (_p && _f->m_ops.release_table)
|
||||
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
|
||||
if (_p && _f->m_ops.release_table)
|
||||
(*_f->m_ops.release_table)(_f->m_appFaceHandle, _p);
|
||||
}
|
||||
|
||||
inline
|
||||
Face::Table::operator const byte * () const throw()
|
||||
{
|
||||
return _p;
|
||||
return _p;
|
||||
}
|
||||
|
||||
inline
|
||||
size_t Face::Table::size() const throw()
|
||||
size_t Face::Table::size() const throw()
|
||||
{
|
||||
return _sz;
|
||||
return _sz;
|
||||
}
|
||||
|
||||
} // namespace graphite2
|
||||
|
@ -52,11 +52,11 @@ private:
|
||||
|
||||
class FeatureRef
|
||||
{
|
||||
typedef uint32 chunk_t;
|
||||
static const uint8 SIZEOF_CHUNK = sizeof(chunk_t)*8;
|
||||
typedef uint32 chunk_t;
|
||||
static const uint8 SIZEOF_CHUNK = sizeof(chunk_t)*8;
|
||||
|
||||
public:
|
||||
FeatureRef() : m_nameValues(0) {}
|
||||
FeatureRef() : m_nameValues(0) {}
|
||||
FeatureRef(const Face & face, unsigned short & bits_offset, uint32 max_val,
|
||||
uint32 name, uint16 uiName, uint16 flags,
|
||||
FeatureSetting *settings, uint16 num_set) throw();
|
||||
@ -64,8 +64,8 @@ public:
|
||||
|
||||
bool applyValToFeature(uint32 val, Features& pDest) const; //defined in GrFaceImp.h
|
||||
void maskFeature(Features & pDest) const {
|
||||
if (m_index < pDest.size()) //defensive
|
||||
pDest[m_index] |= m_mask;
|
||||
if (m_index < pDest.size()) //defensive
|
||||
pDest[m_index] |= m_mask;
|
||||
}
|
||||
|
||||
uint32 getFeatureVal(const Features& feats) const; //defined in GrFaceImp.h
|
||||
@ -83,16 +83,16 @@ public:
|
||||
private:
|
||||
FeatureRef(const FeatureRef & rhs);
|
||||
|
||||
const Face * m_pFace; //not NULL
|
||||
const Face * m_pFace; //not NULL
|
||||
FeatureSetting * m_nameValues; // array of name table ids for feature values
|
||||
chunk_t m_mask, // bit mask to get the value from the vector
|
||||
m_max; // max value the value can take
|
||||
uint32 m_id; // feature identifier/name
|
||||
uint16 m_nameid, // Name table id for feature name
|
||||
m_flags, // feature flags (unused at the moment but read from the font)
|
||||
m_numSet; // number of values (number of entries in m_nameValues)
|
||||
byte m_bits, // how many bits to shift the value into place
|
||||
m_index; // index into the array to find the ulong to mask
|
||||
m_max; // max value the value can take
|
||||
uint32 m_id; // feature identifier/name
|
||||
uint16 m_nameid, // Name table id for feature name
|
||||
m_flags, // feature flags (unused at the moment but read from the font)
|
||||
m_numSet; // number of values (number of entries in m_nameValues)
|
||||
byte m_bits, // how many bits to shift the value into place
|
||||
m_index; // index into the array to find the ulong to mask
|
||||
|
||||
private: //unimplemented
|
||||
FeatureRef& operator=(const FeatureRef&);
|
||||
@ -137,7 +137,7 @@ friend class SillMap;
|
||||
NameAndFeatureRef* m_pNamedFeats; //owned
|
||||
FeatureVal* m_defaultFeatures; //owned
|
||||
|
||||
private: //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
|
||||
private: //defensive on m_feats, m_pNamedFeats, and m_defaultFeatures
|
||||
FeatureMap(const FeatureMap&);
|
||||
FeatureMap& operator=(const FeatureMap&);
|
||||
};
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
|
||||
CLASS_NEW_DELETE
|
||||
private:
|
||||
friend class FeatureRef; //so that FeatureRefs can manipulate m_vec directly
|
||||
friend class FeatureRef; //so that FeatureRefs can manipulate m_vec directly
|
||||
const FeatureMap* m_pMap;
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2012, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
|
@ -32,7 +32,7 @@ of the License or (at your option) any later version.
|
||||
|
||||
namespace graphite2 {
|
||||
|
||||
#define INVALID_ADVANCE -1e38f // can't be a static const because non-integral
|
||||
#define INVALID_ADVANCE -1e38f // can't be a static const because non-integral
|
||||
|
||||
class Font
|
||||
{
|
||||
@ -69,13 +69,13 @@ float Font::advance(unsigned short glyphid) const
|
||||
inline
|
||||
float Font::scale() const
|
||||
{
|
||||
return m_scale;
|
||||
return m_scale;
|
||||
}
|
||||
|
||||
inline
|
||||
bool Font::isHinted() const
|
||||
{
|
||||
return m_hinted;
|
||||
return m_hinted;
|
||||
}
|
||||
|
||||
inline
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2012, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -41,7 +41,7 @@ class GlyphCache
|
||||
{
|
||||
class Loader;
|
||||
|
||||
GlyphCache(const GlyphCache&);
|
||||
GlyphCache(const GlyphCache&);
|
||||
GlyphCache& operator=(const GlyphCache&);
|
||||
|
||||
public:
|
||||
@ -58,11 +58,11 @@ public:
|
||||
CLASS_NEW_DELETE;
|
||||
|
||||
private:
|
||||
const Loader * _glyph_loader;
|
||||
const GlyphFace * * _glyphs;
|
||||
unsigned short _num_glyphs,
|
||||
_num_attrs,
|
||||
_upem;
|
||||
const Loader * _glyph_loader;
|
||||
const GlyphFace * * _glyphs;
|
||||
unsigned short _num_glyphs,
|
||||
_num_attrs,
|
||||
_upem;
|
||||
};
|
||||
|
||||
inline
|
||||
|
@ -147,7 +147,7 @@ public:
|
||||
CLASS_NEW_DELETE;
|
||||
|
||||
SlotMap & slotMap() const throw();
|
||||
status_t status() const throw();
|
||||
status_t status() const throw();
|
||||
operator bool () const throw();
|
||||
|
||||
private:
|
||||
@ -157,18 +157,18 @@ private:
|
||||
|
||||
SlotMap & _map;
|
||||
stack_t _stack[STACK_MAX + 2*STACK_GUARD];
|
||||
status_t _status;
|
||||
status_t _status;
|
||||
};
|
||||
|
||||
inline Machine::Machine(SlotMap & map) throw()
|
||||
: _map(map), _status(finished)
|
||||
{
|
||||
// Initialise stack guard +1 entries as the stack pointer points to the
|
||||
// current top of stack, hence the first push will never write entry 0.
|
||||
// Initialising the guard space like this is unnecessary and is only
|
||||
// done to keep valgrind happy during fuzz testing. Hopefully loop
|
||||
// unrolling will flatten this.
|
||||
for (size_t n = STACK_GUARD + 1; n; --n) _stack[n-1] = 0;
|
||||
// Initialise stack guard +1 entries as the stack pointer points to the
|
||||
// current top of stack, hence the first push will never write entry 0.
|
||||
// Initialising the guard space like this is unnecessary and is only
|
||||
// done to keep valgrind happy during fuzz testing. Hopefully loop
|
||||
// unrolling will flatten this.
|
||||
for (size_t n = STACK_GUARD + 1; n; --n) _stack[n-1] = 0;
|
||||
}
|
||||
|
||||
inline SlotMap& Machine::slotMap() const throw()
|
||||
|
@ -44,7 +44,7 @@ typedef gr_int16 int16;
|
||||
typedef gr_int32 int32;
|
||||
typedef size_t uintptr;
|
||||
|
||||
#if GRAPHITE2_TELEMETRY
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
struct telemetry
|
||||
{
|
||||
class category;
|
||||
@ -82,7 +82,7 @@ struct telemetry {};
|
||||
|
||||
template <typename T> T * gralloc(size_t n)
|
||||
{
|
||||
#if GRAPHITE2_TELEMETRY
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::count_bytes(sizeof(T) * n);
|
||||
#endif
|
||||
return reinterpret_cast<T*>(malloc(sizeof(T) * n));
|
||||
@ -90,7 +90,7 @@ template <typename T> T * gralloc(size_t n)
|
||||
|
||||
template <typename T> T * grzeroalloc(size_t n)
|
||||
{
|
||||
#if GRAPHITE2_TELEMETRY
|
||||
#ifdef GRAPHITE2_TELEMETRY
|
||||
telemetry::count_bytes(sizeof(T) * n);
|
||||
#endif
|
||||
return reinterpret_cast<T*>(calloc(n, sizeof(T)));
|
||||
|
@ -38,6 +38,7 @@ struct Rule;
|
||||
struct RuleEntry;
|
||||
struct State;
|
||||
class FiniteStateMachine;
|
||||
class Error;
|
||||
|
||||
class Pass
|
||||
{
|
||||
@ -45,29 +46,29 @@ public:
|
||||
Pass();
|
||||
~Pass();
|
||||
|
||||
bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, const Face & face);
|
||||
bool readPass(const byte * pPass, size_t pass_length, size_t subtable_base, Face & face, Error &e);
|
||||
void runGraphite(vm::Machine & m, FiniteStateMachine & fsm) const;
|
||||
void init(Silf *silf) { m_silf = silf; }
|
||||
byte spaceContextuals() const { return (m_flags & 0x0E) >> 1; }
|
||||
|
||||
CLASS_NEW_DELETE
|
||||
private:
|
||||
void findNDoRule(Slot* & iSlot, vm::Machine &, FiniteStateMachine& fsm) const;
|
||||
int doAction(const vm::Machine::Code* codeptr, Slot * & slot_out, vm::Machine &) const;
|
||||
bool testPassConstraint(vm::Machine & m) const;
|
||||
bool testConstraint(const Rule & r, vm::Machine &) const;
|
||||
bool readRules(const byte * rule_map, const size_t num_entries,
|
||||
void findNDoRule(Slot* & iSlot, vm::Machine &, FiniteStateMachine& fsm) const;
|
||||
int doAction(const vm::Machine::Code* codeptr, Slot * & slot_out, vm::Machine &) const;
|
||||
bool testPassConstraint(vm::Machine & m) const;
|
||||
bool testConstraint(const Rule & r, vm::Machine &) const;
|
||||
bool readRules(const byte * rule_map, const size_t num_entries,
|
||||
const byte *precontext, const uint16 * sort_key,
|
||||
const uint16 * o_constraint, const byte *constraint_data,
|
||||
const uint16 * o_action, const byte * action_data,
|
||||
const Face &);
|
||||
bool readStates(const byte * starts, const byte * states, const byte * o_rule_map, const Face &);
|
||||
bool readRanges(const byte * ranges, size_t num_ranges);
|
||||
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 adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
|
||||
Face &, Error &e);
|
||||
bool readStates(const byte * starts, const byte * states, const byte * o_rule_map, Face &, Error &e);
|
||||
bool readRanges(const byte * ranges, size_t num_ranges, Error &e);
|
||||
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 adjustSlot(int delta, Slot * & slot_out, SlotMap &) const;
|
||||
const Silf* m_silf;
|
||||
uint16 * m_cols;
|
||||
Rule * m_rules; // rules
|
||||
@ -89,7 +90,7 @@ private:
|
||||
byte m_maxPreCtxt;
|
||||
vm::Machine::Code m_cPConstraint;
|
||||
|
||||
private: //defensive
|
||||
private: //defensive
|
||||
Pass(const Pass&);
|
||||
Pass& operator=(const Pass&);
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -107,12 +107,12 @@ public:
|
||||
Slot * const & operator[](int n) const;
|
||||
Slot * & operator [] (int);
|
||||
void pushSlot(Slot * const slot);
|
||||
void collectGarbage();
|
||||
void collectGarbage();
|
||||
|
||||
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; }
|
||||
bool highpassed() const { return m_highpassed; }
|
||||
void highpassed(bool v) { m_highpassed = v; }
|
||||
|
||||
Segment & segment;
|
||||
private:
|
||||
@ -120,7 +120,7 @@ private:
|
||||
unsigned short m_size;
|
||||
unsigned short m_precontext;
|
||||
Slot * m_highwater;
|
||||
bool m_highpassed;
|
||||
bool m_highpassed;
|
||||
};
|
||||
|
||||
|
||||
|
@ -93,9 +93,7 @@ public:
|
||||
if (m_entryCounts[length-1] + 1u > listSize)
|
||||
{
|
||||
if (m_entryCounts[length-1] == 0)
|
||||
{
|
||||
listSize = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the problem comes when you get incremental numeric ids in a large doc
|
||||
@ -105,9 +103,7 @@ public:
|
||||
}
|
||||
newEntries = gralloc<SegCacheEntry>(listSize);
|
||||
if (!newEntries)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
uint16 insertPos = 0;
|
||||
|
@ -39,6 +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"
|
||||
|
||||
#define MAX_SEG_GROWTH_FACTOR 256
|
||||
|
||||
@ -116,7 +117,7 @@ public:
|
||||
SlotJustify *newJustify();
|
||||
void freeJustify(SlotJustify *aJustify);
|
||||
Position positionSlots(const Font *font, Slot *first=0, Slot *last=0);
|
||||
void associateChars();
|
||||
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); }
|
||||
uint16 findClassIndex(uint16 cid, uint16 gid) const { return m_silf->findClassIndex(cid, gid); }
|
||||
@ -144,13 +145,12 @@ public:
|
||||
CLASS_NEW_DELETE
|
||||
|
||||
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);
|
||||
void read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
|
||||
bool read_text(const Face *face, const Features* pFeats/*must not be NULL*/, gr_encform enc, const void*pStart, size_t nChars);
|
||||
void prepare_pos(const Font *font);
|
||||
void finalise(const Font *font);
|
||||
float justify(Slot *pSlot, const Font *font, float width, enum justFlags flags, Slot *pFirst, Slot *pLast);
|
||||
|
||||
private:
|
||||
Rect m_bbox; // ink box of the segment
|
||||
Position m_advance; // whole segment advance
|
||||
SlotRope m_slots; // Vector of slot buffers
|
||||
AttributeRope m_userAttrs; // Vector of userAttrs buffers
|
||||
@ -176,10 +176,10 @@ private:
|
||||
inline
|
||||
void Segment::finalise(const Font *font)
|
||||
{
|
||||
if (!m_first) return;
|
||||
if (!m_first) return;
|
||||
|
||||
m_advance = positionSlots(font);
|
||||
associateChars();
|
||||
associateChars(0, m_numCharinfo);
|
||||
linkClusters(m_first, m_last);
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ class Face;
|
||||
class Segment;
|
||||
class FeatureVal;
|
||||
class VMScratch;
|
||||
class Error;
|
||||
|
||||
class Pseudo
|
||||
{
|
||||
@ -73,8 +74,8 @@ public:
|
||||
Silf() throw();
|
||||
~Silf() throw();
|
||||
|
||||
bool readGraphite(const byte * const pSilf, size_t lSilf, const Face &face, uint32 version);
|
||||
bool runGraphite(Segment *seg, uint8 firstPass=0, uint8 lastPass=0) const;
|
||||
bool readGraphite(const byte * const pSilf, size_t lSilf, Face &face, uint32 version);
|
||||
bool runGraphite(Segment *seg, uint8 firstPass=0, uint8 lastPass=0, int dobidi = 0) const;
|
||||
uint16 findClassIndex(uint16 cid, uint16 gid) const;
|
||||
uint16 getClassGlyph(uint16 cid, unsigned int index) const;
|
||||
uint16 findPseudo(uint32 uid) const;
|
||||
@ -83,6 +84,7 @@ public:
|
||||
uint8 aBreak() const { return m_aBreak; }
|
||||
uint8 aMirror() const {return m_aMirror; }
|
||||
uint8 aPassBits() const { return m_aPassBits; }
|
||||
uint8 aBidi() const { return m_aBidi; }
|
||||
uint8 substitutionPass() const { return m_sPass; }
|
||||
uint8 positionPass() const { return m_pPass; }
|
||||
uint8 justificationPass() const { return m_jPass; }
|
||||
@ -99,8 +101,8 @@ public:
|
||||
CLASS_NEW_DELETE;
|
||||
|
||||
private:
|
||||
size_t readClassMap(const byte *p, size_t data_len, uint32 version);
|
||||
template<typename T> inline uint32 readClassOffsets(const byte *&p, size_t data_len);
|
||||
size_t readClassMap(const byte *p, size_t data_len, uint32 version, Error &e);
|
||||
template<typename T> inline uint32 readClassOffsets(const byte *&p, size_t data_len, Error &e);
|
||||
|
||||
Pass * m_passes;
|
||||
Pseudo * m_pseudos;
|
||||
|
@ -60,17 +60,17 @@ public:
|
||||
|
||||
class Slot
|
||||
{
|
||||
enum Flag
|
||||
{
|
||||
DELETED = 1,
|
||||
INSERTED = 2,
|
||||
COPIED = 4,
|
||||
POSITIONED = 8,
|
||||
ATTACHED = 16
|
||||
};
|
||||
enum Flag
|
||||
{
|
||||
DELETED = 1,
|
||||
INSERTED = 2,
|
||||
COPIED = 4,
|
||||
POSITIONED = 8,
|
||||
ATTACHED = 16
|
||||
};
|
||||
|
||||
public:
|
||||
struct iterator;
|
||||
struct iterator;
|
||||
|
||||
unsigned short gid() const { return m_glyphid; }
|
||||
Position origin() const { return m_position; }
|
||||
@ -82,7 +82,7 @@ public:
|
||||
void index(uint32 val) { m_index = val; }
|
||||
|
||||
Slot();
|
||||
void set(const Slot & slot, int charOffset, size_t numUserAttr, size_t justLevels);
|
||||
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; }
|
||||
Slot *prev() const { return m_prev; }
|
||||
@ -108,8 +108,8 @@ public:
|
||||
bool isInsertBefore() const { return !(m_flags & INSERTED); }
|
||||
uint8 getBidiLevel() const { return m_bidiLevel; }
|
||||
void setBidiLevel(uint8 level) { m_bidiLevel = level; }
|
||||
uint8 getBidiClass() const { return m_bidiCls; }
|
||||
void setBidiClass(uint8 cls) { m_bidiCls = cls; }
|
||||
int8 getBidiClass() const { return m_bidiCls; }
|
||||
void setBidiClass(int8 cls) { m_bidiCls = cls; }
|
||||
int16 *userAttrs() const { return m_userAttr; }
|
||||
void userAttrs(int16 *p) { m_userAttr = p; }
|
||||
void markInsertBefore(bool state) { if (!state) m_flags |= INSERTED; else m_flags &= ~INSERTED; }
|
||||
@ -140,7 +140,7 @@ private:
|
||||
Slot *m_prev;
|
||||
unsigned short m_glyphid; // glyph id
|
||||
uint16 m_realglyphid;
|
||||
uint32 m_original; // charinfo that originated this slot (e.g. for feature values)
|
||||
uint32 m_original; // charinfo that originated this slot (e.g. for feature values)
|
||||
uint32 m_before; // charinfo index of before association
|
||||
uint32 m_after; // charinfo index of after association
|
||||
uint32 m_index; // slot index given to this slot during finalising
|
||||
@ -151,11 +151,11 @@ private:
|
||||
Position m_shift; // .shift slot attribute
|
||||
Position m_advance; // .advance slot attribute
|
||||
Position m_attach; // attachment point on us
|
||||
Position m_with; // attachment point position on parent
|
||||
Position m_with; // attachment point position on parent
|
||||
float m_just; // Justification inserted space
|
||||
uint8 m_flags; // holds bit flags
|
||||
byte m_attLevel; // attachment level
|
||||
byte m_bidiCls; // bidirectional class
|
||||
int8 m_bidiCls; // bidirectional class
|
||||
byte m_bidiLevel; // bidirectional level
|
||||
int16 *m_userAttr; // pointer to user attributes
|
||||
SlotJustify *m_justs; // pointer to justification parameters
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -43,51 +43,52 @@ class sparse
|
||||
public:
|
||||
typedef uint16 key_type;
|
||||
typedef uint16 mapped_type;
|
||||
typedef std::pair<const key_type, mapped_type> value_type;
|
||||
typedef std::pair<const key_type, mapped_type> value_type;
|
||||
|
||||
private:
|
||||
typedef unsigned long mask_t;
|
||||
typedef unsigned long mask_t;
|
||||
|
||||
static const unsigned char SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;
|
||||
static const unsigned char SIZEOF_CHUNK = (sizeof(mask_t) - sizeof(key_type))*8;
|
||||
|
||||
struct chunk
|
||||
{
|
||||
mask_t mask:SIZEOF_CHUNK;
|
||||
key_type offset;
|
||||
};
|
||||
struct chunk
|
||||
{
|
||||
mask_t mask:SIZEOF_CHUNK;
|
||||
key_type offset;
|
||||
};
|
||||
|
||||
sparse(const sparse &);
|
||||
sparse & operator = (const sparse &);
|
||||
static chunk empty_chunk;
|
||||
sparse(const sparse &);
|
||||
sparse & operator = (const sparse &);
|
||||
|
||||
public:
|
||||
template<typename I>
|
||||
sparse(I first, const I last);
|
||||
sparse() throw();
|
||||
~sparse() throw();
|
||||
template<typename I>
|
||||
sparse(I first, const I last);
|
||||
sparse() throw();
|
||||
~sparse() throw();
|
||||
|
||||
operator bool () const throw();
|
||||
mapped_type operator [] (const key_type k) const throw();
|
||||
operator bool () const throw();
|
||||
mapped_type operator [] (const key_type k) const throw();
|
||||
|
||||
size_t capacity() const throw();
|
||||
size_t size() const throw();
|
||||
size_t capacity() const throw();
|
||||
size_t size() const throw();
|
||||
|
||||
size_t _sizeof() const throw();
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
size_t _sizeof() const throw();
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
|
||||
private:
|
||||
union {
|
||||
chunk * map;
|
||||
mapped_type * values;
|
||||
} m_array;
|
||||
key_type m_nchunks;
|
||||
union {
|
||||
chunk * map;
|
||||
mapped_type * values;
|
||||
} m_array;
|
||||
key_type m_nchunks;
|
||||
};
|
||||
|
||||
|
||||
inline
|
||||
sparse::sparse() throw() : m_nchunks(0)
|
||||
{
|
||||
m_array.map = 0;
|
||||
m_array.map = &empty_chunk;
|
||||
}
|
||||
|
||||
|
||||
@ -97,49 +98,61 @@ sparse::sparse(I attr, const I last)
|
||||
{
|
||||
m_array.map = 0;
|
||||
|
||||
// Find the maximum extent of the key space.
|
||||
size_t n_values=0;
|
||||
for (I i = attr; i != last; ++i, ++n_values)
|
||||
{
|
||||
const key_type k = (*i).first / SIZEOF_CHUNK;
|
||||
if (k >= m_nchunks) m_nchunks = k+1;
|
||||
}
|
||||
if (m_nchunks == 0) return;
|
||||
// Find the maximum extent of the key space.
|
||||
size_t n_values=0;
|
||||
long lastkey = -1;
|
||||
for (I i = attr; i != last; ++i, ++n_values)
|
||||
{
|
||||
const typename std::iterator_traits<I>::value_type v = *i;
|
||||
if (v.second == 0) { --n_values; continue; }
|
||||
if (v.first <= lastkey) { m_nchunks = 0; return; }
|
||||
|
||||
m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)
|
||||
/ sizeof(mapped_type)
|
||||
+ n_values);
|
||||
lastkey = v.first;
|
||||
const key_type k = v.first / SIZEOF_CHUNK;
|
||||
if (k >= m_nchunks) m_nchunks = k+1;
|
||||
}
|
||||
if (m_nchunks == 0)
|
||||
{
|
||||
m_array.map=&empty_chunk;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_array.values == 0)
|
||||
{
|
||||
free(m_array.values); m_array.map=0;
|
||||
return;
|
||||
}
|
||||
m_array.values = grzeroalloc<mapped_type>((m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)
|
||||
/ sizeof(mapped_type)
|
||||
+ n_values);
|
||||
|
||||
chunk * ci = m_array.map;
|
||||
ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
|
||||
mapped_type * vi = m_array.values + ci->offset;
|
||||
for (; attr != last; ++attr, ++vi)
|
||||
{
|
||||
const typename std::iterator_traits<I>::value_type v = *attr;
|
||||
chunk * const ci_ = m_array.map + v.first/SIZEOF_CHUNK;
|
||||
if (m_array.values == 0)
|
||||
{
|
||||
free(m_array.values); m_array.map=0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ci != ci_)
|
||||
{
|
||||
ci = ci_;
|
||||
ci->offset = vi - m_array.values;
|
||||
}
|
||||
chunk * ci = m_array.map;
|
||||
ci->offset = (m_nchunks*sizeof(chunk) + sizeof(mapped_type)-1)/sizeof(mapped_type);
|
||||
mapped_type * vi = m_array.values + ci->offset;
|
||||
for (; attr != last; ++attr, ++vi)
|
||||
{
|
||||
const typename std::iterator_traits<I>::value_type v = *attr;
|
||||
if (v.second == 0) { --vi; continue; }
|
||||
|
||||
ci->mask |= 1UL << (SIZEOF_CHUNK - 1 - (v.first % SIZEOF_CHUNK));
|
||||
*vi = v.second;
|
||||
}
|
||||
chunk * const ci_ = m_array.map + v.first/SIZEOF_CHUNK;
|
||||
|
||||
if (ci != ci_)
|
||||
{
|
||||
ci = ci_;
|
||||
ci->offset = vi - m_array.values;
|
||||
}
|
||||
|
||||
ci->mask |= 1UL << (SIZEOF_CHUNK - 1 - (v.first % SIZEOF_CHUNK));
|
||||
*vi = v.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
sparse::operator bool () const throw()
|
||||
{
|
||||
return m_array.map != 0;
|
||||
return m_array.map != 0;
|
||||
}
|
||||
|
||||
inline
|
||||
@ -151,7 +164,7 @@ size_t sparse::size() const throw()
|
||||
inline
|
||||
size_t sparse::_sizeof() const throw()
|
||||
{
|
||||
return sizeof(sparse) + capacity()*sizeof(mapped_type) + m_nchunks*sizeof(chunk);
|
||||
return sizeof(sparse) + capacity()*sizeof(mapped_type) + m_nchunks*sizeof(chunk);
|
||||
}
|
||||
|
||||
} // namespace graphite2
|
||||
|
@ -37,380 +37,380 @@ Provides types required to represent the TTF basic types.
|
||||
|
||||
|
||||
//**********************************************************************************************
|
||||
// Include files
|
||||
// Include files
|
||||
//**********************************************************************************************
|
||||
namespace graphite2
|
||||
{
|
||||
namespace TtfUtil
|
||||
{
|
||||
//**********************************************************************************************
|
||||
// Forward declarations
|
||||
// Forward declarations
|
||||
//**********************************************************************************************
|
||||
|
||||
|
||||
//**********************************************************************************************
|
||||
// Type declarations
|
||||
// Type declarations
|
||||
//**********************************************************************************************
|
||||
typedef unsigned char uint8;
|
||||
typedef uint8 byte;
|
||||
typedef signed char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
typedef unsigned char uint8;
|
||||
typedef uint8 byte;
|
||||
typedef signed char int8;
|
||||
typedef unsigned short uint16;
|
||||
typedef short int16;
|
||||
typedef unsigned int uint32;
|
||||
typedef int int32;
|
||||
|
||||
typedef int16 short_frac;
|
||||
typedef int32 fixed;
|
||||
typedef int16 fword;
|
||||
typedef uint16 ufword;
|
||||
typedef int16 f2dot14;
|
||||
typedef uint32 long_date_time[2];
|
||||
typedef int16 short_frac;
|
||||
typedef int32 fixed;
|
||||
typedef int16 fword;
|
||||
typedef uint16 ufword;
|
||||
typedef int16 f2dot14;
|
||||
typedef uint32 long_date_time[2];
|
||||
|
||||
//**********************************************************************************************
|
||||
// Constants and enum types
|
||||
// Constants and enum types
|
||||
//**********************************************************************************************/
|
||||
enum
|
||||
{
|
||||
OneFix = 1<<16
|
||||
OneFix = 1<<16
|
||||
};
|
||||
|
||||
//**********************************************************************************************
|
||||
// Table declarations
|
||||
// Table declarations
|
||||
//**********************************************************************************************
|
||||
namespace Sfnt
|
||||
{
|
||||
#pragma pack(1) // We need this or the structure members aren't alligned
|
||||
// correctly. Fortunately this form of pragma is supposed
|
||||
// to be recongnised by VS C++ too (at least according to
|
||||
// MSDN).
|
||||
#pragma pack(1) // We need this or the structure members aren't alligned
|
||||
// correctly. Fortunately this form of pragma is supposed
|
||||
// to be recongnised by VS C++ too (at least according to
|
||||
// MSDN).
|
||||
|
||||
struct OffsetSubTable
|
||||
{
|
||||
uint32 scaler_type;
|
||||
uint16 num_tables,
|
||||
search_range,
|
||||
entry_selector,
|
||||
range_shift;
|
||||
struct Entry
|
||||
{
|
||||
uint32 tag,
|
||||
checksum,
|
||||
offset,
|
||||
length;
|
||||
} table_directory[1];
|
||||
struct OffsetSubTable
|
||||
{
|
||||
uint32 scaler_type;
|
||||
uint16 num_tables,
|
||||
search_range,
|
||||
entry_selector,
|
||||
range_shift;
|
||||
struct Entry
|
||||
{
|
||||
uint32 tag,
|
||||
checksum,
|
||||
offset,
|
||||
length;
|
||||
} table_directory[1];
|
||||
|
||||
enum ScalerType
|
||||
{
|
||||
TrueTypeMac = 0x74727565U,
|
||||
TrueTypeWin = 0x00010000U,
|
||||
Type1 = 0x74797031U
|
||||
};
|
||||
};
|
||||
enum ScalerType
|
||||
{
|
||||
TrueTypeMac = 0x74727565U,
|
||||
TrueTypeWin = 0x00010000U,
|
||||
Type1 = 0x74797031U
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct CharacterCodeMap
|
||||
{
|
||||
uint16 version,
|
||||
num_subtables;
|
||||
struct
|
||||
{
|
||||
uint16 platform_id,
|
||||
platform_specific_id;
|
||||
uint32 offset;
|
||||
} encoding[1];
|
||||
};
|
||||
|
||||
struct CharacterCodeMap
|
||||
{
|
||||
uint16 version,
|
||||
num_subtables;
|
||||
struct
|
||||
{
|
||||
uint16 platform_id,
|
||||
platform_specific_id;
|
||||
uint32 offset;
|
||||
} encoding[1];
|
||||
};
|
||||
|
||||
struct CmapSubTable
|
||||
{
|
||||
uint16 format,
|
||||
length,
|
||||
language;
|
||||
};
|
||||
struct CmapSubTable
|
||||
{
|
||||
uint16 format,
|
||||
length,
|
||||
language;
|
||||
};
|
||||
|
||||
struct CmapSubTableFormat4 : CmapSubTable
|
||||
{
|
||||
uint16 seg_count_x2,
|
||||
search_range,
|
||||
entry_selector,
|
||||
range_shift,
|
||||
end_code[1];
|
||||
// There are arrarys after this which need their
|
||||
// start positions calculated since end_code is
|
||||
// seg_count uint16s long.
|
||||
};
|
||||
struct CmapSubTableFormat4 : CmapSubTable
|
||||
{
|
||||
uint16 seg_count_x2,
|
||||
search_range,
|
||||
entry_selector,
|
||||
range_shift,
|
||||
end_code[1];
|
||||
// There are arrarys after this which need their
|
||||
// start positions calculated since end_code is
|
||||
// seg_count uint16s long.
|
||||
};
|
||||
|
||||
struct CmapSubTableFormat12
|
||||
{
|
||||
fixed format;
|
||||
uint32 length,
|
||||
language,
|
||||
num_groups;
|
||||
struct
|
||||
{
|
||||
uint32 start_char_code,
|
||||
end_char_code,
|
||||
start_glyph_id;
|
||||
} group[1];
|
||||
};
|
||||
struct CmapSubTableFormat12
|
||||
{
|
||||
fixed format;
|
||||
uint32 length,
|
||||
language,
|
||||
num_groups;
|
||||
struct
|
||||
{
|
||||
uint32 start_char_code,
|
||||
end_char_code,
|
||||
start_glyph_id;
|
||||
} group[1];
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct FontHeader
|
||||
{
|
||||
fixed version,
|
||||
font_revision;
|
||||
uint32 check_sum_adjustment,
|
||||
magic_number;
|
||||
uint16 flags,
|
||||
units_per_em;
|
||||
long_date_time created,
|
||||
modified;
|
||||
fword x_min,
|
||||
y_min,
|
||||
x_max,
|
||||
y_max;
|
||||
uint16 mac_style,
|
||||
lowest_rec_ppem;
|
||||
int16 font_direction_hint,
|
||||
index_to_loc_format,
|
||||
glyph_data_format;
|
||||
enum
|
||||
{
|
||||
MagicNumber = 0x5F0F3CF5,
|
||||
GlypDataFormat = 0
|
||||
};
|
||||
enum {ShortIndexLocFormat, LongIndexLocFormat};
|
||||
};
|
||||
struct FontHeader
|
||||
{
|
||||
fixed version,
|
||||
font_revision;
|
||||
uint32 check_sum_adjustment,
|
||||
magic_number;
|
||||
uint16 flags,
|
||||
units_per_em;
|
||||
long_date_time created,
|
||||
modified;
|
||||
fword x_min,
|
||||
y_min,
|
||||
x_max,
|
||||
y_max;
|
||||
uint16 mac_style,
|
||||
lowest_rec_ppem;
|
||||
int16 font_direction_hint,
|
||||
index_to_loc_format,
|
||||
glyph_data_format;
|
||||
enum
|
||||
{
|
||||
MagicNumber = 0x5F0F3CF5,
|
||||
GlypDataFormat = 0
|
||||
};
|
||||
enum {ShortIndexLocFormat, LongIndexLocFormat};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct PostScriptGlyphName
|
||||
{
|
||||
fixed format,
|
||||
italic_angle;
|
||||
fword underline_position,
|
||||
underline_thickness;
|
||||
uint32 is_fixed_pitch,
|
||||
min_mem_type42,
|
||||
max_mem_type42,
|
||||
min_mem_type1,
|
||||
max_mem_type1;
|
||||
enum
|
||||
{
|
||||
Format1 = 0x10000,
|
||||
Format2 = 0x20000,
|
||||
Format25 = 0x28000,
|
||||
Format3 = 0x30000,
|
||||
Format4 = 0x40000
|
||||
};
|
||||
};
|
||||
|
||||
struct PostScriptGlyphName2 : PostScriptGlyphName
|
||||
{
|
||||
uint16 number_of_glyphs,
|
||||
glyph_name_index[1];
|
||||
};
|
||||
|
||||
struct PostScriptGlyphName25 : PostScriptGlyphName
|
||||
{
|
||||
uint16 number_of_glyphs;
|
||||
int8 offset[1];
|
||||
};
|
||||
|
||||
struct PostScriptGlyphName3 : PostScriptGlyphName {};
|
||||
|
||||
struct PostScriptGlyphName4 : PostScriptGlyphName
|
||||
{
|
||||
uint16 glyph_to_char_map[1];
|
||||
};
|
||||
|
||||
|
||||
struct HorizontalHeader
|
||||
{
|
||||
fixed version;
|
||||
fword ascent,
|
||||
descent,
|
||||
line_gap;
|
||||
ufword advance_width_max;
|
||||
fword min_left_side_bearing,
|
||||
max_left_side_bearing,
|
||||
x_max_element;
|
||||
int16 caret_slope_rise,
|
||||
caret_slope_run;
|
||||
fword caret_offset;
|
||||
int16 reserved[4],
|
||||
metric_data_format;
|
||||
uint16 num_long_hor_metrics;
|
||||
};
|
||||
|
||||
struct MaximumProfile
|
||||
{
|
||||
fixed version;
|
||||
uint16 num_glyphs,
|
||||
max_points,
|
||||
max_contours,
|
||||
max_component_points,
|
||||
max_component_contours,
|
||||
max_zones,
|
||||
max_twilight_points,
|
||||
max_storage,
|
||||
max_function_defs,
|
||||
max_instruction_defs,
|
||||
max_stack_elements,
|
||||
max_size_of_instructions,
|
||||
max_component_elements,
|
||||
max_component_depth;
|
||||
};
|
||||
struct PostScriptGlyphName
|
||||
{
|
||||
fixed format,
|
||||
italic_angle;
|
||||
fword underline_position,
|
||||
underline_thickness;
|
||||
uint32 is_fixed_pitch,
|
||||
min_mem_type42,
|
||||
max_mem_type42,
|
||||
min_mem_type1,
|
||||
max_mem_type1;
|
||||
enum
|
||||
{
|
||||
Format1 = 0x10000,
|
||||
Format2 = 0x20000,
|
||||
Format25 = 0x28000,
|
||||
Format3 = 0x30000,
|
||||
Format4 = 0x40000
|
||||
};
|
||||
};
|
||||
|
||||
struct PostScriptGlyphName2 : PostScriptGlyphName
|
||||
{
|
||||
uint16 number_of_glyphs,
|
||||
glyph_name_index[1];
|
||||
};
|
||||
|
||||
struct PostScriptGlyphName25 : PostScriptGlyphName
|
||||
{
|
||||
uint16 number_of_glyphs;
|
||||
int8 offset[1];
|
||||
};
|
||||
|
||||
struct PostScriptGlyphName3 : PostScriptGlyphName {};
|
||||
|
||||
struct PostScriptGlyphName4 : PostScriptGlyphName
|
||||
{
|
||||
uint16 glyph_to_char_map[1];
|
||||
};
|
||||
|
||||
|
||||
struct HorizontalHeader
|
||||
{
|
||||
fixed version;
|
||||
fword ascent,
|
||||
descent,
|
||||
line_gap;
|
||||
ufword advance_width_max;
|
||||
fword min_left_side_bearing,
|
||||
max_left_side_bearing,
|
||||
x_max_element;
|
||||
int16 caret_slope_rise,
|
||||
caret_slope_run;
|
||||
fword caret_offset;
|
||||
int16 reserved[4],
|
||||
metric_data_format;
|
||||
uint16 num_long_hor_metrics;
|
||||
};
|
||||
|
||||
struct MaximumProfile
|
||||
{
|
||||
fixed version;
|
||||
uint16 num_glyphs,
|
||||
max_points,
|
||||
max_contours,
|
||||
max_component_points,
|
||||
max_component_contours,
|
||||
max_zones,
|
||||
max_twilight_points,
|
||||
max_storage,
|
||||
max_function_defs,
|
||||
max_instruction_defs,
|
||||
max_stack_elements,
|
||||
max_size_of_instructions,
|
||||
max_component_elements,
|
||||
max_component_depth;
|
||||
};
|
||||
|
||||
|
||||
typedef byte Panose[10];
|
||||
typedef byte Panose[10];
|
||||
|
||||
struct Compatibility0
|
||||
{
|
||||
uint16 version;
|
||||
int16 x_avg_char_width;
|
||||
uint16 weight_class,
|
||||
width_class;
|
||||
int16 fs_type,
|
||||
y_subscript_x_size,
|
||||
y_subscript_y_size,
|
||||
y_subscript_x_offset,
|
||||
y_subscript_y_offset,
|
||||
y_superscript_x_size,
|
||||
y_superscript_y_size,
|
||||
y_superscript_x_offset,
|
||||
y_superscript_y_offset,
|
||||
y_strikeout_size,
|
||||
y_strikeout_position,
|
||||
family_class;
|
||||
Panose panose;
|
||||
uint32 unicode_range[4];
|
||||
int8 ach_vend_id[4];
|
||||
uint16 fs_selection,
|
||||
fs_first_char_index,
|
||||
fs_last_char_index, // Acording to Apple's spec this is where v0 should end
|
||||
typo_ascender,
|
||||
typo_descender,
|
||||
type_linegap,
|
||||
win_ascent,
|
||||
win_descent;
|
||||
|
||||
enum
|
||||
{
|
||||
Italic =0x01,
|
||||
Underscore=0x02,
|
||||
Negative =0x04,
|
||||
Outlined =0x08,
|
||||
StrikeOut =0x10,
|
||||
Bold =0x20
|
||||
};
|
||||
};
|
||||
|
||||
struct Compatibility1 : Compatibility0
|
||||
{
|
||||
uint32 codepage_range[2];
|
||||
};
|
||||
|
||||
struct Compatibility2 : Compatibility1
|
||||
{
|
||||
int16 x_height,
|
||||
cap_height;
|
||||
uint16 default_char,
|
||||
break_char,
|
||||
max_context;
|
||||
};
|
||||
|
||||
struct Compatibility3 : Compatibility2 {};
|
||||
|
||||
typedef Compatibility3 Compatibility;
|
||||
|
||||
|
||||
struct NameRecord
|
||||
{
|
||||
uint16 platform_id,
|
||||
platform_specific_id,
|
||||
language_id,
|
||||
name_id,
|
||||
length,
|
||||
offset;
|
||||
enum {Unicode, Mactintosh, Reserved, Microsoft};
|
||||
enum
|
||||
{
|
||||
Copyright, Family, Subfamily, UniqueSubfamily,
|
||||
Fullname, Version, PostScript
|
||||
};
|
||||
};
|
||||
struct Compatibility0
|
||||
{
|
||||
uint16 version;
|
||||
int16 x_avg_char_width;
|
||||
uint16 weight_class,
|
||||
width_class;
|
||||
int16 fs_type,
|
||||
y_subscript_x_size,
|
||||
y_subscript_y_size,
|
||||
y_subscript_x_offset,
|
||||
y_subscript_y_offset,
|
||||
y_superscript_x_size,
|
||||
y_superscript_y_size,
|
||||
y_superscript_x_offset,
|
||||
y_superscript_y_offset,
|
||||
y_strikeout_size,
|
||||
y_strikeout_position,
|
||||
family_class;
|
||||
Panose panose;
|
||||
uint32 unicode_range[4];
|
||||
int8 ach_vend_id[4];
|
||||
uint16 fs_selection,
|
||||
fs_first_char_index,
|
||||
fs_last_char_index, // Acording to Apple's spec this is where v0 should end
|
||||
typo_ascender,
|
||||
typo_descender,
|
||||
type_linegap,
|
||||
win_ascent,
|
||||
win_descent;
|
||||
|
||||
enum
|
||||
{
|
||||
Italic =0x01,
|
||||
Underscore=0x02,
|
||||
Negative =0x04,
|
||||
Outlined =0x08,
|
||||
StrikeOut =0x10,
|
||||
Bold =0x20
|
||||
};
|
||||
};
|
||||
|
||||
struct Compatibility1 : Compatibility0
|
||||
{
|
||||
uint32 codepage_range[2];
|
||||
};
|
||||
|
||||
struct Compatibility2 : Compatibility1
|
||||
{
|
||||
int16 x_height,
|
||||
cap_height;
|
||||
uint16 default_char,
|
||||
break_char,
|
||||
max_context;
|
||||
};
|
||||
|
||||
struct Compatibility3 : Compatibility2 {};
|
||||
|
||||
typedef Compatibility3 Compatibility;
|
||||
|
||||
|
||||
struct NameRecord
|
||||
{
|
||||
uint16 platform_id,
|
||||
platform_specific_id,
|
||||
language_id,
|
||||
name_id,
|
||||
length,
|
||||
offset;
|
||||
enum {Unicode, Mactintosh, Reserved, Microsoft};
|
||||
enum
|
||||
{
|
||||
Copyright, Family, Subfamily, UniqueSubfamily,
|
||||
Fullname, Version, PostScript
|
||||
};
|
||||
};
|
||||
|
||||
struct LangTagRecord
|
||||
{
|
||||
uint16 length,
|
||||
offset;
|
||||
};
|
||||
struct LangTagRecord
|
||||
{
|
||||
uint16 length,
|
||||
offset;
|
||||
};
|
||||
|
||||
struct FontNames
|
||||
{
|
||||
uint16 format,
|
||||
count,
|
||||
string_offset;
|
||||
NameRecord name_record[1];
|
||||
};
|
||||
|
||||
|
||||
struct HorizontalMetric
|
||||
{
|
||||
uint16 advance_width;
|
||||
int16 left_side_bearing;
|
||||
};
|
||||
|
||||
|
||||
struct Glyph
|
||||
{
|
||||
int16 number_of_contours;
|
||||
fword x_min,
|
||||
y_min,
|
||||
x_max,
|
||||
y_max;
|
||||
};
|
||||
|
||||
struct SimpleGlyph : Glyph
|
||||
{
|
||||
uint16 end_pts_of_contours[1];
|
||||
enum
|
||||
{
|
||||
OnCurve = 0x01,
|
||||
XShort = 0x02,
|
||||
YShort = 0x04,
|
||||
Repeat = 0x08,
|
||||
XIsSame = 0x10,
|
||||
XIsPos = 0x10,
|
||||
YIsSame = 0x20,
|
||||
YIsPos = 0x20
|
||||
};
|
||||
};
|
||||
|
||||
struct CompoundGlyph : Glyph
|
||||
{
|
||||
uint16 flags,
|
||||
glyph_index;
|
||||
enum
|
||||
{
|
||||
Arg1Arg2Words = 0x01,
|
||||
ArgsAreXYValues = 0x02,
|
||||
RoundXYToGrid = 0x04,
|
||||
HaveScale = 0x08,
|
||||
MoreComponents = 0x20,
|
||||
HaveXAndYScale = 0x40,
|
||||
HaveTwoByTwo = 0x80,
|
||||
HaveInstructions = 0x100,
|
||||
UseMyMetrics = 0x200,
|
||||
OverlapCompund = 0x400,
|
||||
ScaledOffset = 0x800,
|
||||
UnscaledOffset = 0x1000
|
||||
};
|
||||
};
|
||||
struct FontNames
|
||||
{
|
||||
uint16 format,
|
||||
count,
|
||||
string_offset;
|
||||
NameRecord name_record[1];
|
||||
};
|
||||
|
||||
|
||||
struct HorizontalMetric
|
||||
{
|
||||
uint16 advance_width;
|
||||
int16 left_side_bearing;
|
||||
};
|
||||
|
||||
|
||||
struct Glyph
|
||||
{
|
||||
int16 number_of_contours;
|
||||
fword x_min,
|
||||
y_min,
|
||||
x_max,
|
||||
y_max;
|
||||
};
|
||||
|
||||
struct SimpleGlyph : Glyph
|
||||
{
|
||||
uint16 end_pts_of_contours[1];
|
||||
enum
|
||||
{
|
||||
OnCurve = 0x01,
|
||||
XShort = 0x02,
|
||||
YShort = 0x04,
|
||||
Repeat = 0x08,
|
||||
XIsSame = 0x10,
|
||||
XIsPos = 0x10,
|
||||
YIsSame = 0x20,
|
||||
YIsPos = 0x20
|
||||
};
|
||||
};
|
||||
|
||||
struct CompoundGlyph : Glyph
|
||||
{
|
||||
uint16 flags,
|
||||
glyph_index;
|
||||
enum
|
||||
{
|
||||
Arg1Arg2Words = 0x01,
|
||||
ArgsAreXYValues = 0x02,
|
||||
RoundXYToGrid = 0x04,
|
||||
HaveScale = 0x08,
|
||||
MoreComponents = 0x20,
|
||||
HaveXAndYScale = 0x40,
|
||||
HaveTwoByTwo = 0x80,
|
||||
HaveInstructions = 0x100,
|
||||
UseMyMetrics = 0x200,
|
||||
OverlapCompund = 0x400,
|
||||
ScaledOffset = 0x800,
|
||||
UnscaledOffset = 0x1000
|
||||
};
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
} // end of namespace Sfnt
|
||||
|
@ -51,155 +51,155 @@ typedef unsigned short gid16;
|
||||
// Enumeration used to specify a table in a TTF file
|
||||
class Tag
|
||||
{
|
||||
unsigned long _v;
|
||||
unsigned long _v;
|
||||
public:
|
||||
Tag(const char n[5]) throw() : _v(TTF_TAG(n[0],n[1],n[2],n[3])) {}
|
||||
Tag(const unsigned long tag) throw() : _v(tag) {}
|
||||
Tag(const char n[5]) throw() : _v(TTF_TAG(n[0],n[1],n[2],n[3])) {}
|
||||
Tag(const unsigned long tag) throw() : _v(tag) {}
|
||||
|
||||
operator unsigned long () const throw () { return _v; }
|
||||
operator unsigned long () const throw () { return _v; }
|
||||
|
||||
enum
|
||||
{
|
||||
Feat = TTF_TAG('F','e','a','t'),
|
||||
Glat = TTF_TAG('G','l','a','t'),
|
||||
Gloc = TTF_TAG('G','l','o','c'),
|
||||
Sile = TTF_TAG('S','i','l','e'),
|
||||
Silf = TTF_TAG('S','i','l','f'),
|
||||
Sill = TTF_TAG('S','i','l','l'),
|
||||
cmap = TTF_TAG('c','m','a','p'),
|
||||
cvt = TTF_TAG('c','v','t',' '),
|
||||
cryp = TTF_TAG('c','r','y','p'),
|
||||
head = TTF_TAG('h','e','a','d'),
|
||||
fpgm = TTF_TAG('f','p','g','m'),
|
||||
gdir = TTF_TAG('g','d','i','r'),
|
||||
glyf = TTF_TAG('g','l','y','f'),
|
||||
hdmx = TTF_TAG('h','d','m','x'),
|
||||
hhea = TTF_TAG('h','h','e','a'),
|
||||
hmtx = TTF_TAG('h','m','t','x'),
|
||||
loca = TTF_TAG('l','o','c','a'),
|
||||
kern = TTF_TAG('k','e','r','n'),
|
||||
LTSH = TTF_TAG('L','T','S','H'),
|
||||
maxp = TTF_TAG('m','a','x','p'),
|
||||
name = TTF_TAG('n','a','m','e'),
|
||||
OS_2 = TTF_TAG('O','S','/','2'),
|
||||
post = TTF_TAG('p','o','s','t'),
|
||||
prep = TTF_TAG('p','r','e','p')
|
||||
};
|
||||
enum
|
||||
{
|
||||
Feat = TTF_TAG('F','e','a','t'),
|
||||
Glat = TTF_TAG('G','l','a','t'),
|
||||
Gloc = TTF_TAG('G','l','o','c'),
|
||||
Sile = TTF_TAG('S','i','l','e'),
|
||||
Silf = TTF_TAG('S','i','l','f'),
|
||||
Sill = TTF_TAG('S','i','l','l'),
|
||||
cmap = TTF_TAG('c','m','a','p'),
|
||||
cvt = TTF_TAG('c','v','t',' '),
|
||||
cryp = TTF_TAG('c','r','y','p'),
|
||||
head = TTF_TAG('h','e','a','d'),
|
||||
fpgm = TTF_TAG('f','p','g','m'),
|
||||
gdir = TTF_TAG('g','d','i','r'),
|
||||
glyf = TTF_TAG('g','l','y','f'),
|
||||
hdmx = TTF_TAG('h','d','m','x'),
|
||||
hhea = TTF_TAG('h','h','e','a'),
|
||||
hmtx = TTF_TAG('h','m','t','x'),
|
||||
loca = TTF_TAG('l','o','c','a'),
|
||||
kern = TTF_TAG('k','e','r','n'),
|
||||
LTSH = TTF_TAG('L','T','S','H'),
|
||||
maxp = TTF_TAG('m','a','x','p'),
|
||||
name = TTF_TAG('n','a','m','e'),
|
||||
OS_2 = TTF_TAG('O','S','/','2'),
|
||||
post = TTF_TAG('p','o','s','t'),
|
||||
prep = TTF_TAG('p','r','e','p')
|
||||
};
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------------------------
|
||||
Class providing utility methods to parse a TrueType font file (TTF).
|
||||
Callling application handles all file input and memory allocation.
|
||||
Assumes minimal knowledge of TTF file format.
|
||||
Class providing utility methods to parse a TrueType font file (TTF).
|
||||
Callling application handles all file input and memory allocation.
|
||||
Assumes minimal knowledge of TTF file format.
|
||||
----------------------------------------------------------------------------------------------*/
|
||||
////////////////////////////////// tools to find & check TTF tables
|
||||
bool GetHeaderInfo(size_t & lOffset, size_t & lSize);
|
||||
bool CheckHeader(const void * pHdr);
|
||||
bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize);
|
||||
bool GetTableInfo(const Tag TableTag, const void * pHdr, const void * pTableDir,
|
||||
size_t & lOffset, size_t & lSize);
|
||||
bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize);
|
||||
////////////////////////////////// tools to find & check TTF tables
|
||||
bool GetHeaderInfo(size_t & lOffset, size_t & lSize);
|
||||
bool CheckHeader(const void * pHdr);
|
||||
bool GetTableDirInfo(const void * pHdr, size_t & lOffset, size_t & lSize);
|
||||
bool GetTableInfo(const Tag TableTag, const void * pHdr, const void * pTableDir,
|
||||
size_t & lOffset, size_t & lSize);
|
||||
bool CheckTable(const Tag TableId, const void * pTable, size_t lTableSize);
|
||||
|
||||
////////////////////////////////// simple font wide info
|
||||
size_t GlyphCount(const void * pMaxp);
|
||||
////////////////////////////////// simple font wide info
|
||||
size_t GlyphCount(const void * pMaxp);
|
||||
#ifdef ALL_TTFUTILS
|
||||
size_t MaxCompositeComponentCount(const void * pMaxp);
|
||||
size_t MaxCompositeLevelCount(const void * pMaxp);
|
||||
size_t LocaGlyphCount(size_t lLocaSize, const void * pHead); // throw (std::domain_error);
|
||||
size_t MaxCompositeComponentCount(const void * pMaxp);
|
||||
size_t MaxCompositeLevelCount(const void * pMaxp);
|
||||
size_t LocaGlyphCount(size_t lLocaSize, const void * pHead); // throw (std::domain_error);
|
||||
#endif
|
||||
int DesignUnits(const void * pHead);
|
||||
int DesignUnits(const void * pHead);
|
||||
#ifdef ALL_TTFUTILS
|
||||
int HeadTableCheckSum(const void * pHead);
|
||||
void HeadTableCreateTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
|
||||
void HeadTableModifyTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
|
||||
bool IsItalic(const void * pHead);
|
||||
int FontAscent(const void * pOs2);
|
||||
int FontDescent(const void * pOs2);
|
||||
bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic);
|
||||
bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp,
|
||||
const char * pPostName);
|
||||
int HeadTableCheckSum(const void * pHead);
|
||||
void HeadTableCreateTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
|
||||
void HeadTableModifyTime(const void * pHead, unsigned int * pnDateBC, unsigned int * pnDateAD);
|
||||
bool IsItalic(const void * pHead);
|
||||
int FontAscent(const void * pOs2);
|
||||
int FontDescent(const void * pOs2);
|
||||
bool FontOs2Style(const void *pOs2, bool & fBold, bool & fItalic);
|
||||
bool Get31EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
bool Get31EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
bool Get30EngFamilyInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
bool Get30EngFullFontInfo(const void * pName, size_t & lOffset, size_t & lSize);
|
||||
int PostLookup(const void * pPost, size_t lPostSize, const void * pMaxp,
|
||||
const char * pPostName);
|
||||
#endif
|
||||
|
||||
////////////////////////////////// utility methods helpful for name table
|
||||
bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
|
||||
int nLangId, int nNameId, size_t & lOffset, size_t & lSize);
|
||||
//size_t NameTableLength(const byte * pTable);
|
||||
////////////////////////////////// utility methods helpful for name table
|
||||
bool GetNameInfo(const void * pName, int nPlatformId, int nEncodingId,
|
||||
int nLangId, int nNameId, size_t & lOffset, size_t & lSize);
|
||||
//size_t NameTableLength(const byte * pTable);
|
||||
#ifdef ALL_TTFUTILS
|
||||
int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
|
||||
int *nameIdList, int cNameIds, short *langIdList);
|
||||
void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
|
||||
int GetLangsForNames(const void * pName, int nPlatformId, int nEncodingId,
|
||||
int *nameIdList, int cNameIds, short *langIdList);
|
||||
void SwapWString(void * pWStr, size_t nSize = 0); // throw (std::invalid_argument);
|
||||
#endif
|
||||
|
||||
////////////////////////////////// cmap lookup tools
|
||||
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
|
||||
int nEncodingId = 1, size_t length = 0);
|
||||
bool CheckCmapSubtable4(const void * pCmap31);
|
||||
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);
|
||||
gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
|
||||
unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
|
||||
int * pRangeKey = 0);
|
||||
////////////////////////////////// cmap lookup tools
|
||||
const void * FindCmapSubtable(const void * pCmap, int nPlatformId = 3,
|
||||
int nEncodingId = 1, size_t length = 0);
|
||||
bool CheckCmapSubtable4(const void * pCmap31);
|
||||
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);
|
||||
gid16 CmapSubtable12Lookup(const void * pCmap310, unsigned int uUnicodeId, int rangeKey = 0);
|
||||
unsigned int CmapSubtable12NextCodepoint(const void *pCmap310, unsigned int nUnicodeId,
|
||||
int * pRangeKey = 0);
|
||||
|
||||
///////////////////////////////// horizontal metric data for a glyph
|
||||
bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize,
|
||||
const void * pHhea, int & nLsb, unsigned int & nAdvWid);
|
||||
///////////////////////////////// horizontal metric data for a glyph
|
||||
bool HorMetrics(gid16 nGlyphId, const void * pHmtx, size_t lHmtxSize,
|
||||
const void * pHhea, int & nLsb, unsigned int & nAdvWid);
|
||||
|
||||
////////////////////////////////// primitives for loca and glyf lookup
|
||||
size_t LocaLookup(gid16 nGlyphId, const void * pLoca, size_t lLocaSize,
|
||||
const void * pHead); // throw (std::out_of_range);
|
||||
void * GlyfLookup(const void * pGlyf, size_t lGlyfOffset, size_t lTableLen);
|
||||
////////////////////////////////// primitives for loca and glyf lookup
|
||||
size_t LocaLookup(gid16 nGlyphId, const void * pLoca, size_t lLocaSize,
|
||||
const void * pHead); // throw (std::out_of_range);
|
||||
void * GlyfLookup(const void * pGlyf, size_t lGlyfOffset, size_t lTableLen);
|
||||
|
||||
////////////////////////////////// primitves for simple glyph data
|
||||
bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin,
|
||||
int & xMax, int & yMax);
|
||||
////////////////////////////////// primitves for simple glyph data
|
||||
bool GlyfBox(const void * pSimpleGlyf, int & xMin, int & yMin,
|
||||
int & xMax, int & yMax);
|
||||
|
||||
#ifdef ALL_TTFUTILS
|
||||
int GlyfContourCount(const void * pSimpleGlyf);
|
||||
bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint,
|
||||
int cnPointsTotal, size_t & cnPoints);
|
||||
bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY,
|
||||
char * prgbFlag, int cnPointsTotal, int & cnPoints);
|
||||
|
||||
// primitive to find the glyph ids in a composite glyph
|
||||
bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId,
|
||||
size_t cnCompIdTotal, size_t & cnCompId);
|
||||
// primitive to find the placement data for a component in a composite glyph
|
||||
bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
|
||||
bool fOffset, int & a, int & b);
|
||||
// primitive to find the transform data for a component in a composite glyph
|
||||
bool GetComponentTransform(const void * pSimpleGlyf, int nCompId,
|
||||
float & flt11, float & flt12, float & flt21, float & flt22, bool & fTransOffset);
|
||||
int GlyfContourCount(const void * pSimpleGlyf);
|
||||
bool GlyfContourEndPoints(const void * pSimpleGlyf, int * prgnContourEndPoint,
|
||||
int cnPointsTotal, size_t & cnPoints);
|
||||
bool GlyfPoints(const void * pSimpleGlyf, int * prgnX, int * prgnY,
|
||||
char * prgbFlag, int cnPointsTotal, int & cnPoints);
|
||||
|
||||
// primitive to find the glyph ids in a composite glyph
|
||||
bool GetComponentGlyphIds(const void * pSimpleGlyf, int * prgnCompId,
|
||||
size_t cnCompIdTotal, size_t & cnCompId);
|
||||
// primitive to find the placement data for a component in a composite glyph
|
||||
bool GetComponentPlacement(const void * pSimpleGlyf, int nCompId,
|
||||
bool fOffset, int & a, int & b);
|
||||
// primitive to find the transform data for a component in a composite glyph
|
||||
bool GetComponentTransform(const void * pSimpleGlyf, int nCompId,
|
||||
float & flt11, float & flt12, float & flt21, float & flt22, bool & fTransOffset);
|
||||
#endif
|
||||
|
||||
////////////////////////////////// operate on composite or simple glyph (auto glyf lookup)
|
||||
void * GlyfLookup(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead); // primitive used by below methods
|
||||
////////////////////////////////// operate on composite or simple glyph (auto glyf lookup)
|
||||
void * GlyfLookup(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead); // primitive used by below methods
|
||||
|
||||
#ifdef ALL_TTFUTILS
|
||||
// below are primary user methods for handling glyf data
|
||||
bool IsSpace(gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead);
|
||||
bool IsDeepComposite(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead);
|
||||
// below are primary user methods for handling glyf data
|
||||
bool IsSpace(gid16 nGlyphId, const void * pLoca, size_t lLocaSize, const void * pHead);
|
||||
bool IsDeepComposite(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead);
|
||||
|
||||
bool GlyfBox(gid16 nGlyphId, const void * pGlyf, const void * pLoca, size_t lGlyfSize, size_t lLocaSize,
|
||||
const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax);
|
||||
bool GlyfContourCount(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void *pHead, size_t & cnContours);
|
||||
bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead, int * prgnContourEndPoint, size_t cnPoints);
|
||||
bool GlyfPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead, const int * prgnContourEndPoint, size_t cnEndPoints,
|
||||
int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints);
|
||||
bool GlyfBox(gid16 nGlyphId, const void * pGlyf, const void * pLoca, size_t lGlyfSize, size_t lLocaSize,
|
||||
const void * pHead, int & xMin, int & yMin, int & xMax, int & yMax);
|
||||
bool GlyfContourCount(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void *pHead, size_t & cnContours);
|
||||
bool GlyfContourEndPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead, int * prgnContourEndPoint, size_t cnPoints);
|
||||
bool GlyfPoints(gid16 nGlyphId, const void * pGlyf, const void * pLoca,
|
||||
size_t lGlyfSize, size_t lLocaSize, const void * pHead, const int * prgnContourEndPoint, size_t cnEndPoints,
|
||||
int * prgnX, int * prgnY, bool * prgfOnCurve, size_t cnPoints);
|
||||
|
||||
// utitily method used by high-level GlyfPoints
|
||||
bool SimplifyFlags(char * prgbFlags, int cnPoints);
|
||||
bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints);
|
||||
// utitily method used by high-level GlyfPoints
|
||||
bool SimplifyFlags(char * prgbFlags, int cnPoints);
|
||||
bool CalcAbsolutePoints(int * prgnX, int * prgnY, int cnPoints);
|
||||
#endif
|
||||
|
||||
} // end of namespace TtfUtil
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -31,15 +31,15 @@ of the License or (at your option) any later version.
|
||||
|
||||
namespace graphite2 {
|
||||
|
||||
typedef uint32 uchar_t;
|
||||
typedef uint32 uchar_t;
|
||||
|
||||
template <int N>
|
||||
struct _utf_codec
|
||||
{
|
||||
typedef uchar_t codeunit_t;
|
||||
typedef uchar_t codeunit_t;
|
||||
|
||||
static void put(codeunit_t * cp, const uchar_t , int8 & len) throw();
|
||||
static uchar_t get(const codeunit_t * cp, int8 & len) throw();
|
||||
static void put(codeunit_t * cp, const uchar_t , int8 & len) throw();
|
||||
static uchar_t get(const codeunit_t * cp, int8 & len) throw();
|
||||
};
|
||||
|
||||
|
||||
@ -47,22 +47,22 @@ template <>
|
||||
struct _utf_codec<32>
|
||||
{
|
||||
private:
|
||||
static const uchar_t limit = 0x110000;
|
||||
static const uchar_t limit = 0x110000;
|
||||
public:
|
||||
typedef uint32 codeunit_t;
|
||||
typedef uint32 codeunit_t;
|
||||
|
||||
inline
|
||||
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
|
||||
{
|
||||
*cp = usv; l = 1;
|
||||
}
|
||||
inline
|
||||
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
|
||||
{
|
||||
*cp = usv; l = 1;
|
||||
}
|
||||
|
||||
inline
|
||||
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
||||
{
|
||||
if (cp[0] < limit) { l = 1; return cp[0]; }
|
||||
else { l = -1; return 0xFFFD; }
|
||||
}
|
||||
inline
|
||||
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
||||
{
|
||||
if (cp[0] < limit) { l = 1; return cp[0]; }
|
||||
else { l = -1; return 0xFFFD; }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -70,35 +70,35 @@ template <>
|
||||
struct _utf_codec<16>
|
||||
{
|
||||
private:
|
||||
static const int32 lead_offset = 0xD800 - (0x10000 >> 10);
|
||||
static const int32 surrogate_offset = 0x10000 - (0xD800 << 10) - 0xDC00;
|
||||
static const int32 lead_offset = 0xD800 - (0x10000 >> 10);
|
||||
static const int32 surrogate_offset = 0x10000 - (0xD800 << 10) - 0xDC00;
|
||||
public:
|
||||
typedef uint16 codeunit_t;
|
||||
typedef uint16 codeunit_t;
|
||||
|
||||
inline
|
||||
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
|
||||
{
|
||||
if (usv < 0x10000) { l = 1; cp[0] = codeunit_t(usv); }
|
||||
else
|
||||
{
|
||||
cp[0] = codeunit_t(lead_offset + (usv >> 10));
|
||||
cp[1] = codeunit_t(0xDC00 + (usv & 0x3FF));
|
||||
l = 2;
|
||||
}
|
||||
}
|
||||
inline
|
||||
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
|
||||
{
|
||||
if (usv < 0x10000) { l = 1; cp[0] = codeunit_t(usv); }
|
||||
else
|
||||
{
|
||||
cp[0] = codeunit_t(lead_offset + (usv >> 10));
|
||||
cp[1] = codeunit_t(0xDC00 + (usv & 0x3FF));
|
||||
l = 2;
|
||||
}
|
||||
}
|
||||
|
||||
inline
|
||||
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
||||
{
|
||||
const uint32 uh = cp[0];
|
||||
l = 1;
|
||||
inline
|
||||
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
||||
{
|
||||
const uint32 uh = cp[0];
|
||||
l = 1;
|
||||
|
||||
if (0xD800 > uh || uh > 0xDFFF) { return uh; }
|
||||
const uint32 ul = cp[1];
|
||||
if (uh > 0xDBFF || 0xDC00 > ul || ul > 0xDFFF) { l = -1; return 0xFFFD; }
|
||||
++l;
|
||||
return (uh<<10) + ul + surrogate_offset;
|
||||
}
|
||||
if (0xD800 > uh || uh > 0xDFFF) { return uh; }
|
||||
const uint32 ul = cp[1];
|
||||
if (uh > 0xDBFF || 0xDC00 > ul || ul > 0xDFFF) { l = -1; return 0xFFFD; }
|
||||
++l;
|
||||
return (uh<<10) + ul + surrogate_offset;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -106,102 +106,102 @@ template <>
|
||||
struct _utf_codec<8>
|
||||
{
|
||||
private:
|
||||
static const int8 sz_lut[16];
|
||||
static const byte mask_lut[5];
|
||||
static const int8 sz_lut[16];
|
||||
static const byte mask_lut[5];
|
||||
|
||||
|
||||
public:
|
||||
typedef uint8 codeunit_t;
|
||||
typedef uint8 codeunit_t;
|
||||
|
||||
inline
|
||||
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
|
||||
{
|
||||
if (usv < 0x80) {l = 1; cp[0] = usv; return; }
|
||||
if (usv < 0x0800) {l = 2; cp[0] = 0xC0 + (usv >> 6); cp[1] = 0x80 + (usv & 0x3F); return; }
|
||||
if (usv < 0x10000) {l = 3; cp[0] = 0xE0 + (usv >> 12); cp[1] = 0x80 + ((usv >> 6) & 0x3F); cp[2] = 0x80 + (usv & 0x3F); return; }
|
||||
else {l = 4; cp[0] = 0xF0 + (usv >> 18); cp[1] = 0x80 + ((usv >> 12) & 0x3F); cp[2] = 0x80 + ((usv >> 6) & 0x3F); cp[3] = 0x80 + (usv & 0x3F); return; }
|
||||
}
|
||||
inline
|
||||
static void put(codeunit_t * cp, const uchar_t usv, int8 & l) throw()
|
||||
{
|
||||
if (usv < 0x80) {l = 1; cp[0] = usv; return; }
|
||||
if (usv < 0x0800) {l = 2; cp[0] = 0xC0 + (usv >> 6); cp[1] = 0x80 + (usv & 0x3F); return; }
|
||||
if (usv < 0x10000) {l = 3; cp[0] = 0xE0 + (usv >> 12); cp[1] = 0x80 + ((usv >> 6) & 0x3F); cp[2] = 0x80 + (usv & 0x3F); return; }
|
||||
else {l = 4; cp[0] = 0xF0 + (usv >> 18); cp[1] = 0x80 + ((usv >> 12) & 0x3F); cp[2] = 0x80 + ((usv >> 6) & 0x3F); cp[3] = 0x80 + (usv & 0x3F); return; }
|
||||
}
|
||||
|
||||
inline
|
||||
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
||||
{
|
||||
const int8 seq_sz = sz_lut[*cp >> 4];
|
||||
uchar_t u = *cp & mask_lut[seq_sz];
|
||||
l = 1;
|
||||
bool toolong = false;
|
||||
inline
|
||||
static uchar_t get(const codeunit_t * cp, int8 & l) throw()
|
||||
{
|
||||
const int8 seq_sz = sz_lut[*cp >> 4];
|
||||
uchar_t u = *cp & mask_lut[seq_sz];
|
||||
l = 1;
|
||||
bool toolong = false;
|
||||
|
||||
switch(seq_sz) {
|
||||
case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10); // no break
|
||||
case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); // no break
|
||||
case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); // no break
|
||||
case 1: break;
|
||||
case 0: l = -1; return 0xFFFD;
|
||||
}
|
||||
switch(seq_sz) {
|
||||
case 4: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong = (u < 0x10); // no break
|
||||
case 3: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x20); // no break
|
||||
case 2: u <<= 6; u |= *++cp & 0x3F; if (*cp >> 6 != 2) break; ++l; toolong |= (u < 0x80); // no break
|
||||
case 1: break;
|
||||
case 0: l = -1; return 0xFFFD;
|
||||
}
|
||||
|
||||
if (l != seq_sz || toolong)
|
||||
{
|
||||
l = -l;
|
||||
return 0xFFFD;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
if (l != seq_sz || toolong)
|
||||
{
|
||||
l = -l;
|
||||
return 0xFFFD;
|
||||
}
|
||||
return u;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename C>
|
||||
class _utf_iterator
|
||||
{
|
||||
typedef _utf_codec<sizeof(C)*8> codec;
|
||||
typedef _utf_codec<sizeof(C)*8> codec;
|
||||
|
||||
C * cp;
|
||||
mutable int8 sl;
|
||||
C * cp;
|
||||
mutable int8 sl;
|
||||
|
||||
public:
|
||||
typedef C codeunit_type;
|
||||
typedef uchar_t value_type;
|
||||
typedef uchar_t * pointer;
|
||||
typedef C codeunit_type;
|
||||
typedef uchar_t value_type;
|
||||
typedef uchar_t * pointer;
|
||||
|
||||
class reference
|
||||
{
|
||||
const _utf_iterator & _i;
|
||||
class reference
|
||||
{
|
||||
const _utf_iterator & _i;
|
||||
|
||||
reference(const _utf_iterator & i): _i(i) {}
|
||||
public:
|
||||
operator value_type () const throw () { return codec::get(_i.cp, _i.sl); }
|
||||
reference & operator = (const value_type usv) throw() { codec::put(_i.cp, usv, _i.sl); return *this; }
|
||||
reference(const _utf_iterator & i): _i(i) {}
|
||||
public:
|
||||
operator value_type () const throw () { return codec::get(_i.cp, _i.sl); }
|
||||
reference & operator = (const value_type usv) throw() { codec::put(_i.cp, usv, _i.sl); return *this; }
|
||||
|
||||
friend class _utf_iterator;
|
||||
};
|
||||
friend class _utf_iterator;
|
||||
};
|
||||
|
||||
|
||||
_utf_iterator(const void * us=0) : cp(reinterpret_cast<C *>(const_cast<void *>(us))), sl(1) { }
|
||||
_utf_iterator(const void * us=0) : cp(reinterpret_cast<C *>(const_cast<void *>(us))), sl(1) { }
|
||||
|
||||
_utf_iterator & operator ++ () { cp += abs(sl); return *this; }
|
||||
_utf_iterator operator ++ (int) { _utf_iterator tmp(*this); operator++(); return tmp; }
|
||||
_utf_iterator & operator ++ () { cp += abs(sl); return *this; }
|
||||
_utf_iterator operator ++ (int) { _utf_iterator tmp(*this); operator++(); return tmp; }
|
||||
|
||||
bool operator == (const _utf_iterator & rhs) const throw() { return cp >= rhs.cp; }
|
||||
bool operator != (const _utf_iterator & rhs) const throw() { return !operator==(rhs); }
|
||||
bool operator == (const _utf_iterator & rhs) const throw() { return cp >= rhs.cp; }
|
||||
bool operator != (const _utf_iterator & rhs) const throw() { return !operator==(rhs); }
|
||||
|
||||
reference operator * () const throw() { return *this; }
|
||||
pointer operator ->() const throw() { return &operator *(); }
|
||||
reference operator * () const throw() { return *this; }
|
||||
pointer operator ->() const throw() { return &operator *(); }
|
||||
|
||||
operator codeunit_type * () const throw() { return cp; }
|
||||
operator codeunit_type * () const throw() { return cp; }
|
||||
|
||||
bool error() const throw() { return sl < 1; }
|
||||
bool error() const throw() { return sl < 1; }
|
||||
};
|
||||
|
||||
template <typename C>
|
||||
struct utf
|
||||
{
|
||||
typedef typename _utf_codec<sizeof(C)*8>::codeunit_t codeunit_t;
|
||||
typedef typename _utf_codec<sizeof(C)*8>::codeunit_t codeunit_t;
|
||||
|
||||
typedef _utf_iterator<C> iterator;
|
||||
typedef _utf_iterator<const C> const_iterator;
|
||||
typedef _utf_iterator<C> iterator;
|
||||
typedef _utf_iterator<const C> const_iterator;
|
||||
};
|
||||
|
||||
|
||||
typedef utf<uint32> utf32;
|
||||
typedef utf<uint16> utf16;
|
||||
typedef utf<uint8> utf8;
|
||||
typedef utf<uint32> utf32;
|
||||
typedef utf<uint16> utf16;
|
||||
typedef utf<uint8> utf8;
|
||||
|
||||
} // namespace graphite2
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2012, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -32,40 +32,40 @@ namespace graphite2
|
||||
template<typename T>
|
||||
inline unsigned int bit_set_count(T v)
|
||||
{
|
||||
v = v - ((v >> 1) & T(~T(0)/3)); // temp
|
||||
v = (v & T(~T(0)/15*3)) + ((v >> 2) & T(~T(0)/15*3)); // temp
|
||||
v = (v + (v >> 4)) & T(~T(0)/255*15); // temp
|
||||
return (T)(v * T(~T(0)/255)) >> (sizeof(T)-1)*8; // count
|
||||
v = v - ((v >> 1) & T(~T(0)/3)); // temp
|
||||
v = (v & T(~T(0)/15*3)) + ((v >> 2) & T(~T(0)/15*3)); // temp
|
||||
v = (v + (v >> 4)) & T(~T(0)/255*15); // temp
|
||||
return (T)(v * T(~T(0)/255)) >> (sizeof(T)-1)*8; // count
|
||||
}
|
||||
|
||||
|
||||
template<int S>
|
||||
inline unsigned long _mask_over_val(unsigned long v)
|
||||
{
|
||||
v = _mask_over_val<S/2>(v);
|
||||
v |= v >> S*4;
|
||||
return v;
|
||||
v = _mask_over_val<S/2>(v);
|
||||
v |= v >> S*4;
|
||||
return v;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline unsigned long _mask_over_val<1>(unsigned long v)
|
||||
{
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
return v;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
return v;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T mask_over_val(T v)
|
||||
{
|
||||
return _mask_over_val<sizeof(T)>(v);
|
||||
return _mask_over_val<sizeof(T)>(v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline unsigned long next_highest_power2(T v)
|
||||
{
|
||||
return _mask_over_val<sizeof(T)>(v-1)+1;
|
||||
return _mask_over_val<sizeof(T)>(v-1)+1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@ -77,14 +77,14 @@ inline unsigned int log_binary(T v)
|
||||
template<typename T>
|
||||
inline T has_zero(const T x)
|
||||
{
|
||||
return (x - T(~T(0)/255)) & ~x & T(~T(0)/255*128);
|
||||
return (x - T(~T(0)/255)) & ~x & T(~T(0)/255*128);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T zero_bytes(const T x, unsigned char n)
|
||||
{
|
||||
const T t = T(~T(0)/255*n);
|
||||
return T((has_zero(x^t) >> 7)*n);
|
||||
const T t = T(~T(0)/255*n);
|
||||
return T((has_zero(x^t) >> 7)*n);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -24,7 +24,7 @@ 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.
|
||||
*/
|
||||
// debug.h
|
||||
// debug.h
|
||||
//
|
||||
// Created on: 22 Dec 2011
|
||||
// Author: tim
|
||||
@ -44,12 +44,12 @@ class CharInfo;
|
||||
class Segment;
|
||||
class Slot;
|
||||
|
||||
typedef std::pair<const Segment * const, const Slot * const> dslot;
|
||||
typedef std::pair<const Segment * const, const Slot * const> dslot;
|
||||
struct objectid
|
||||
{
|
||||
char name[16];
|
||||
objectid(const dslot &) throw();
|
||||
objectid(const Segment * const p) throw();
|
||||
char name[16];
|
||||
objectid(const dslot &) throw();
|
||||
objectid(const Segment * const p) throw();
|
||||
};
|
||||
|
||||
|
||||
@ -64,14 +64,14 @@ json & operator << (json & j, const telemetry &) throw();
|
||||
inline
|
||||
json & operator << (json & j, const Position & p) throw()
|
||||
{
|
||||
return j << json::flat << json::array << p.x << p.y << json::close;
|
||||
return j << json::flat << json::array << p.x << p.y << json::close;
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
json & operator << (json & j, const objectid & sid) throw()
|
||||
{
|
||||
return j << sid.name;
|
||||
return j << sid.name;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -41,53 +41,53 @@ class json
|
||||
json(const json &);
|
||||
json & operator = (const json &);
|
||||
|
||||
typedef void (*_context_t)(json &);
|
||||
class _null_t {};
|
||||
typedef void (*_context_t)(json &);
|
||||
class _null_t {};
|
||||
|
||||
FILE * const _stream;
|
||||
char _contexts[128], // context stack
|
||||
* _context, // current context (top of stack)
|
||||
* _flatten; // if !0 points to context above which
|
||||
// pretty printed output should occur.
|
||||
FILE * const _stream;
|
||||
char _contexts[128], // context stack
|
||||
* _context, // current context (top of stack)
|
||||
* _flatten; // if !0 points to context above which
|
||||
// pretty printed output should occur.
|
||||
|
||||
void context(const char current) throw();
|
||||
void indent(const int d=0) throw();
|
||||
void push_context(const char, const char) throw();
|
||||
void pop_context() throw();
|
||||
void context(const char current) throw();
|
||||
void indent(const int d=0) throw();
|
||||
void push_context(const char, const char) throw();
|
||||
void pop_context() throw();
|
||||
|
||||
public:
|
||||
class closer;
|
||||
class closer;
|
||||
|
||||
typedef const char * string;
|
||||
typedef double number;
|
||||
typedef long signed int integer;
|
||||
typedef bool boolean;
|
||||
static const _null_t null;
|
||||
typedef const char * string;
|
||||
typedef double number;
|
||||
typedef long signed int integer;
|
||||
typedef bool boolean;
|
||||
static const _null_t null;
|
||||
|
||||
static void flat(json &) throw();
|
||||
static void close(json &) throw();
|
||||
static void object(json &) throw();
|
||||
static void array(json &) throw();
|
||||
static void item(json &) throw();
|
||||
static void flat(json &) throw();
|
||||
static void close(json &) throw();
|
||||
static void object(json &) throw();
|
||||
static void array(json &) throw();
|
||||
static void item(json &) throw();
|
||||
|
||||
json(FILE * stream) throw();
|
||||
~json() throw ();
|
||||
json(FILE * stream) throw();
|
||||
~json() throw ();
|
||||
|
||||
FILE * stream() const throw();
|
||||
FILE * stream() const throw();
|
||||
|
||||
json & operator << (string) throw();
|
||||
json & operator << (number) throw();
|
||||
json & operator << (integer) throw();
|
||||
json & operator << (long unsigned int d) throw();
|
||||
json & operator << (boolean) throw();
|
||||
json & operator << (_null_t) throw();
|
||||
json & operator << (_context_t) throw();
|
||||
json & operator << (string) throw();
|
||||
json & operator << (number) throw();
|
||||
json & operator << (integer) throw();
|
||||
json & operator << (long unsigned int d) throw();
|
||||
json & operator << (boolean) throw();
|
||||
json & operator << (_null_t) throw();
|
||||
json & operator << (_context_t) throw();
|
||||
|
||||
operator bool() const throw();
|
||||
bool good() const throw();
|
||||
bool eof() const throw();
|
||||
operator bool() const throw();
|
||||
bool good() const throw();
|
||||
bool eof() const throw();
|
||||
|
||||
CLASS_NEW_DELETE;
|
||||
CLASS_NEW_DELETE;
|
||||
};
|
||||
|
||||
class json::closer
|
||||
@ -96,70 +96,70 @@ class json::closer
|
||||
closer(const closer &);
|
||||
closer & operator = (const closer &);
|
||||
|
||||
json * const _j;
|
||||
json * const _j;
|
||||
public:
|
||||
closer(json * const j) : _j(j) {}
|
||||
~closer() throw() { if (_j) *_j << close; }
|
||||
closer(json * const j) : _j(j) {}
|
||||
~closer() throw() { if (_j) *_j << close; }
|
||||
};
|
||||
|
||||
inline
|
||||
json::json(FILE * s) throw()
|
||||
: _stream(s), _context(_contexts), _flatten(0)
|
||||
{
|
||||
if (good())
|
||||
fflush(s);
|
||||
if (good())
|
||||
fflush(s);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
json::~json() throw ()
|
||||
{
|
||||
while (_context > _contexts) pop_context();
|
||||
while (_context > _contexts) pop_context();
|
||||
}
|
||||
|
||||
inline
|
||||
FILE * json::stream() const throw() { return _stream; }
|
||||
FILE * json::stream() const throw() { return _stream; }
|
||||
|
||||
|
||||
inline
|
||||
json & json::operator << (json::_context_t ctxt) throw()
|
||||
{
|
||||
ctxt(*this);
|
||||
return *this;
|
||||
ctxt(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline
|
||||
json & operator << (json & j, signed char d) throw() { return j << json::integer(d); }
|
||||
json & operator << (json & j, signed char d) throw() { return j << json::integer(d); }
|
||||
|
||||
inline
|
||||
json & operator << (json & j, short signed int d) throw() { return j << json::integer(d); }
|
||||
json & operator << (json & j, short signed int d) throw() { return j << json::integer(d); }
|
||||
|
||||
inline
|
||||
json & operator << (json & j, signed int d) throw() { return j << json::integer(d); }
|
||||
json & operator << (json & j, signed int d) throw() { return j << json::integer(d); }
|
||||
|
||||
inline
|
||||
json & operator << (json & j, unsigned char d) throw() { return j << json::integer(d); }
|
||||
json & operator << (json & j, unsigned char d) throw() { return j << json::integer(d); }
|
||||
|
||||
inline
|
||||
json & operator << (json & j, short unsigned int d) throw() { return j << json::integer(d); }
|
||||
|
||||
inline
|
||||
json & operator << (json & j, unsigned int d) throw() { return j << json::integer(d); }
|
||||
json & operator << (json & j, unsigned int d) throw() { return j << json::integer(d); }
|
||||
|
||||
inline
|
||||
json & operator << (json & j, char c) throw ()
|
||||
{
|
||||
const char str[2] = {c,0};
|
||||
return j << str;
|
||||
const char str[2] = {c,0};
|
||||
return j << str;
|
||||
}
|
||||
|
||||
inline
|
||||
json::operator bool() const throw() { return good(); }
|
||||
json::operator bool() const throw() { return good(); }
|
||||
|
||||
inline
|
||||
bool json::good() const throw() { return _stream && ferror(_stream) == 0; }
|
||||
bool json::good() const throw() { return _stream && ferror(_stream) == 0; }
|
||||
|
||||
inline
|
||||
bool json::eof() const throw() { return feof(_stream) != 0; }
|
||||
bool json::eof() const throw() { return feof(_stream) != 0; }
|
||||
|
||||
} // namespace graphite2
|
||||
|
@ -273,6 +273,11 @@ public:
|
||||
while (old[len]) len++;
|
||||
len += 2;
|
||||
mLangLookup[a][b] = gralloc<const IsoLangEntry *>(len);
|
||||
if (!mLangLookup[a][b])
|
||||
{
|
||||
mLangLookup[a][b] = old;
|
||||
continue;
|
||||
}
|
||||
mLangLookup[a][b][--len] = NULL;
|
||||
mLangLookup[a][b][--len] = &LANG_ENTRIES[i];
|
||||
while (--len >= 0)
|
||||
@ -285,6 +290,7 @@ public:
|
||||
else
|
||||
{
|
||||
mLangLookup[a][b] = gralloc<const IsoLangEntry *>(2);
|
||||
if (!mLangLookup[a][b]) continue;
|
||||
mLangLookup[a][b][1] = NULL;
|
||||
mLangLookup[a][b][0] = &LANG_ENTRIES[i];
|
||||
}
|
||||
@ -295,8 +301,8 @@ public:
|
||||
~Locale2Lang()
|
||||
{
|
||||
for (int i = 0; i != 26; ++i)
|
||||
for (int j = 0; j != 26; ++j)
|
||||
free(mLangLookup[i][j]);
|
||||
for (int j = 0; j != 26; ++j)
|
||||
free(mLangLookup[i][j]);
|
||||
}
|
||||
unsigned short getMsId(const char * locale) const
|
||||
{
|
||||
@ -393,7 +399,7 @@ public:
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(mLangLookup[a][b][i]->maCountry, region) == 0)
|
||||
if (region && (strncmp(mLangLookup[a][b][i]->maCountry, region, regionLength) == 0))
|
||||
{
|
||||
langId = mLangLookup[a][b][i]->mnLang;
|
||||
break;
|
||||
|
@ -199,9 +199,9 @@ STARTOP(next)
|
||||
if (map - &smap[0] >= int(smap.size())) DIE
|
||||
if (is)
|
||||
{
|
||||
if (is == smap.highwater())
|
||||
smap.highpassed(true);
|
||||
is = is->next();
|
||||
if (is == smap.highwater())
|
||||
smap.highpassed(true);
|
||||
is = is->next();
|
||||
}
|
||||
++map;
|
||||
ENDOP
|
||||
@ -263,6 +263,7 @@ ENDOP
|
||||
|
||||
STARTOP(insert)
|
||||
Slot *newSlot = seg.newSlot();
|
||||
if (!newSlot) DIE;
|
||||
Slot *iss = is;
|
||||
while (iss && iss->isDeleted()) iss = iss->next();
|
||||
if (!iss)
|
||||
@ -284,7 +285,7 @@ STARTOP(insert)
|
||||
{
|
||||
iss->prev()->next(newSlot);
|
||||
newSlot->prev(iss->prev());
|
||||
newSlot->before(iss->prev()->after());
|
||||
newSlot->before(iss->prev()->after());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -297,12 +298,12 @@ STARTOP(insert)
|
||||
{
|
||||
iss->prev(newSlot);
|
||||
newSlot->originate(iss->original());
|
||||
newSlot->after(iss->before());
|
||||
newSlot->after(iss->before());
|
||||
}
|
||||
else if (newSlot->prev())
|
||||
{
|
||||
newSlot->originate(newSlot->prev()->original());
|
||||
newSlot->after(newSlot->prev()->after());
|
||||
newSlot->after(newSlot->prev()->after());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -328,7 +329,7 @@ STARTOP(delete_)
|
||||
seg.last(is->prev());
|
||||
|
||||
if (is == smap.highwater())
|
||||
smap.highwater(is->next());
|
||||
smap.highwater(is->next());
|
||||
if (is->prev())
|
||||
is = is->prev();
|
||||
seg.extendLength(-1);
|
||||
@ -373,14 +374,14 @@ ENDOP
|
||||
|
||||
STARTOP(attr_set)
|
||||
declare_params(1);
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const int val = int(pop());
|
||||
is->setAttr(&seg, slat, 0, val, smap);
|
||||
ENDOP
|
||||
|
||||
STARTOP(attr_add)
|
||||
declare_params(1);
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const int val = int(pop());
|
||||
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
||||
{
|
||||
@ -393,7 +394,7 @@ ENDOP
|
||||
|
||||
STARTOP(attr_sub)
|
||||
declare_params(1);
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const int val = int(pop());
|
||||
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
||||
{
|
||||
@ -406,7 +407,7 @@ ENDOP
|
||||
|
||||
STARTOP(attr_set_slot)
|
||||
declare_params(1);
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const attrCode slat = attrCode(uint8(*param));
|
||||
const int offset = (map - smap.begin())*int(slat == gr_slatAttTo);
|
||||
const int val = int(pop()) + offset;
|
||||
is->setAttr(&seg, slat, offset, val, smap);
|
||||
@ -414,7 +415,7 @@ ENDOP
|
||||
|
||||
STARTOP(iattr_set_slot)
|
||||
declare_params(2);
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const size_t idx = uint8(param[1]);
|
||||
const int val = int(pop()) + (map - smap.begin())*int(slat == gr_slatAttTo);
|
||||
is->setAttr(&seg, slat, idx, val, smap);
|
||||
@ -422,7 +423,7 @@ ENDOP
|
||||
|
||||
STARTOP(push_slot_attr)
|
||||
declare_params(2);
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const int slot_ref = int8(param[1]);
|
||||
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
||||
{
|
||||
@ -497,7 +498,7 @@ ENDOP
|
||||
|
||||
STARTOP(push_islot_attr)
|
||||
declare_params(3);
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const int slot_ref = int8(param[1]),
|
||||
idx = uint8(param[2]);
|
||||
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
||||
@ -534,7 +535,7 @@ ENDOP
|
||||
|
||||
STARTOP(iattr_set)
|
||||
declare_params(2);
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const size_t idx = uint8(param[1]);
|
||||
const int val = int(pop());
|
||||
is->setAttr(&seg, slat, idx, val, smap);
|
||||
@ -542,7 +543,7 @@ ENDOP
|
||||
|
||||
STARTOP(iattr_add)
|
||||
declare_params(2);
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const size_t idx = uint8(param[1]);
|
||||
const int val = int(pop());
|
||||
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
||||
@ -556,7 +557,7 @@ ENDOP
|
||||
|
||||
STARTOP(iattr_sub)
|
||||
declare_params(2);
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const attrCode slat = attrCode(uint8(param[0]));
|
||||
const size_t idx = uint8(param[1]);
|
||||
const int val = int(pop());
|
||||
if ((slat == gr_slatPosX || slat == gr_slatPosY) && (flags & POSITIONED) == 0)
|
||||
@ -635,6 +636,7 @@ ENDOP
|
||||
|
||||
STARTOP(temp_copy)
|
||||
slotref newSlot = seg.newSlot();
|
||||
if (!newSlot) DIE;
|
||||
int16 *tempUserAttrs = newSlot->userAttrs();
|
||||
memcpy(newSlot, is, sizeof(Slot));
|
||||
memcpy(tempUserAttrs, is->userAttrs(), seg.numAttrs() * sizeof(uint16));
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* GRAPHITE2 LICENSING
|
||||
|
||||
Copyright 2010, SIL International
|
||||
Copyright 2011, SIL International
|
||||
All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
@ -36,91 +36,91 @@ using namespace graphite2;
|
||||
|
||||
namespace
|
||||
{
|
||||
enum
|
||||
{
|
||||
seq = ',',
|
||||
obj='}', member=':', empty_obj='{',
|
||||
arr=']', empty_arr='['
|
||||
};
|
||||
enum
|
||||
{
|
||||
seq = ',',
|
||||
obj='}', member=':', empty_obj='{',
|
||||
arr=']', empty_arr='['
|
||||
};
|
||||
}
|
||||
|
||||
const json::_null_t json::null = {};
|
||||
const json::_null_t json::null = {};
|
||||
|
||||
inline
|
||||
void json::context(const char current) throw()
|
||||
{
|
||||
fprintf(_stream, "%c", *_context);
|
||||
indent();
|
||||
*_context = current;
|
||||
fprintf(_stream, "%c", *_context);
|
||||
indent();
|
||||
*_context = current;
|
||||
}
|
||||
|
||||
|
||||
void json::indent(const int d) throw()
|
||||
{
|
||||
if (*_context == member || (_flatten && _flatten < _context))
|
||||
fputc(' ', _stream);
|
||||
else
|
||||
fprintf(_stream, "\n%*s", 4*int(_context - _contexts + d), "");
|
||||
if (*_context == member || (_flatten && _flatten < _context))
|
||||
fputc(' ', _stream);
|
||||
else
|
||||
fprintf(_stream, "\n%*s", 4*int(_context - _contexts + d), "");
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
void json::push_context(const char prefix, const char suffix) throw()
|
||||
{
|
||||
assert(_context - _contexts < ptrdiff_t(sizeof _contexts));
|
||||
assert(_context - _contexts < ptrdiff_t(sizeof _contexts));
|
||||
|
||||
if (_context == _contexts)
|
||||
*_context = suffix;
|
||||
else
|
||||
context(suffix);
|
||||
*++_context = prefix;
|
||||
if (_context == _contexts)
|
||||
*_context = suffix;
|
||||
else
|
||||
context(suffix);
|
||||
*++_context = prefix;
|
||||
}
|
||||
|
||||
|
||||
void json::pop_context() throw()
|
||||
{
|
||||
assert(_context > _contexts);
|
||||
assert(_context > _contexts);
|
||||
|
||||
if (*_context == seq) indent(-1);
|
||||
else fputc(*_context, _stream);
|
||||
if (*_context == seq) indent(-1);
|
||||
else fputc(*_context, _stream);
|
||||
|
||||
fputc(*--_context, _stream);
|
||||
if (_context == _contexts) fputc('\n', _stream);
|
||||
fflush(_stream);
|
||||
fputc(*--_context, _stream);
|
||||
if (_context == _contexts) fputc('\n', _stream);
|
||||
fflush(_stream);
|
||||
|
||||
if (_flatten >= _context) _flatten = 0;
|
||||
*_context = seq;
|
||||
if (_flatten >= _context) _flatten = 0;
|
||||
*_context = seq;
|
||||
}
|
||||
|
||||
|
||||
// These four functions cannot be inlined as pointers to these
|
||||
// functions are needed for operator << (_context_t) to work.
|
||||
void json::flat(json & j) throw() { if (!j._flatten) j._flatten = j._context; }
|
||||
void json::close(json & j) throw() { j.pop_context(); }
|
||||
void json::object(json & j) throw() { j.push_context('{', '}'); }
|
||||
void json::array(json & j) throw() { j.push_context('[', ']'); }
|
||||
void json::flat(json & j) throw() { if (!j._flatten) j._flatten = j._context; }
|
||||
void json::close(json & j) throw() { j.pop_context(); }
|
||||
void json::object(json & j) throw() { j.push_context('{', '}'); }
|
||||
void json::array(json & j) throw() { j.push_context('[', ']'); }
|
||||
void json::item(json & j) throw()
|
||||
{
|
||||
while (j._context > j._contexts+1 && j._context[-1] != arr)
|
||||
j.pop_context();
|
||||
while (j._context > j._contexts+1 && j._context[-1] != arr)
|
||||
j.pop_context();
|
||||
}
|
||||
|
||||
|
||||
json & json::operator << (json::string s) throw()
|
||||
{
|
||||
const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq;
|
||||
context(ctxt);
|
||||
fprintf(_stream, "\"%s\"", s);
|
||||
if (ctxt == member) fputc(' ', _stream);
|
||||
const char ctxt = _context[-1] == obj ? *_context == member ? seq : member : seq;
|
||||
context(ctxt);
|
||||
fprintf(_stream, "\"%s\"", s);
|
||||
if (ctxt == member) fputc(' ', _stream);
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; }
|
||||
json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
|
||||
json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
|
||||
json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
|
||||
json & json::operator << (json::_null_t) throw() { context(seq); fputs("null",_stream); return *this; }
|
||||
json & json::operator << (json::number f) throw() { context(seq); fprintf(_stream, "%g", f); return *this; }
|
||||
json & json::operator << (json::integer d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
|
||||
json & json::operator << (long unsigned d) throw() { context(seq); fprintf(_stream, "%ld", d); return *this; }
|
||||
json & json::operator << (json::boolean b) throw() { context(seq); fputs(b ? "true" : "false", _stream); return *this; }
|
||||
json & json::operator << (json::_null_t) throw() { context(seq); fputs("null",_stream); return *this; }
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -4324,7 +4324,7 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then
|
||||
CC="$HOST_CC" CXX="$HOST_CXX" LD="$HOST_LD" \
|
||||
CFLAGS="$HOST_ICU_CFLAGS $HOST_OPTIMIZE_FLAGS" \
|
||||
CPPFLAGS="$ICU_CPPFLAGS" \
|
||||
CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMZIE_FLAGS" \
|
||||
CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMIZE_FLAGS" \
|
||||
LDFLAGS="$HOST_LDFLAGS" \
|
||||
$SHELL $abs_srcdir/../../intl/icu/source/runConfigureICU \
|
||||
$HOST_ICU_BUILD_OPTS \
|
||||
@ -4364,11 +4364,16 @@ if test -n "$ENABLE_INTL_API" -a -z "$MOZ_NATIVE_ICU"; then
|
||||
if test -n "$MOZ_DEBUG" -o "MOZ_DEBUG_SYMBOLS"; then
|
||||
ICU_CFLAGS="$ICU_CFLAGS $MOZ_DEBUG_FLAGS"
|
||||
ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_DEBUG_FLAGS"
|
||||
if test -n "$CROSS_COMPILE" -a "$OS_TARGET" = "Darwin"; then
|
||||
# Bug 951758: Cross-OSX builds have issues with -g because it
|
||||
# tries to run dsymutil
|
||||
ICU_CFLAGS=`echo $ICU_CFLAGS | sed 's|-g||g'`
|
||||
ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-g||g'`
|
||||
if test -n "$CROSS_COMPILE" -a "$OS_TARGET" = "Darwin" \
|
||||
-a "$HOST_OS_ARCH" != "Darwin"
|
||||
then
|
||||
# Bug 951758: Cross-OSX builds with non-Darwin hosts have issues
|
||||
# with -g and friends (like -gdwarf and -gfull) because they try
|
||||
# to run dsymutil
|
||||
changequote(,)
|
||||
ICU_CFLAGS=`echo $ICU_CFLAGS | sed 's|-g[^ \t]*||g'`
|
||||
ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-g[^ \t]*||g'`
|
||||
changequote([,])
|
||||
fi
|
||||
|
||||
ICU_LDFLAGS="$MOZ_DEBUG_LDFLAGS"
|
||||
|
@ -306,7 +306,7 @@ class AsmJSModule
|
||||
const uint8_t *deserialize(ExclusiveContext *cx, const uint8_t *cursor);
|
||||
};
|
||||
|
||||
#if defined(MOZ_VTUNE) or defined(JS_ION_PERF)
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
// Function information to add to the VTune JIT profiler following linking.
|
||||
struct ProfiledFunction
|
||||
{
|
||||
@ -360,7 +360,7 @@ class AsmJSModule
|
||||
typedef Vector<Exit, 0, SystemAllocPolicy> ExitVector;
|
||||
typedef Vector<jit::AsmJSHeapAccess, 0, SystemAllocPolicy> HeapAccessVector;
|
||||
typedef Vector<jit::IonScriptCounts *, 0, SystemAllocPolicy> FunctionCountsVector;
|
||||
#if defined(MOZ_VTUNE) or defined(JS_ION_PERF)
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
typedef Vector<ProfiledFunction, 0, SystemAllocPolicy> ProfiledFunctionVector;
|
||||
#endif
|
||||
#if defined(JS_ION_PERF)
|
||||
@ -376,7 +376,7 @@ class AsmJSModule
|
||||
ExitVector exits_;
|
||||
ExportedFunctionVector exports_;
|
||||
HeapAccessVector heapAccesses_;
|
||||
#if defined(MOZ_VTUNE) or defined(JS_ION_PERF)
|
||||
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
|
||||
ProfiledFunctionVector profiledFunctions_;
|
||||
#endif
|
||||
#if defined(JS_ION_PERF)
|
||||
|
@ -688,7 +688,7 @@ HandleException(ResumeFromException *rfe)
|
||||
void
|
||||
HandleParallelFailure(ResumeFromException *rfe)
|
||||
{
|
||||
ForkJoinSlice *slice = ForkJoinSlice::Current();
|
||||
ForkJoinSlice *slice = ForkJoinSlice::current();
|
||||
IonFrameIterator iter(slice->perThreadData->ionTop, ParallelExecution);
|
||||
|
||||
parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry");
|
||||
|