Merge m-c to b2g-inbound

This commit is contained in:
Wes Kocher 2014-01-08 18:16:31 -08:00
commit eca807f202
122 changed files with 4720 additions and 3352 deletions

View File

@ -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]

View File

@ -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");

View File

@ -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]

View File

@ -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)

View File

@ -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;
}
}

View File

@ -573,7 +573,7 @@ this.WinTaskbarJumpList =
}
break;
case "back":
case "active":
this._updateTimer();
break;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -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;
}

View File

@ -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);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -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
=========================

View File

@ -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
};

View File

@ -6,3 +6,4 @@ interface WorkerNavigator {
};
WorkerNavigator implements NavigatorID;
WorkerNavigator implements NavigatorOnLine;

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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)
{

View File

@ -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

View File

@ -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]

View File

@ -9,7 +9,8 @@ var supportedProps = [
"platform",
"product",
"taintEnabled",
"userAgent"
"userAgent",
"onLine"
];
for (var prop in navigator) {

View 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' });
});

View 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' });

View 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();
}
}
}

View 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>

View File

@ -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.

View File

@ -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.
*/

View File

@ -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.

View File

@ -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;
}

View File

@ -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.*")

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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};

View File

@ -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; \
}

View File

@ -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 \

View File

@ -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);
}

View File

@ -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*/)

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View 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);
}
}

View File

@ -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.
};

View File

@ -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;

View File

@ -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

View File

@ -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<>

View 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
};
}

View File

@ -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

View File

@ -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&);
};

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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)));

View File

@ -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&);
};

View File

@ -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;
};

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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));

View File

@ -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

View File

@ -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"

View File

@ -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)

View File

@ -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");

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