1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

SheenBidi: Add sources

This commit is contained in:
reuk 2024-09-05 16:30:35 +01:00
parent a3a4813107
commit d77d5801d9
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
85 changed files with 15845 additions and 0 deletions

View file

@ -0,0 +1,110 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include "SBBase.h"
#include "BidiChain.h"
SB_INTERNAL void BidiChainInitialize(BidiChainRef chain,
SBBidiType *types, SBLevel *levels, BidiLink *links)
{
chain->types = types;
chain->levels = levels;
chain->links = links;
chain->roller = 0;
chain->last = 0;
/* Make first link empty. */
chain->types[0] = SBBidiTypeNil;
chain->levels[0] = SBLevelInvalid;
chain->links[0] = BidiLinkNone;
}
SB_INTERNAL void BidiChainAdd(BidiChainRef chain, SBBidiType type, SBUInteger length)
{
BidiLink last = chain->last;
BidiLink current = last + (SBUInt32)length;
chain->types[current] = type;
chain->links[current] = chain->roller;
chain->links[last] = current;
chain->last = current;
}
SB_INTERNAL SBBoolean BidiChainIsSingle(BidiChainRef chain, BidiLink link)
{
BidiLink next = chain->links[link];
/* Check the type of in between code units. */
while (++link != next) {
if (chain->types[link] != SBBidiTypeBN) {
return SBFalse;
}
}
return SBTrue;
}
SB_INTERNAL SBBidiType BidiChainGetType(BidiChainRef chain, BidiLink link)
{
return chain->types[link];
}
SB_INTERNAL void BidiChainSetType(BidiChainRef chain, BidiLink link, SBBidiType type)
{
chain->types[link] = type;
}
SB_INTERNAL SBLevel BidiChainGetLevel(BidiChainRef chain, BidiLink link)
{
return chain->levels[link];
}
SB_INTERNAL void BidiChainSetLevel(BidiChainRef chain, BidiLink link, SBLevel level)
{
chain->levels[link] = level;
}
SB_INTERNAL BidiLink BidiChainGetNext(BidiChainRef chain, BidiLink link)
{
return chain->links[link];
}
SB_INTERNAL void BidiChainSetNext(BidiChainRef chain, BidiLink link, BidiLink next)
{
chain->links[link] = next;
}
SB_INTERNAL void BidiChainAbandonNext(BidiChainRef chain, BidiLink link)
{
BidiLink next = chain->links[link];
BidiLink limit = chain->links[next];
chain->links[link] = limit;
}
SB_INTERNAL SBBoolean BidiChainMergeIfEqual(BidiChainRef chain, BidiLink first, BidiLink second)
{
if (chain->types[first] == chain->types[second]
&& chain->levels[first] == chain->levels[second]) {
chain->links[first] = chain->links[second];
return SBTrue;
}
return SBFalse;
}

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_BIDI_CHAIN_H
#define _SB_INTERNAL_BIDI_CHAIN_H
#include <SBConfig.h>
#include "SBBase.h"
typedef SBUInt32 BidiLink;
#define BidiLinkNone (SBUInt32)(-1)
typedef struct _BidiChain {
SBBidiType *types;
SBLevel *levels;
BidiLink *links;
BidiLink roller;
BidiLink last;
} BidiChain, *BidiChainRef;
SB_INTERNAL void BidiChainInitialize(BidiChainRef chain,
SBBidiType *types, SBLevel *levels, BidiLink *links);
SB_INTERNAL void BidiChainAdd(BidiChainRef chain, SBBidiType type, SBUInteger length);
#define BidiChainGetOffset(chain, link) \
( \
(link) - 1 \
)
SB_INTERNAL SBBoolean BidiChainIsSingle(BidiChainRef chain, BidiLink link);
SB_INTERNAL SBBidiType BidiChainGetType(BidiChainRef chain, BidiLink link);
SB_INTERNAL void BidiChainSetType(BidiChainRef chain, BidiLink link, SBBidiType type);
SB_INTERNAL SBLevel BidiChainGetLevel(BidiChainRef chain, BidiLink link);
SB_INTERNAL void BidiChainSetLevel(BidiChainRef chain, BidiLink link, SBLevel level);
SB_INTERNAL BidiLink BidiChainGetNext(BidiChainRef chain, BidiLink link);
SB_INTERNAL void BidiChainSetNext(BidiChainRef chain, BidiLink link, BidiLink next);
SB_INTERNAL void BidiChainAbandonNext(BidiChainRef chain, BidiLink link);
SB_INTERNAL SBBoolean BidiChainMergeIfEqual(BidiChainRef chain, BidiLink first, BidiLink second);
#define BidiChainForEach(chain, roller, link) \
for (link = chain->links[roller]; link != roller; link = chain->links[link])
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
/*
* Automatically generated by SheenBidiGenerator tool.
* DO NOT EDIT!!
*/
#ifndef _SB_INTERNAL_BIDI_TYPE_LOOKUP_H
#define _SB_INTERNAL_BIDI_TYPE_LOOKUP_H
#include <SBBidiType.h>
#include <SBConfig.h>
#include "SBBase.h"
SB_INTERNAL SBBidiType LookupBidiType(SBCodepoint codepoint);
#endif

View file

@ -0,0 +1,242 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "BidiChain.h"
#include "SBAssert.h"
#include "SBBase.h"
#include "BracketQueue.h"
static SBBoolean BracketQueueInsertElement(BracketQueueRef queue)
{
if (queue->_rearTop != BracketQueueList_MaxIndex) {
queue->_rearTop += 1;
} else {
BracketQueueListRef previousList = queue->_rearList;
BracketQueueListRef rearList = previousList->next;
if (!rearList) {
rearList = malloc(sizeof(BracketQueueList));
if (!rearList) {
return SBFalse;
}
rearList->previous = previousList;
rearList->next = NULL;
previousList->next = rearList;
}
queue->_rearList = rearList;
queue->_rearTop = 0;
}
queue->count += 1;
return SBTrue;
}
static void BracketQueueFinalizePairs(BracketQueueRef queue, BracketQueueListRef list, SBInteger top)
{
do {
SBInteger limit = (list == queue->_rearList ? queue->_rearTop : BracketQueueList_MaxIndex);
while (++top <= limit) {
if (list->openingLink[top] != BidiLinkNone
&& list->closingLink[top] == BidiLinkNone) {
list->openingLink[top] = BidiLinkNone;
}
}
list = list->next;
top = 0;
} while (list);
}
SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue)
{
queue->_firstList.previous = NULL;
queue->_firstList.next = NULL;
queue->_frontList = NULL;
queue->_rearList = NULL;
queue->count = 0;
queue->shouldDequeue = SBFalse;
}
SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction)
{
queue->_frontList = &queue->_firstList;
queue->_rearList = &queue->_firstList;
queue->_frontTop = 0;
queue->_rearTop = -1;
queue->count = 0;
queue->shouldDequeue = SBFalse;
queue->_direction = direction;
}
SB_INTERNAL SBBoolean BracketQueueEnqueue(BracketQueueRef queue,
BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket)
{
/* The queue can only take a maximum of 63 elements. */
SBAssert(queue->count < BracketQueueGetMaxCapacity());
if (BracketQueueInsertElement(queue)) {
BracketQueueListRef list = queue->_rearList;
SBInteger top = queue->_rearTop;
list->priorStrongLink[top] = priorStrongLink;
list->openingLink[top] = openingLink;
list->closingLink[top] = BidiLinkNone;
list->bracket[top] = bracket;
list->strongType[top] = SBBidiTypeNil;
return SBTrue;
}
return SBFalse;
}
SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue)
{
/* The queue must NOT be empty. */
SBAssert(queue->count != 0);
if (queue->_frontTop != BracketQueueList_MaxIndex) {
queue->_frontTop += 1;
} else {
BracketQueueListRef frontList = queue->_frontList;
if (frontList == queue->_rearList) {
queue->_rearTop = -1;
} else {
queue->_frontList = frontList->next;
}
queue->_frontTop = 0;
}
queue->count -= 1;
}
SB_INTERNAL void BracketQueueSetStrongType(BracketQueueRef queue, SBBidiType strongType)
{
BracketQueueListRef list = queue->_rearList;
SBInteger top = queue->_rearTop;
while (1) {
SBInteger limit = (list == queue->_frontList ? queue->_frontTop : 0);
do {
if (list->closingLink[top] == BidiLinkNone
&& list->strongType[top] != queue->_direction) {
list->strongType[top] = strongType;
}
} while (top-- > limit);
if (list == queue->_frontList) {
break;
}
list = list->previous;
top = BracketQueueList_MaxIndex;
}
}
SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue, BidiLink closingLink, SBCodepoint bracket)
{
BracketQueueListRef list = queue->_rearList;
SBInteger top = queue->_rearTop;
SBCodepoint canonical;
switch (bracket) {
case 0x232A:
canonical = 0x3009;
break;
case 0x3009:
canonical = 0x232A;
break;
default:
canonical = bracket;
break;
}
while (1) {
SBBoolean isFrontList = (list == queue->_frontList);
SBInteger limit = (isFrontList ? queue->_frontTop : 0);
do {
if (list->openingLink[top] != BidiLinkNone
&& list->closingLink[top] == BidiLinkNone
&& (list->bracket[top] == bracket || list->bracket[top] == canonical)) {
list->closingLink[top] = closingLink;
BracketQueueFinalizePairs(queue, list, top);
if (isFrontList && top == queue->_frontTop) {
queue->shouldDequeue = SBTrue;
}
return;
}
} while (top-- > limit);
if (isFrontList) {
break;
}
list = list->previous;
top = BracketQueueList_MaxIndex;
}
}
SB_INTERNAL SBBoolean BracketQueueShouldDequeue(BracketQueueRef queue)
{
return queue->shouldDequeue;
}
SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue)
{
return queue->_frontList->priorStrongLink[queue->_frontTop];
}
SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue)
{
return queue->_frontList->openingLink[queue->_frontTop];
}
SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue)
{
return queue->_frontList->closingLink[queue->_frontTop];
}
SB_INTERNAL SBBidiType BracketQueueGetStrongType(BracketQueueRef queue)
{
return queue->_frontList->strongType[queue->_frontTop];
}
SB_INTERNAL void BracketQueueFinalize(BracketQueueRef queue)
{
BracketQueueListRef list = queue->_firstList.next;
while (list) {
BracketQueueListRef next = list->next;
free(list);
list = next;
}
}

View file

@ -0,0 +1,72 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_BRACKET_QUEUE_H
#define _SB_INTERNAL_BRACKET_QUEUE_H
#include <SBConfig.h>
#include "BidiChain.h"
#include "SBBase.h"
#define BracketQueueList_Length 8
#define BracketQueueList_MaxIndex (BracketQueueList_Length - 1)
typedef struct _BracketQueueList {
SBCodepoint bracket[BracketQueueList_Length];
BidiLink priorStrongLink[BracketQueueList_Length];
BidiLink openingLink[BracketQueueList_Length];
BidiLink closingLink[BracketQueueList_Length];
SBBidiType strongType[BracketQueueList_Length];
struct _BracketQueueList *previous;
struct _BracketQueueList *next;
} BracketQueueList, *BracketQueueListRef;
typedef struct _BracketQueue {
BracketQueueList _firstList;
BracketQueueListRef _frontList;
BracketQueueListRef _rearList;
SBInteger _frontTop;
SBInteger _rearTop;
SBUInteger count;
SBBoolean shouldDequeue;
SBBidiType _direction;
} BracketQueue, *BracketQueueRef;
#define BracketQueueGetMaxCapacity() 63
SB_INTERNAL void BracketQueueInitialize(BracketQueueRef queue);
SB_INTERNAL void BracketQueueReset(BracketQueueRef queue, SBBidiType direction);
SB_INTERNAL SBBoolean BracketQueueEnqueue(BracketQueueRef queue,
BidiLink priorStrongLink, BidiLink openingLink, SBCodepoint bracket);
SB_INTERNAL void BracketQueueDequeue(BracketQueueRef queue);
SB_INTERNAL void BracketQueueSetStrongType(BracketQueueRef queue, SBBidiType strongType);
SB_INTERNAL void BracketQueueClosePair(BracketQueueRef queue,
BidiLink closingLink, SBCodepoint bracket);
SB_INTERNAL SBBoolean BracketQueueShouldDequeue(BracketQueueRef queue);
SB_INTERNAL BidiLink BracketQueueGetPriorStrongLink(BracketQueueRef queue);
SB_INTERNAL BidiLink BracketQueueGetOpeningLink(BracketQueueRef queue);
SB_INTERNAL BidiLink BracketQueueGetClosingLink(BracketQueueRef queue);
SB_INTERNAL SBBidiType BracketQueueGetStrongType(BracketQueueRef queue);
SB_INTERNAL void BracketQueueFinalize(BracketQueueRef queue);
#endif

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_BRACKET_TYPE_H
#define _SB_INTERNAL_BRACKET_TYPE_H
#include "SBBase.h"
enum {
BracketTypeNone = 0x00,
BracketTypeOpen = 0x40, /**< Opening paired bracket. */
BracketTypeClose = 0x80, /**< Closing paired bracket. */
BracketTypePrimaryMask = BracketTypeOpen | BracketTypeClose,
BracketTypeInverseMask = ~BracketTypePrimaryMask
};
typedef SBUInt8 BracketType;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
/*
* Automatically generated by SheenBidiGenerator tool.
* DO NOT EDIT!!
*/
#ifndef _SB_INTERNAL_GENERAL_CATEGORY_LOOKUP_H
#define _SB_INTERNAL_GENERAL_CATEGORY_LOOKUP_H
#include <SBConfig.h>
#include <SBGeneralCategory.h>
#include "SBBase.h"
SB_INTERNAL SBGeneralCategory LookupGeneralCategory(SBCodepoint codepoint);
#endif

View file

@ -0,0 +1,537 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include "BidiChain.h"
#include "BracketQueue.h"
#include "BracketType.h"
#include "LevelRun.h"
#include "PairingLookup.h"
#include "SBAssert.h"
#include "SBBase.h"
#include "SBLog.h"
#include "IsolatingRun.h"
static void ResolveAvailableBracketPairs(IsolatingRunRef isolatingRun);
static void AttachLevelRunLinks(IsolatingRunRef isolatingRun)
{
BidiChainRef chain = isolatingRun->bidiChain;
LevelRunRef baseLevelRun = isolatingRun->baseLevelRun;
LevelRunRef current;
LevelRunRef next;
isolatingRun->_originalLink = BidiChainGetNext(chain, chain->roller);
BidiChainSetNext(chain, chain->roller, baseLevelRun->firstLink);
/* Iterate over level runs and attach their links to form an isolating run. */
for (current = baseLevelRun; (next = current->next); current = next) {
BidiChainSetNext(chain, current->lastLink, next->firstLink);
}
BidiChainSetNext(chain, current->lastLink, chain->roller);
isolatingRun->_lastLevelRun = current;
isolatingRun->_sos = RunExtrema_SOR(baseLevelRun->extrema);
if (!RunKindIsPartialIsolate(baseLevelRun->kind)) {
isolatingRun->_eos = RunExtrema_EOR(current->extrema);
} else {
SBLevel paragraphLevel = isolatingRun->paragraphLevel;
SBLevel runLevel = baseLevelRun->level;
SBLevel eosLevel = (runLevel > paragraphLevel ? runLevel : paragraphLevel);
isolatingRun->_eos = ((eosLevel & 1) ? SBBidiTypeR : SBBidiTypeL);
}
}
static void AttachOriginalLinks(IsolatingRunRef isolatingRun)
{
BidiChainRef chain = isolatingRun->bidiChain;
LevelRunRef current;
BidiChainSetNext(chain, chain->roller, isolatingRun->_originalLink);
/* Iterate over level runs and attach original subsequent links. */
for (current = isolatingRun->baseLevelRun; current; current = current->next) {
BidiChainSetNext(chain, current->lastLink, current->subsequentLink);
}
}
static BidiLink ResolveWeakTypes(IsolatingRunRef isolatingRun)
{
BidiChainRef chain = isolatingRun->bidiChain;
BidiLink roller = chain->roller;
BidiLink link;
BidiLink priorLink;
SBBidiType sos;
SBBidiType w1PriorType;
SBBidiType w2StrongType;
SBBidiType w4PriorType;
SBBidiType w5PriorType;
SBBidiType w7StrongType;
priorLink = roller;
sos = isolatingRun->_sos;
w1PriorType = sos;
w2StrongType = sos;
BidiChainForEach(chain, roller, link) {
SBBidiType type = BidiChainGetType(chain, link);
SBBoolean forceMerge = SBFalse;
/* Rule W1 */
if (type == SBBidiTypeNSM) {
/* Change the 'type' variable as well because it can be EN on which W2 depends. */
type = (SBBidiTypeIsIsolate(w1PriorType) ? SBBidiTypeON : w1PriorType);
BidiChainSetType(chain, link, type);
/* Fix for 3rd point of rule N0. */
if (w1PriorType == SBBidiTypeON) {
forceMerge = SBTrue;
}
}
w1PriorType = type;
/* Rule W2 */
if (type == SBBidiTypeEN) {
if (w2StrongType == SBBidiTypeAL) {
BidiChainSetType(chain, link, SBBidiTypeAN);
}
}
/*
* Rule W3
* NOTE: It is safe to apply W3 in 'else-if' statement because it only depends on type AL.
* Even if W2 changes EN to AN, there won't be any harm.
*/
else if (type == SBBidiTypeAL) {
BidiChainSetType(chain, link, SBBidiTypeR);
}
if (SBBidiTypeIsStrong(type)) {
/* Save the strong type as it is checked in W2. */
w2StrongType = type;
}
if ((type != SBBidiTypeON && BidiChainGetType(chain, priorLink) == type) || forceMerge) {
BidiChainAbandonNext(chain, priorLink);
} else {
priorLink = link;
}
}
priorLink = roller;
w4PriorType = sos;
w5PriorType = sos;
w7StrongType = sos;
BidiChainForEach(chain, roller, link) {
SBBidiType type = BidiChainGetType(chain, link);
SBBidiType nextType = BidiChainGetType(chain, BidiChainGetNext(chain, link));
/* Rule W4 */
if (BidiChainIsSingle(chain, link)
&& SBBidiTypeIsNumberSeparator(type)
&& SBBidiTypeIsNumber(w4PriorType)
&& (w4PriorType == nextType)
&& (w4PriorType == SBBidiTypeEN || type == SBBidiTypeCS))
{
/* Change the current type as well because it can be EN on which W5 depends. */
type = w4PriorType;
BidiChainSetType(chain, link, type);
}
w4PriorType = type;
/* Rule W5 */
if (type == SBBidiTypeET && (w5PriorType == SBBidiTypeEN || nextType == SBBidiTypeEN)) {
/* Change the current type as well because it is EN on which W7 depends. */
type = SBBidiTypeEN;
BidiChainSetType(chain, link, type);
}
w5PriorType = type;
switch (type) {
/* Rule W6 */
case SBBidiTypeET:
case SBBidiTypeCS:
case SBBidiTypeES:
BidiChainSetType(chain, link, SBBidiTypeON);
break;
/*
* Rule W7
* NOTE: W7 is expected to be applied after W6. However this is not the case here. The
* reason is that W6 can only create the type ON which is not tested in W7 by any
* means. So it won't affect the algorithm.
*/
case SBBidiTypeEN:
if (w7StrongType == SBBidiTypeL) {
BidiChainSetType(chain, link, SBBidiTypeL);
}
break;
/*
* Save the strong type for W7.
* NOTE: The strong type is expected to be saved after applying W7 because W7 itself creates
* a strong type. However the strong type being saved here is based on the type after
* W5. This won't effect the algorithm because a single link contains all consecutive
* EN types. This means that even if W7 creates a strong type, it will be saved in
* next iteration.
*/
case SBBidiTypeL:
case SBBidiTypeR:
w7StrongType = type;
break;
}
if (type != SBBidiTypeON && BidiChainGetType(chain, priorLink) == type) {
BidiChainAbandonNext(chain, priorLink);
} else {
priorLink = link;
}
}
return priorLink;
}
static SBBoolean ResolveBrackets(IsolatingRunRef isolatingRun)
{
const SBCodepointSequence *sequence = isolatingRun->codepointSequence;
SBUInteger paragraphOffset = isolatingRun->paragraphOffset;
BracketQueueRef queue = &isolatingRun->_bracketQueue;
BidiChainRef chain = isolatingRun->bidiChain;
BidiLink roller = chain->roller;
BidiLink link;
BidiLink priorStrongLink;
SBLevel runLevel;
priorStrongLink = BidiLinkNone;
runLevel = isolatingRun->baseLevelRun->level;
BracketQueueReset(queue, SBLevelAsNormalBidiType(runLevel));
BidiChainForEach(chain, roller, link) {
SBUInteger stringIndex;
SBCodepoint codepoint;
SBBidiType type;
SBCodepoint bracketValue;
BracketType bracketType;
type = BidiChainGetType(chain, link);
switch (type) {
case SBBidiTypeON:
stringIndex = BidiChainGetOffset(chain, link) + paragraphOffset;
codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex);
bracketValue = LookupBracketPair(codepoint, &bracketType);
switch (bracketType) {
case BracketTypeOpen:
if (queue->count < BracketQueueGetMaxCapacity()) {
if (!BracketQueueEnqueue(queue, priorStrongLink, link, bracketValue)) {
return SBFalse;
}
} else {
goto Resolve;
}
break;
case BracketTypeClose:
if (queue->count != 0) {
BracketQueueClosePair(queue, link, codepoint);
if (BracketQueueShouldDequeue(queue)) {
ResolveAvailableBracketPairs(isolatingRun);
}
}
break;
}
break;
case SBBidiTypeEN:
case SBBidiTypeAN:
type = SBBidiTypeR;
case SBBidiTypeR:
case SBBidiTypeL:
if (queue->count != 0) {
BracketQueueSetStrongType(queue, type);
}
priorStrongLink = link;
break;
}
}
Resolve:
ResolveAvailableBracketPairs(isolatingRun);
return SBTrue;
}
static void ResolveAvailableBracketPairs(IsolatingRunRef isolatingRun)
{
BracketQueueRef queue = &isolatingRun->_bracketQueue;
BidiChainRef chain = isolatingRun->bidiChain;
SBLevel runLevel;
SBBidiType embeddingDirection;
SBBidiType oppositeDirection;
runLevel = isolatingRun->baseLevelRun->level;
embeddingDirection = SBLevelAsNormalBidiType(runLevel);
oppositeDirection = SBLevelAsOppositeBidiType(runLevel);
while (queue->count != 0) {
BidiLink openingLink = BracketQueueGetOpeningLink(queue);
BidiLink closingLink = BracketQueueGetClosingLink(queue);
if ((openingLink != BidiLinkNone) && (closingLink != BidiLinkNone)) {
SBBidiType innerStrongType;
SBBidiType pairType;
innerStrongType = BracketQueueGetStrongType(queue);
/* Rule: N0.b */
if (innerStrongType == embeddingDirection) {
pairType = innerStrongType;
}
/* Rule: N0.c */
else if (innerStrongType == oppositeDirection) {
BidiLink priorStrongLink;
SBBidiType priorStrongType;
priorStrongLink = BracketQueueGetPriorStrongLink(queue);
if (priorStrongLink != BidiLinkNone) {
BidiLink link;
priorStrongType = BidiChainGetType(chain, priorStrongLink);
if (SBBidiTypeIsNumber(priorStrongType)) {
priorStrongType = SBBidiTypeR;
}
link = BidiChainGetNext(chain, priorStrongLink);
while (link != openingLink) {
SBBidiType type = BidiChainGetType(chain, link);
if (type == SBBidiTypeL || type == SBBidiTypeR) {
priorStrongType = type;
}
link = BidiChainGetNext(chain, link);
}
} else {
priorStrongType = isolatingRun->_sos;
}
/* Rule: N0.c.1 */
if (priorStrongType == oppositeDirection) {
pairType = oppositeDirection;
}
/* Rule: N0.c.2 */
else {
pairType = embeddingDirection;
}
}
/* Rule: N0.d */
else {
pairType = SBBidiTypeNil;
}
if (pairType != SBBidiTypeNil) {
/* Do the substitution */
BidiChainSetType(chain, openingLink, pairType);
BidiChainSetType(chain, closingLink, pairType);
}
}
BracketQueueDequeue(queue);
}
}
static void ResolveNeutrals(IsolatingRunRef isolatingRun)
{
BidiChainRef chain = isolatingRun->bidiChain;
BidiLink roller = chain->roller;
BidiLink link;
SBLevel runLevel;
SBBidiType strongType;
BidiLink neutralLink;
runLevel = isolatingRun->baseLevelRun->level;
strongType = isolatingRun->_sos;
neutralLink = BidiLinkNone;
BidiChainForEach(chain, roller, link) {
SBBidiType type = BidiChainGetType(chain, link);
SBBidiType nextType;
SBAssert(SBBidiTypeIsStrongOrNumber(type) || SBBidiTypeIsNeutralOrIsolate(type));
switch (type) {
case SBBidiTypeL:
strongType = SBBidiTypeL;
break;
case SBBidiTypeR:
case SBBidiTypeEN:
case SBBidiTypeAN:
strongType = SBBidiTypeR;
break;
case SBBidiTypeB:
case SBBidiTypeS:
case SBBidiTypeWS:
case SBBidiTypeON:
case SBBidiTypeLRI:
case SBBidiTypeRLI:
case SBBidiTypeFSI:
case SBBidiTypePDI:
if (neutralLink == BidiLinkNone) {
neutralLink = link;
}
nextType = BidiChainGetType(chain, BidiChainGetNext(chain, link));
if (SBBidiTypeIsNumber(nextType)) {
nextType = SBBidiTypeR;
} else if (nextType == SBBidiTypeNil) {
nextType = isolatingRun->_eos;
}
if (SBBidiTypeIsStrong(nextType)) {
/* Rules N1, N2 */
SBBidiType resolvedType = (strongType == nextType
? strongType
: SBLevelAsNormalBidiType(runLevel));
do {
BidiChainSetType(chain, neutralLink, resolvedType);
neutralLink = BidiChainGetNext(chain, neutralLink);
} while (neutralLink != BidiChainGetNext(chain, link));
neutralLink = BidiLinkNone;
}
break;
}
}
}
static void ResolveImplicitLevels(IsolatingRunRef isolatingRun)
{
BidiChainRef chain = isolatingRun->bidiChain;
BidiLink roller = chain->roller;
BidiLink link;
SBLevel runLevel = isolatingRun->baseLevelRun->level;
if ((runLevel & 1) == 0) {
BidiChainForEach(chain, roller, link) {
SBBidiType type = BidiChainGetType(chain, link);
SBLevel level = BidiChainGetLevel(chain, link);
SBAssert(SBBidiTypeIsStrongOrNumber(type));
/* Rule I1 */
if (type == SBBidiTypeR) {
BidiChainSetLevel(chain, link, level + 1);
} else if (type != SBBidiTypeL) {
BidiChainSetLevel(chain, link, level + 2);
}
}
} else {
BidiChainForEach(chain, roller, link) {
SBBidiType type = BidiChainGetType(chain, link);
SBLevel level = BidiChainGetLevel(chain, link);
SBAssert(SBBidiTypeIsStrongOrNumber(type));
/* Rule I2 */
if (type != SBBidiTypeR) {
BidiChainSetLevel(chain, link, level + 1);
}
}
}
}
SB_INTERNAL void IsolatingRunInitialize(IsolatingRunRef isolatingRun)
{
BracketQueueInitialize(&isolatingRun->_bracketQueue);
}
SB_INTERNAL SBBoolean IsolatingRunResolve(IsolatingRunRef isolatingRun)
{
BidiLink lastLink;
BidiLink subsequentLink;
SB_LOG_BLOCK_OPENER("Identified Isolating Run");
/* Attach level run links to form isolating run. */
AttachLevelRunLinks(isolatingRun);
/* Save last subsequent link. */
subsequentLink = isolatingRun->_lastLevelRun->subsequentLink;
SB_LOG_STATEMENT("Range", 1, SB_LOG_RUN_RANGE(isolatingRun));
SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun));
SB_LOG_STATEMENT("Level", 1, SB_LOG_LEVEL(isolatingRun->baseLevelRun->level));
SB_LOG_STATEMENT("SOS", 1, SB_LOG_BIDI_TYPE(isolatingRun->_sos));
SB_LOG_STATEMENT("EOS", 1, SB_LOG_BIDI_TYPE(isolatingRun->_eos));
/* Rules W1-W7 */
lastLink = ResolveWeakTypes(isolatingRun);
SB_LOG_BLOCK_OPENER("Resolved Weak Types");
SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun));
SB_LOG_BLOCK_CLOSER();
/* Rule N0 */
if (!ResolveBrackets(isolatingRun)) {
return SBFalse;
}
SB_LOG_BLOCK_OPENER("Resolved Brackets");
SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun));
SB_LOG_BLOCK_CLOSER();
/* Rules N1, N2 */
ResolveNeutrals(isolatingRun);
SB_LOG_BLOCK_OPENER("Resolved Neutrals");
SB_LOG_STATEMENT("Types", 1, SB_LOG_RUN_TYPES(isolatingRun));
SB_LOG_BLOCK_CLOSER();
/* Rules I1, I2 */
ResolveImplicitLevels(isolatingRun);
SB_LOG_BLOCK_OPENER("Resolved Implicit Levels");
SB_LOG_STATEMENT("Levels", 1, SB_LOG_RUN_LEVELS(isolatingRun));
SB_LOG_BLOCK_CLOSER();
/* Re-attach original links. */
AttachOriginalLinks(isolatingRun);
/* Attach new final link (of isolating run) with last subsequent link. */
BidiChainSetNext(isolatingRun->bidiChain, lastLink, subsequentLink);
SB_LOG_BLOCK_CLOSER();
return SBTrue;
}
SB_INTERNAL void IsolatingRunFinalize(IsolatingRunRef isolatingRun)
{
BracketQueueFinalize(&isolatingRun->_bracketQueue);
}

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_ISOLATING_RUN_H
#define _SB_INTERNAL_ISOLATING_RUN_H
#include <SBConfig.h>
#include "BidiChain.h"
#include "BracketQueue.h"
#include "LevelRun.h"
#include "SBBase.h"
#include "SBCodepointSequence.h"
typedef struct _IsolatingRun {
const SBCodepointSequence *codepointSequence;
const SBBidiType *bidiTypes;
BidiChainRef bidiChain;
LevelRunRef baseLevelRun;
LevelRunRef _lastLevelRun;
BracketQueue _bracketQueue;
SBUInteger paragraphOffset;
BidiLink _originalLink;
SBBidiType _sos;
SBBidiType _eos;
SBLevel paragraphLevel;
} IsolatingRun, *IsolatingRunRef;
SB_INTERNAL void IsolatingRunInitialize(IsolatingRunRef isolatingRun);
SB_INTERNAL SBBoolean IsolatingRunResolve(IsolatingRunRef isolatingRun);
SB_INTERNAL void IsolatingRunFinalize(IsolatingRunRef isolatingRun);
#endif

View file

@ -0,0 +1,68 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include "BidiChain.h"
#include "RunExtrema.h"
#include "RunKind.h"
#include "SBAssert.h"
#include "LevelRun.h"
SB_INTERNAL void LevelRunInitialize(LevelRunRef levelRun,
BidiChainRef bidiChain, BidiLink firstLink, BidiLink lastLink,
SBBidiType sor, SBBidiType eor)
{
SBBidiType firstType = BidiChainGetType(bidiChain, firstLink);
SBBidiType lastType = BidiChainGetType(bidiChain, lastLink);
levelRun->next = NULL;
levelRun->firstLink = firstLink;
levelRun->lastLink = lastLink;
levelRun->subsequentLink = BidiChainGetNext(bidiChain, lastLink);
levelRun->extrema = RunExtremaMake(sor, eor);
levelRun->kind = RunKindMake
(
SBBidiTypeIsIsolateInitiator(lastType),
SBBidiTypeIsIsolateTerminator(firstType)
);
levelRun->level = BidiChainGetLevel(bidiChain, firstLink);
}
SB_INTERNAL void LevelRunAttach(LevelRunRef levelRun, LevelRunRef next)
{
/* Only the runs of same level can be attached. */
SBAssert(levelRun->level == next->level);
/* No other run can be attached with a simple run. */
SBAssert(!RunKindIsSimple(levelRun->kind));
/* No other run can be attached with a complete isolating run. */
SBAssert(!RunKindIsCompleteIsolate(levelRun->kind));
/* Only a terminating run can be attached with an isolating run. */
SBAssert(RunKindIsIsolate(levelRun->kind) && RunKindIsTerminating(next->kind));
/* The next run must be unattached. */
SBAssert(!RunKindIsAttachedTerminating(next->kind));
if (RunKindIsTerminating(next->kind)) {
RunKindMakeAttached(next->kind);
}
if (RunKindIsIsolate(levelRun->kind)) {
RunKindMakeComplete(levelRun->kind);
}
levelRun->next = next;
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_LEVEL_RUN_H
#define _SB_INTERNAL_LEVEL_RUN_H
#include <SBConfig.h>
#include "BidiChain.h"
#include "RunExtrema.h"
#include "RunKind.h"
#include "SBBase.h"
typedef struct _LevelRun {
struct _LevelRun *next; /**< Reference to the next sequence of run links. */
BidiLink firstLink; /**< First link of the run. */
BidiLink lastLink; /**< Last link of the run. */
BidiLink subsequentLink; /**< Subsequent link of the run. */
RunExtrema extrema;
RunKind kind;
SBLevel level;
} LevelRun, *LevelRunRef;
SB_INTERNAL void LevelRunInitialize(LevelRunRef levelRun,
BidiChainRef bidiChain, BidiLink firstLink, BidiLink lastLink,
SBBidiType sor, SBBidiType eor);
SB_INTERNAL void LevelRunAttach(LevelRunRef levelRun, LevelRunRef next);
#endif

View file

@ -0,0 +1,267 @@
/*
* Automatically generated by SheenBidiGenerator tool.
* DO NOT EDIT!!
*
* REQUIRED MEMORY: (37)+2310+(617*2) = 3618 Bytes
*/
#include "PairingLookup.h"
static const SBInt16 PairDifferences[37] = {
0, 1, -1, 2, -2, 16, -16, 3, -3, 2016, 2527, 1923, 1914, 1918,
2250, 138, 7, -7, 1824, 2104, 2108, 2106, 1316, -138, 8, -8, -1316,
-1914, -1918, -1923, -1824, -2016, -2104, -2106, -2108, -2250, -2527
};
static const SBUInt8 PairData[2310] = {
/* DATA_BLOCK: -- 0x0000..0x0069 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 132, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x006A..0x00D3 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0,
132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x00D4..0x013D -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x013E..0x01A7 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x01A8..0x0211 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x0212..0x027B -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x027C..0x02E5 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x02E6..0x034F -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 7, 7, 7, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,
0, 0, 0, 0, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0,
0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 1,
2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x0350..0x03B9 -- */
0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0,
0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 19, 0, 20, 21,
0, 21, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 22, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x03BA..0x0423 -- */
0, 1, 2, 1, 2, 23, 0, 0, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
0, 0, 1, 2, 24, 24, 24, 0, 16, 16, 0, 0, 25, 25, 25, 17, 17, 0, 0,
0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x0424..0x048D -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65,
130, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x048E..0x04F7 -- */
0, 0, 0, 1, 2, 65, 130, 0, 1, 2, 0, 3, 0, 4, 0, 0, 0, 0, 0,
0, 0, 1, 2, 0, 0, 0, 0, 0, 26, 1, 2, 0, 0, 0, 1, 2, 1, 2,
65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x04F8..0x0561 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 71,
129, 66, 136, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 27, 0, 0, 0, 0, 28,
0, 0, 29, 1, 2, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0,
0, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 2, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1,
/* DATA_BLOCK: -- 0x0562..0x05CB -- */
2, 0, 1, 2, 0, 0, 65, 130, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0,
1, 2, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0,
0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x05CC..0x0635 -- */
1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0,
/* DATA_BLOCK: -- 0x0636..0x069F -- */
1, 2, 1, 2, 1, 2, 1, 2, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 32,
0, 0, 0, 0, 33, 34, 33, 0, 0, 0, 0, 0, 0, 1, 2, 35, 0, 0, 0,
0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x06A0..0x0709 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x070A..0x0773 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 0,
1, 2, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 2, 0, 0, 1, 2, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 0,
/* DATA_BLOCK: -- 0x0774..0x07DD -- */
65, 130, 65, 130, 65, 130, 65, 130, 65, 130, 0, 0, 65, 130, 65, 130, 65, 130, 65,
130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x07DE..0x0847 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 130, 65, 130, 65, 130, 0, 0, 0,
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x0848..0x08B1 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 65, 130, 0, 0, 0, 0, 0, 0,
/* DATA_BLOCK: -- 0x08B2..0x0905 -- */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 67, 0, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67,
0, 132, 0, 65, 130, 0, 65, 130,
};
static const SBUInt16 PairIndexes[617] = {
0x0000, 0x006A, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x013E, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x01A8, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0212, 0x027C, 0x00D4, 0x00D4, 0x00D4, 0x02E6, 0x0350,
0x03BA, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0424,
0x048E, 0x00D4, 0x00D4, 0x00D4, 0x04F8, 0x0562, 0x05CC, 0x0636, 0x00D4, 0x00D4, 0x06A0, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x070A, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x0774, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4, 0x00D4,
0x00D4, 0x00D4, 0x07DE, 0x0848, 0x08B2
};
SB_INTERNAL SBCodepoint LookupMirror(SBCodepoint codepoint)
{
if (codepoint <= 0xFF63) {
SBInt16 diff = PairDifferences[
PairData[
PairIndexes[
codepoint / 0x06A
] + (codepoint % 0x06A)
] & BracketTypeInverseMask
];
if (diff != 0) {
return (codepoint + diff);
}
}
return 0;
}
SB_INTERNAL SBCodepoint LookupBracketPair(SBCodepoint codepoint, BracketType *type)
{
if (codepoint <= 0xFF63) {
SBUInt8 data = PairData[
PairIndexes[
codepoint / 0x06A
] + (codepoint % 0x06A)
];
*type = (data & BracketTypePrimaryMask);
if (*type != 0) {
SBInt16 diff = PairDifferences[
data & BracketTypeInverseMask
];
return (codepoint + diff);
}
} else {
*type = BracketTypeNone;
}
return 0;
}

View file

@ -0,0 +1,17 @@
/*
* Automatically generated by SheenBidiGenerator tool.
* DO NOT EDIT!!
*/
#ifndef _SB_INTERNAL_PAIRING_LOOKUP_H
#define _SB_INTERNAL_PAIRING_LOOKUP_H
#include <SBConfig.h>
#include "BracketType.h"
#include "SBBase.h"
SB_INTERNAL SBCodepoint LookupMirror(SBCodepoint codepoint);
SB_INTERNAL SBCodepoint LookupBracketPair(SBCodepoint codepoint, BracketType *bracketType);
#endif

View file

@ -0,0 +1,50 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_RUN_EXTREMA_H
#define _SB_INTERNAL_RUN_EXTREMA_H
#include "SBBase.h"
enum {
RunExtremaLeadingL = SBBidiTypeL << 0,
RunExtremaLeadingR = SBBidiTypeR << 0,
RunExtremaTrailingL = SBBidiTypeL << 4,
RunExtremaTrailingR = SBBidiTypeR << 4
};
typedef SBUInt8 RunExtrema;
#define RunExtremaMake(sor, eor) \
(RunExtrema) \
( \
((sor) << 0) \
| ((eor) << 4) \
)
#define RunExtrema_SOR(e) \
(RunExtrema) \
( \
(e) & 0xF \
)
#define RunExtrema_EOR(e) \
(RunExtrema) \
( \
(e) >> 4 \
)
#endif

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_RUN_KIND_H
#define _SB_INTERNAL_RUN_KIND_H
#include "SBBase.h"
enum {
RunKindSimple = 0x00,
RunKindIsolate = 0x01,
RunKindPartial = 0x02,
RunKindPartialIsolate = RunKindIsolate | RunKindPartial,
RunKindTerminating = 0x04,
RunKindAttached = 0x08
};
typedef SBUInt8 RunKind;
#define RunKindMake(i, t) \
( \
((i) ? RunKindPartialIsolate : 0) \
| ((t) ? RunKindTerminating : 0) \
)
#define RunKindMakeComplete(k) \
( \
(k) &= ~RunKindPartial \
)
#define RunKindMakeAttached(k) \
( \
(k) |= RunKindAttached \
)
#define RunKindIsSimple(k) \
( \
(k) == RunKindSimple \
)
#define RunKindIsIsolate(k) \
( \
(k) & RunKindIsolate \
)
#define RunKindIsTerminating(k) \
( \
(k) & RunKindTerminating \
)
#define RunKindIsPartialIsolate(k) \
( \
(k) & RunKindPartial \
)
#define RunKindIsCompleteIsolate(k) \
( \
((k) & RunKindPartialIsolate) \
== RunKindIsolate \
)
#define RunKindIsAttachedTerminating(k) \
( \
(k) & RunKindAttached \
)
#endif

View file

@ -0,0 +1,161 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "LevelRun.h"
#include "SBAssert.h"
#include "SBBase.h"
#include "RunQueue.h"
static SBBoolean RunQueueInsertElement(RunQueueRef queue)
{
if (queue->_rearTop != RunQueueList_MaxIndex) {
queue->_rearTop += 1;
} else {
RunQueueListRef previousList = queue->_rearList;
RunQueueListRef rearList = previousList->next;
if (!rearList) {
rearList = malloc(sizeof(RunQueueList));
if (!rearList) {
return SBFalse;
}
rearList->previous = previousList;
rearList->next = NULL;
previousList->next = rearList;
}
queue->_rearList = rearList;
queue->_rearTop = 0;
}
queue->count += 1;
return SBTrue;
}
static void FindPreviousPartialRun(RunQueueRef queue)
{
RunQueueListRef list = queue->_partialList;
SBInteger top = queue->_partialTop;
do {
SBInteger limit = (list == queue->_frontList ? queue->_frontTop : 0);
do {
LevelRunRef levelRun = &list->elements[top];
if (RunKindIsPartialIsolate(levelRun->kind)) {
queue->_partialList = list;
queue->_partialTop = top;
return;
}
} while (top-- > limit);
list = list->previous;
top = RunQueueList_MaxIndex;
} while (list);
queue->_partialList = NULL;
queue->_partialTop = -1;
queue->shouldDequeue = SBFalse;
}
SB_INTERNAL void RunQueueInitialize(RunQueueRef queue)
{
/* Initialize first list. */
queue->_firstList.previous = NULL;
queue->_firstList.next = NULL;
/* Initialize front and rear lists with first list. */
queue->_frontList = &queue->_firstList;
queue->_rearList = &queue->_firstList;
queue->_partialList = NULL;
/* Initialize list indexes. */
queue->_frontTop = 0;
queue->_rearTop = -1;
queue->_partialTop = -1;
/* Initialize rest of the elements. */
queue->count = 0;
queue->peek = &queue->_frontList->elements[queue->_frontTop];
queue->shouldDequeue = SBFalse;
}
SB_INTERNAL SBBoolean RunQueueEnqueue(RunQueueRef queue, const LevelRunRef levelRun)
{
if (RunQueueInsertElement(queue)) {
LevelRunRef element = &queue->_rearList->elements[queue->_rearTop];
/* Copy the level run into the current element. */
*element = *levelRun;
/* Complete the latest isolating run with this terminating run. */
if (queue->_partialTop != -1 && RunKindIsTerminating(element->kind)) {
LevelRunRef incompleteRun = &queue->_partialList->elements[queue->_partialTop];
LevelRunAttach(incompleteRun, element);
FindPreviousPartialRun(queue);
}
/* Save the location of the isolating run. */
if (RunKindIsIsolate(element->kind)) {
queue->_partialList = queue->_rearList;
queue->_partialTop = queue->_rearTop;
}
return SBTrue;
}
return SBFalse;
}
SB_INTERNAL void RunQueueDequeue(RunQueueRef queue)
{
/* The queue should not be empty. */
SBAssert(queue->count != 0);
if (queue->_frontTop != RunQueueList_MaxIndex) {
queue->_frontTop += 1;
} else {
RunQueueListRef frontList = queue->_frontList;
if (frontList == queue->_rearList) {
queue->_rearTop = -1;
} else {
queue->_frontList = frontList->next;
}
queue->_frontTop = 0;
}
queue->count -= 1;
queue->peek = &queue->_frontList->elements[queue->_frontTop];
}
SB_INTERNAL void RunQueueFinalize(RunQueueRef queue)
{
RunQueueListRef list = queue->_firstList.next;
while (list) {
RunQueueListRef next = list->next;
free(list);
list = next;
};
}

View file

@ -0,0 +1,55 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_RUN_QUEUE_H
#define _SB_INTERNAL_RUN_QUEUE_H
#include <SBConfig.h>
#include "LevelRun.h"
#include "SBBase.h"
#define RunQueueList_Length 8
#define RunQueueList_MaxIndex (RunQueueList_Length - 1)
typedef struct _RunQueueList {
LevelRun elements[RunQueueList_Length];
struct _RunQueueList *previous; /**< Reference to the previous list of queue elements */
struct _RunQueueList *next; /**< Reference to the next list of queue elements */
} RunQueueList, *RunQueueListRef;
typedef struct _RunQueue {
RunQueueList _firstList; /**< First list of elements, which is part of the queue */
RunQueueListRef _frontList; /**< The list containing front element of the queue */
RunQueueListRef _rearList; /**< The list containing rear element of the queue */
RunQueueListRef _partialList; /**< The list containing latest partial isolating run */
SBInteger _frontTop; /**< Index of front element in front list */
SBInteger _rearTop; /**< Index of rear element in rear list */
SBInteger _partialTop; /**< Index of partial run in partial list */
LevelRunRef peek; /**< Peek element of the queue */
SBUInteger count; /**< Number of elements the queue contains */
SBBoolean shouldDequeue;
} RunQueue, *RunQueueRef;
SB_INTERNAL void RunQueueInitialize(RunQueueRef queue);
SB_INTERNAL SBBoolean RunQueueEnqueue(RunQueueRef queue, const LevelRunRef levelRun);
SB_INTERNAL void RunQueueDequeue(RunQueueRef queue);
SB_INTERNAL void RunQueueFinalize(RunQueueRef queue);
#endif

View file

@ -0,0 +1,203 @@
/*
* Copyright (C) 2016-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "BidiTypeLookup.h"
#include "SBBase.h"
#include "SBCodepointSequence.h"
#include "SBLog.h"
#include "SBParagraph.h"
#include "SBAlgorithm.h"
static SBAlgorithmRef AllocateAlgorithm(SBUInteger stringLength)
{
const SBUInteger sizeAlgorithm = sizeof(SBAlgorithm);
const SBUInteger sizeTypes = sizeof(SBBidiType) * stringLength;
const SBUInteger sizeMemory = sizeAlgorithm + sizeTypes;
void *pointer = malloc(sizeMemory);
if (pointer) {
const SBUInteger offsetAlgorithm = 0;
const SBUInteger offsetTypes = offsetAlgorithm + sizeAlgorithm;
SBUInt8 *memory = (SBUInt8 *)pointer;
SBAlgorithmRef algorithm = (SBAlgorithmRef)(memory + offsetAlgorithm);
SBLevel *fixedTypes = (SBLevel *)(memory + offsetTypes);
algorithm->fixedTypes = fixedTypes;
return algorithm;
}
return NULL;
}
static void DisposeAlgorithm(SBAlgorithmRef algorithm)
{
free(algorithm);
}
static void DetermineBidiTypes(const SBCodepointSequence *sequence, SBBidiType *types)
{
SBUInteger stringIndex = 0;
SBUInteger firstIndex = 0;
SBCodepoint codepoint;
while ((codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex)) != SBCodepointInvalid) {
types[firstIndex] = LookupBidiType(codepoint);
/* Subsequent code units get 'BN' type. */
while (++firstIndex < stringIndex) {
types[firstIndex] = SBBidiTypeBN;
}
}
}
static SBAlgorithmRef CreateAlgorithm(const SBCodepointSequence *codepointSequence)
{
SBUInteger stringLength = codepointSequence->stringLength;
SBAlgorithmRef algorithm;
SB_LOG_BLOCK_OPENER("Algorithm Input");
SB_LOG_STATEMENT("Codepoints", 1, SB_LOG_CODEPOINT_SEQUENCE(codepointSequence));
SB_LOG_BLOCK_CLOSER();
algorithm = AllocateAlgorithm(stringLength);
if (algorithm) {
algorithm->codepointSequence = *codepointSequence;
algorithm->retainCount = 1;
DetermineBidiTypes(codepointSequence, algorithm->fixedTypes);
SB_LOG_BLOCK_OPENER("Determined Types");
SB_LOG_STATEMENT("Types", 1, SB_LOG_BIDI_TYPES_ARRAY(algorithm->fixedTypes, stringLength));
SB_LOG_BLOCK_CLOSER();
SB_LOG_BREAKER();
}
return algorithm;
}
SBAlgorithmRef SBAlgorithmCreate(const SBCodepointSequence *codepointSequence)
{
if (SBCodepointSequenceIsValid(codepointSequence)) {
return CreateAlgorithm(codepointSequence);
}
return NULL;
}
const SBBidiType *SBAlgorithmGetBidiTypesPtr(SBAlgorithmRef algorithm)
{
return algorithm->fixedTypes;
}
SB_INTERNAL SBUInteger SBAlgorithmGetSeparatorLength(SBAlgorithmRef algorithm, SBUInteger separatorIndex)
{
const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence;
SBUInteger stringIndex = separatorIndex;
SBCodepoint codepoint;
SBUInteger separatorLength;
codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex);
separatorLength = stringIndex - separatorIndex;
if (codepoint == '\r') {
/* Don't break in between 'CR' and 'LF'. */
if (stringIndex < codepointSequence->stringLength) {
codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex);
if (codepoint == '\n') {
separatorLength = stringIndex - separatorIndex;
}
}
}
return separatorLength;
}
void SBAlgorithmGetParagraphBoundary(SBAlgorithmRef algorithm,
SBUInteger paragraphOffset, SBUInteger suggestedLength,
SBUInteger *acutalLength, SBUInteger *separatorLength)
{
const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence;
SBBidiType *bidiTypes = algorithm->fixedTypes;
SBUInteger limitIndex;
SBUInteger startIndex;
if (separatorLength) {
*separatorLength = 0;
}
SBUIntegerNormalizeRange(codepointSequence->stringLength, &paragraphOffset, &suggestedLength);
limitIndex = paragraphOffset + suggestedLength;
for (startIndex = paragraphOffset; startIndex < limitIndex; startIndex++) {
SBBidiType currentType = bidiTypes[startIndex];
if (currentType == SBBidiTypeB) {
SBUInteger codeUnitCount = SBAlgorithmGetSeparatorLength(algorithm, startIndex);
startIndex += codeUnitCount;
if (separatorLength) {
*separatorLength = codeUnitCount;
}
break;
}
}
if (acutalLength) {
*acutalLength = startIndex - paragraphOffset;
}
}
SBParagraphRef SBAlgorithmCreateParagraph(SBAlgorithmRef algorithm,
SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel)
{
const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence;
SBUInteger stringLength = codepointSequence->stringLength;
SBUIntegerNormalizeRange(stringLength, &paragraphOffset, &suggestedLength);
if (suggestedLength > 0) {
return SBParagraphCreate(algorithm, paragraphOffset, suggestedLength, baseLevel);
}
return NULL;
}
SBAlgorithmRef SBAlgorithmRetain(SBAlgorithmRef algorithm)
{
if (algorithm) {
algorithm->retainCount += 1;
}
return algorithm;
}
void SBAlgorithmRelease(SBAlgorithmRef algorithm)
{
if (algorithm && --algorithm->retainCount == 0) {
DisposeAlgorithm(algorithm);
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_ALGORITHM_H
#define _SB_INTERNAL_ALGORITHM_H
#include <SBAlgorithm.h>
#include <SBBase.h>
#include <SBBidiType.h>
#include <SBCodepointSequence.h>
#include <SBConfig.h>
typedef struct _SBAlgorithm {
SBCodepointSequence codepointSequence;
SBBidiType *fixedTypes;
SBUInteger retainCount;
} SBAlgorithm;
SB_INTERNAL SBUInteger SBAlgorithmGetSeparatorLength(SBAlgorithmRef algorithm, SBUInteger separatorIndex);
#endif

View file

@ -0,0 +1,24 @@
/*
* Copyright (C) 2014 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_ASSERT_H
#define _SB_INTERNAL_ASSERT_H
#include <assert.h>
#define SBAssert(exp) assert(exp)
#endif

View file

@ -0,0 +1,420 @@
/*
* Copyright (C) 2016-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include "BidiTypeLookup.h"
#include "GeneralCategoryLookup.h"
#include "PairingLookup.h"
#include "ScriptLookup.h"
#include "SBBase.h"
#define TAG(a, b, c, d) \
(SBUInt32) \
( \
((SBUInt8)(a) << 24) \
| ((SBUInt8)(b) << 16) \
| ((SBUInt8)(c) << 8) \
| ((SBUInt8)(d) << 0) \
)
SB_INTERNAL void SBUIntegerNormalizeRange(SBUInteger actualLength,
SBUInteger *rangeOffset, SBUInteger *rangeLength)
{
/**
* Assume:
* Actual Length = 10
*
* Case 1:
* Offset = 0, Length = 10
* Result:
* Offset = 0, Length = 10
*
* Case 2:
* Offset = 0, Length = 11
* Result:
* Offset = 0, Length = 10
*
* Case 3:
* Offset = 1, Length = -1 (MAX)
* Result:
* Offset = 1, Length = 9
*
* Case 4:
* Offset = 10, Length = 0
* Result:
* Offset = Invalid, Length = 0
*
* Case 5:
* Offset = -1 (MAX), Length = 1
* Result:
* Offset = Invalid, Length = 0
*/
if (*rangeOffset < actualLength) {
SBUInteger possibleLimit = *rangeOffset + *rangeLength;
if (*rangeOffset <= possibleLimit && possibleLimit <= actualLength) {
/* The range is valid. Nothing to do here. */
} else {
*rangeLength = actualLength - *rangeOffset;
}
} else {
*rangeOffset = SBInvalidIndex;
*rangeLength = 0;
}
}
SB_INTERNAL SBBoolean SBUIntegerVerifyRange(SBUInteger actualLength,
SBUInteger rangeOffset, SBUInteger rangeLength)
{
SBUInteger possibleLimit = rangeOffset + rangeLength;
return rangeOffset < actualLength
&& rangeOffset <= possibleLimit
&& possibleLimit <= actualLength;
}
SBBidiType SBCodepointGetBidiType(SBCodepoint codepoint)
{
return LookupBidiType(codepoint);
}
SBGeneralCategory SBCodepointGetGeneralCategory(SBCodepoint codepoint)
{
return LookupGeneralCategory(codepoint);
}
SBCodepoint SBCodepointGetMirror(SBCodepoint codepoint)
{
return LookupMirror(codepoint);
}
SBScript SBCodepointGetScript(SBCodepoint codepoint)
{
return LookupScript(codepoint);
}
SBUInt32 SBScriptGetOpenTypeTag(SBScript script)
{
/* Reference: https://docs.microsoft.com/en-us/typography/opentype/spec/scripttags */
/* Dated: 07/24/2017 */
switch (script) {
case SBScriptADLM:
return TAG('a', 'd', 'l', 'm');
case SBScriptAHOM:
return TAG('a', 'h', 'o', 'm');
case SBScriptHLUW:
return TAG('h', 'l', 'u', 'w');
case SBScriptARAB:
return TAG('a', 'r', 'a', 'b');
case SBScriptARMN:
return TAG('a', 'r', 'm', 'n');
case SBScriptAVST:
return TAG('a', 'v', 's', 't');
case SBScriptBALI:
return TAG('b', 'a', 'l', 'i');
case SBScriptBAMU:
return TAG('b', 'a', 'm', 'u');
case SBScriptBASS:
return TAG('b', 'a', 's', 's');
case SBScriptBATK:
return TAG('b', 'a', 't', 'k');
/* case SBScriptBENG:
return TAG('b', 'e', 'n', 'g'); */
case SBScriptBENG:
return TAG('b', 'n', 'g', '2');
case SBScriptBHKS:
return TAG('b', 'h', 'k', 's');
case SBScriptBOPO:
return TAG('b', 'o', 'p', 'o');
case SBScriptBRAH:
return TAG('b', 'r', 'a', 'h');
case SBScriptBRAI:
return TAG('b', 'r', 'a', 'i');
case SBScriptBUGI:
return TAG('b', 'u', 'g', 'i');
case SBScriptBUHD:
return TAG('b', 'u', 'h', 'd');
/* case SBScriptBYZM:
return TAG('b', 'y', 'z', 'm'); */
case SBScriptCANS:
return TAG('c', 'a', 'n', 's');
case SBScriptCARI:
return TAG('c', 'a', 'r', 'i');
case SBScriptAGHB:
return TAG('a', 'g', 'h', 'b');
case SBScriptCAKM:
return TAG('c', 'a', 'k', 'm');
case SBScriptCHAM:
return TAG('c', 'h', 'a', 'm');
case SBScriptCHER:
return TAG('c', 'h', 'e', 'r');
case SBScriptHANI:
return TAG('h', 'a', 'n', 'i');
case SBScriptCOPT:
return TAG('c', 'o', 'p', 't');
case SBScriptCPRT:
return TAG('c', 'p', 'r', 't');
case SBScriptCYRL:
return TAG('c', 'y', 'r', 'l');
/* case SBScriptDFLT:
return TAG('D', 'F', 'L', 'T'); */
case SBScriptDSRT:
return TAG('d', 's', 'r', 't');
/* case SBScriptDEVA:
return TAG('d', 'e', 'v', 'a'); */
case SBScriptDEVA:
return TAG('d', 'e', 'v', '2');
case SBScriptDUPL:
return TAG('d', 'u', 'p', 'l');
case SBScriptEGYP:
return TAG('e', 'g', 'y', 'p');
case SBScriptELBA:
return TAG('e', 'l', 'b', 'a');
case SBScriptETHI:
return TAG('e', 't', 'h', 'i');
case SBScriptGEOR:
return TAG('g', 'e', 'o', 'r');
case SBScriptGLAG:
return TAG('g', 'l', 'a', 'g');
case SBScriptGOTH:
return TAG('g', 'o', 't', 'h');
case SBScriptGRAN:
return TAG('g', 'r', 'a', 'n');
case SBScriptGREK:
return TAG('g', 'r', 'e', 'k');
/* case SBScriptGUJR:
return TAG('g', 'u', 'j', 'r'); */
case SBScriptGUJR:
return TAG('g', 'j', 'r', '2');
/* case SBScriptGURU:
return TAG('g', 'u', 'r', 'u'); */
case SBScriptGURU:
return TAG('g', 'u', 'r', '2');
case SBScriptHANG:
return TAG('h', 'a', 'n', 'g');
/* case SBScriptJAMO:
return TAG('j', 'a', 'm', 'o'); */
case SBScriptHANO:
return TAG('h', 'a', 'n', 'o');
case SBScriptHATR:
return TAG('h', 'a', 't', 'r');
case SBScriptHEBR:
return TAG('h', 'e', 'b', 'r');
case SBScriptHIRA:
return TAG('k', 'a', 'n', 'a');
case SBScriptARMI:
return TAG('a', 'r', 'm', 'i');
case SBScriptPHLI:
return TAG('p', 'h', 'l', 'i');
case SBScriptPRTI:
return TAG('p', 'r', 't', 'i');
case SBScriptJAVA:
return TAG('j', 'a', 'v', 'a');
case SBScriptKTHI:
return TAG('k', 't', 'h', 'i');
/* case SBScriptKNDA:
return TAG('k', 'n', 'd', 'a'); */
case SBScriptKNDA:
return TAG('k', 'n', 'd', '2');
case SBScriptKANA:
return TAG('k', 'a', 'n', 'a');
case SBScriptKALI:
return TAG('k', 'a', 'l', 'i');
case SBScriptKHAR:
return TAG('k', 'h', 'a', 'r');
case SBScriptKHMR:
return TAG('k', 'h', 'm', 'r');
case SBScriptKHOJ:
return TAG('k', 'h', 'o', 'j');
case SBScriptSIND:
return TAG('s', 'i', 'n', 'd');
case SBScriptLAOO:
return TAG('l', 'a', 'o', ' ');
case SBScriptLATN:
return TAG('l', 'a', 't', 'n');
case SBScriptLEPC:
return TAG('l', 'e', 'p', 'c');
case SBScriptLIMB:
return TAG('l', 'i', 'm', 'b');
case SBScriptLINA:
return TAG('l', 'i', 'n', 'a');
case SBScriptLINB:
return TAG('l', 'i', 'n', 'b');
case SBScriptLISU:
return TAG('l', 'i', 's', 'u');
case SBScriptLYCI:
return TAG('l', 'y', 'c', 'i');
case SBScriptLYDI:
return TAG('l', 'y', 'd', 'i');
case SBScriptMAHJ:
return TAG('m', 'a', 'h', 'j');
/* case SBScriptMLYM:
return TAG('m', 'l', 'y', 'm'); */
case SBScriptMLYM:
return TAG('m', 'l', 'm', '2');
case SBScriptMAND:
return TAG('m', 'a', 'n', 'd');
case SBScriptMANI:
return TAG('m', 'a', 'n', 'i');
case SBScriptMARC:
return TAG('m', 'a', 'r', 'c');
/* case SBScriptMATH:
return TAG('m', 'a', 't', 'h'); */
case SBScriptMTEI:
return TAG('m', 't', 'e', 'i');
case SBScriptMEND:
return TAG('m', 'e', 'n', 'd');
case SBScriptMERC:
return TAG('m', 'e', 'r', 'c');
case SBScriptMERO:
return TAG('m', 'e', 'r', 'o');
case SBScriptPLRD:
return TAG('p', 'l', 'r', 'd');
case SBScriptMODI:
return TAG('m', 'o', 'd', 'i');
case SBScriptMONG:
return TAG('m', 'o', 'n', 'g');
case SBScriptMROO:
return TAG('m', 'r', 'o', 'o');
case SBScriptMULT:
return TAG('m', 'u', 'l', 't');
/* case SBScriptMUSC:
return TAG('m', 'u', 's', 'c'); */
/* case SBScriptMYMR:
return TAG('m', 'y', 'm', 'r'); */
case SBScriptMYMR:
return TAG('m', 'y', 'm', '2');
case SBScriptNBAT:
return TAG('n', 'b', 'a', 't');
case SBScriptNEWA:
return TAG('n', 'e', 'w', 'a');
case SBScriptTALU:
return TAG('t', 'a', 'l', 'u');
case SBScriptNKOO:
return TAG('n', 'k', 'o', ' ');
/* case SBScriptORYA:
return TAG('o', 'r', 'y', 'a'); */
case SBScriptORYA:
return TAG('o', 'r', 'y', '2');
case SBScriptOGAM:
return TAG('o', 'g', 'a', 'm');
case SBScriptOLCK:
return TAG('o', 'l', 'c', 'k');
case SBScriptITAL:
return TAG('i', 't', 'a', 'l');
case SBScriptHUNG:
return TAG('h', 'u', 'n', 'g');
case SBScriptNARB:
return TAG('n', 'a', 'r', 'b');
case SBScriptPERM:
return TAG('p', 'e', 'r', 'm');
case SBScriptXPEO:
return TAG('x', 'p', 'e', 'o');
case SBScriptSARB:
return TAG('s', 'a', 'r', 'b');
case SBScriptORKH:
return TAG('o', 'r', 'k', 'h');
case SBScriptOSGE:
return TAG('o', 's', 'g', 'e');
case SBScriptOSMA:
return TAG('o', 's', 'm', 'a');
case SBScriptHMNG:
return TAG('h', 'm', 'n', 'g');
case SBScriptPALM:
return TAG('p', 'a', 'l', 'm');
case SBScriptPAUC:
return TAG('p', 'a', 'u', 'c');
case SBScriptPHAG:
return TAG('p', 'h', 'a', 'g');
case SBScriptPHNX:
return TAG('p', 'h', 'n', 'x');
case SBScriptPHLP:
return TAG('p', 'h', 'l', 'p');
case SBScriptRJNG:
return TAG('r', 'j', 'n', 'g');
case SBScriptRUNR:
return TAG('r', 'u', 'n', 'r');
case SBScriptSAMR:
return TAG('s', 'a', 'm', 'r');
case SBScriptSAUR:
return TAG('s', 'a', 'u', 'r');
case SBScriptSHRD:
return TAG('s', 'h', 'r', 'd');
case SBScriptSHAW:
return TAG('s', 'h', 'a', 'w');
case SBScriptSIDD:
return TAG('s', 'i', 'd', 'd');
case SBScriptSGNW:
return TAG('s', 'g', 'n', 'w');
case SBScriptSINH:
return TAG('s', 'i', 'n', 'h');
case SBScriptSORA:
return TAG('s', 'o', 'r', 'a');
case SBScriptXSUX:
return TAG('x', 's', 'u', 'x');
case SBScriptSUND:
return TAG('s', 'u', 'n', 'd');
case SBScriptSYLO:
return TAG('s', 'y', 'l', 'o');
case SBScriptSYRC:
return TAG('s', 'y', 'r', 'c');
case SBScriptTGLG:
return TAG('t', 'g', 'l', 'g');
case SBScriptTAGB:
return TAG('t', 'a', 'g', 'b');
case SBScriptTALE:
return TAG('t', 'a', 'l', 'e');
case SBScriptLANA:
return TAG('l', 'a', 'n', 'a');
case SBScriptTAVT:
return TAG('t', 'a', 'v', 't');
case SBScriptTAKR:
return TAG('t', 'a', 'k', 'r');
/* case SBScriptTAML:
return TAG('t', 'a', 'm', 'l'); */
case SBScriptTAML:
return TAG('t', 'm', 'l', '2');
case SBScriptTANG:
return TAG('t', 'a', 'n', 'g');
/* case SBScriptTELU:
return TAG('t', 'e', 'l', 'u'); */
case SBScriptTELU:
return TAG('t', 'e', 'l', '2');
case SBScriptTHAA:
return TAG('t', 'h', 'a', 'a');
case SBScriptTHAI:
return TAG('t', 'h', 'a', 'i');
case SBScriptTIBT:
return TAG('t', 'i', 'b', 't');
case SBScriptTFNG:
return TAG('t', 'f', 'n', 'g');
case SBScriptTIRH:
return TAG('t', 'i', 'r', 'h');
case SBScriptUGAR:
return TAG('u', 'g', 'a', 'r');
case SBScriptVAII:
return TAG('v', 'a', 'i', ' ');
case SBScriptWARA:
return TAG('w', 'a', 'r', 'a');
case SBScriptYIII:
return TAG('y', 'i', ' ', ' ');
default:
return TAG('D', 'F', 'L', 'T');
}
}

View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2016-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_BASE_H
#define _SB_INTERNAL_BASE_H
#include <SBBase.h>
#include <SBBidiType.h>
#include <SBCodepoint.h>
#include <SBConfig.h>
#include <SBGeneralCategory.h>
#include <SBScript.h>
/**
* A value that indicates an invalid unsigned index.
*/
#define SBInvalidIndex (SBUInteger)(-1)
SB_INTERNAL void SBUIntegerNormalizeRange(SBUInteger actualLength,
SBUInteger *rangeOffset, SBUInteger *rangeLength);
SB_INTERNAL SBBoolean SBUIntegerVerifyRange(SBUInteger actualLength,
SBUInteger rangeOffset, SBUInteger rangeLength);
#define SBNumberGetMax(first, second) \
( \
(first) > (second) \
? (first) \
: (second) \
)
#define SBNumberLimitIncrement(number, limit) \
( \
(number) < (limit) \
? (number) + (1) \
: (limit) \
)
#define SBNumberLimitDecrement(number, limit) \
( \
(number) > (limit) \
? (number) - (1) \
: (limit) \
)
#define SBNumberRingAdd(number, count, capacity) \
(((number) + (count)) % (capacity))
#define SBNumberRingIncrement(number, capacity) \
SBNumberRingAdd(number, 1, capacity)
#define SBNumberRingSubtract(number, count, capacity) \
(((number) + (capacity) - (count)) % (capacity))
#define SBNumberRingDecrement(number, capacity) \
SBNumberRingSubtract(number, 1, capacity)
#define SBLevelAsNormalBidiType(level) \
( \
((level) & 1) \
? SBBidiTypeR \
: SBBidiTypeL \
)
#define SBLevelAsOppositeBidiType(level) \
( \
((level) & 1) \
? SBBidiTypeL \
: SBBidiTypeR \
)
#define SBBidiTypeIsEqual(t1, t2) ((t1) == (t2))
#define SBBidiTypeIsNumber(t) SBUInt8InRange(t, SBBidiTypeAN, SBBidiTypeEN)
#define SBBidiTypeIsIsolate(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypePDI)
#define SBBidiTypeIsStrongOrNumber(t) (SBBidiTypeIsStrong(t) || SBBidiTypeIsNumber(t))
#define SBBidiTypeIsNumberSeparator(t) SBUInt8InRange(t, SBBidiTypeES, SBBidiTypeCS)
#define SBBidiTypeIsIsolateInitiator(t) SBUInt8InRange(t, SBBidiTypeLRI, SBBidiTypeFSI)
#define SBBidiTypeIsIsolateTerminator(t) SBBidiTypeIsEqual(t, SBBidiTypePDI)
#define SBBidiTypeIsNeutralOrIsolate(t) SBUInt8InRange(t, SBBidiTypeWS, SBBidiTypePDI)
#define SBCodepointMax 0x10FFFF
#define SBCodepointInRange(v, s, e) SBUInt32InRange(v, s, e)
#define SBCodepointIsSurrogate(c) SBCodepointInRange(c, 0xD800, 0xDFFF)
#define SBCodepointIsValid(c) (!SBCodepointIsSurrogate(c) && (c) <= SBCodepointMax)
#define SBScriptIsCommonOrInherited(s) ((s) <= SBScriptZYYY)
#endif

View file

@ -0,0 +1,303 @@
/*
* Copyright (C) 2016-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "SBAssert.h"
#include "SBBase.h"
#include "SBCodepointSequence.h"
typedef struct {
SBUInt8 valid;
SBUInt8 total;
SBUInt8 start;
SBUInt8 end;
} UTF8State;
static const UTF8State UTF8StateTable[9] = {
{1,0,0x00,0x00}, {0,0,0x00,0x00}, {1,2,0x80,0xBF}, {1,3,0xA0,0xBF}, {1,3,0x80,0xBF},
{1,3,0x80,0x9F}, {1,4,0x90,0xBF}, {1,4,0x80,0xBF}, {1,4,0x80,0x8F}
};
static const SBUInt8 UTF8LookupTable[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
/* LEAD: -- 80..BF -- */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1,
/* LEAD: -- C0..C1 -- */
1, 1,
/* LEAD: -- C2..DF -- */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* LEAD: -- E0..E0 -- */
3,
/* LEAD: -- E1..EC -- */
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* LEAD: -- ED..ED -- */
5,
/* LEAD: -- EE..EF -- */
4, 4,
/* LEAD: -- F0..F0 -- */
6,
/* LEAD: -- F1..F3 -- */
7, 7, 7,
/* LEAD: -- F4..F4 -- */
8,
/* LEAD: -- F5..F7 -- */
1, 1, 1,
/* LEAD: -- F8..FB -- */
1, 1, 1, 1,
/* LEAD: -- FC..FD -- */
1, 1,
/* LEAD: -- FE..FF -- */
1, 1
};
static SBCodepoint GetUTF8CodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex);
static SBCodepoint GetUTF8CodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex);
static SBCodepoint GetUTF16CodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex);
static SBCodepoint GetUTF16CodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex);
static SBCodepoint GetUTF32CodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex);
static SBCodepoint GetUTF32CodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex);
SB_INTERNAL SBBoolean SBCodepointSequenceIsValid(const SBCodepointSequence *codepointSequence)
{
if (codepointSequence) {
SBBoolean encodingValid = SBFalse;
switch (codepointSequence->stringEncoding) {
case SBStringEncodingUTF8:
case SBStringEncodingUTF16:
case SBStringEncodingUTF32:
encodingValid = SBTrue;
break;
}
return (encodingValid && codepointSequence->stringBuffer && codepointSequence->stringLength > 0);
}
return SBFalse;
}
SBCodepoint SBCodepointSequenceGetCodepointBefore(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex)
{
SBCodepoint codepoint = SBCodepointInvalid;
if ((*stringIndex - 1) < codepointSequence->stringLength) {
switch (codepointSequence->stringEncoding) {
case SBStringEncodingUTF8:
codepoint = GetUTF8CodepointBefore(codepointSequence, stringIndex);
break;
case SBStringEncodingUTF16:
codepoint = GetUTF16CodepointBefore(codepointSequence, stringIndex);
break;
case SBStringEncodingUTF32:
codepoint = GetUTF32CodepointBefore(codepointSequence, stringIndex);
break;
}
}
return codepoint;
}
SBCodepoint SBCodepointSequenceGetCodepointAt(const SBCodepointSequence *codepointSequence, SBUInteger *stringIndex)
{
SBCodepoint codepoint = SBCodepointInvalid;
if (*stringIndex < codepointSequence->stringLength) {
switch (codepointSequence->stringEncoding) {
case SBStringEncodingUTF8:
codepoint = GetUTF8CodepointAt(codepointSequence, stringIndex);
break;
case SBStringEncodingUTF16:
codepoint = GetUTF16CodepointAt(codepointSequence, stringIndex);
break;
case SBStringEncodingUTF32:
codepoint = GetUTF32CodepointAt(codepointSequence, stringIndex);
break;
}
}
return codepoint;
}
static SBCodepoint GetUTF8CodepointAt(const SBCodepointSequence *sequence, SBUInteger *index)
{
const SBUInt8 *buffer = sequence->stringBuffer;
SBUInteger length = sequence->stringLength;
SBUInt8 lead;
UTF8State state;
SBUInteger limit;
SBCodepoint codepoint;
lead = buffer[*index];
state = UTF8StateTable[UTF8LookupTable[lead]];
limit = *index + state.total;
if (limit > length) {
limit = length;
state.valid = SBFalse;
}
codepoint = lead & (0x7F >> state.total);
while (++(*index) < limit) {
SBUInt8 byte = buffer[*index];
if (byte >= state.start && byte <= state.end) {
codepoint = (codepoint << 6) | (byte & 0x3F);
} else {
state.valid = SBFalse;
break;
}
state.start = 0x80;
state.end = 0xBF;
}
if (state.valid) {
return codepoint;
}
return SBCodepointFaulty;
}
static SBCodepoint GetUTF8CodepointBefore(const SBCodepointSequence *sequence, SBUInteger *index)
{
const SBUInt8 *buffer = sequence->stringBuffer;
SBUInteger startIndex = *index;
SBUInteger limitIndex;
SBUInteger continuation;
SBCodepoint codepoint;
continuation = 7;
while (--continuation && --startIndex) {
SBUInt8 codeunit = buffer[startIndex];
if ((codeunit & 0xC0) != 0x80) {
break;
}
}
limitIndex = startIndex;
codepoint = GetUTF8CodepointAt(sequence, &limitIndex);
if (limitIndex == *index) {
*index = startIndex;
} else {
codepoint = SBCodepointFaulty;
*index -= 1;
}
return codepoint;
}
static SBCodepoint GetUTF16CodepointAt(const SBCodepointSequence *sequence, SBUInteger *index)
{
const SBUInt16 *buffer = sequence->stringBuffer;
SBUInteger length = sequence->stringLength;
SBCodepoint codepoint;
SBUInt16 lead;
codepoint = SBCodepointFaulty;
lead = buffer[*index];
*index += 1;
if (!SBCodepointIsSurrogate(lead)) {
codepoint = lead;
} else if (lead <= 0xDBFF) {
if (*index < length) {
SBUInt16 trail = buffer[*index];
if (SBUInt16InRange(trail, 0xDC00, 0xDFFF)) {
codepoint = (lead << 10) + trail - ((0xD800 << 10) + 0xDC00 - 0x10000);
*index += 1;
}
}
}
return codepoint;
}
static SBCodepoint GetUTF16CodepointBefore(const SBCodepointSequence *sequence, SBUInteger *index)
{
const SBUInt16 *buffer = sequence->stringBuffer;
SBCodepoint codepoint;
SBUInt16 trail;
codepoint = SBCodepointFaulty;
*index -= 1;
trail = buffer[*index];
if (!SBCodepointIsSurrogate(trail)) {
codepoint = trail;
} else if (trail >= 0xDC00) {
if (*index > 0) {
SBUInt16 lead = buffer[*index - 1];
if (SBUInt16InRange(lead, 0xD800, 0xDBFF)) {
codepoint = (lead << 10) + trail - ((0xD800 << 10) + 0xDC00 - 0x10000);
*index -= 1;
}
}
}
return codepoint;
}
static SBCodepoint GetUTF32CodepointAt(const SBCodepointSequence *sequence, SBUInteger *index)
{
const SBUInt32 *buffer = sequence->stringBuffer;
SBCodepoint codepoint;
codepoint = buffer[*index];
*index += 1;
if (SBCodepointIsValid(codepoint)) {
return codepoint;
}
return SBCodepointFaulty;
}
static SBCodepoint GetUTF32CodepointBefore(const SBCodepointSequence *sequence, SBUInteger *index)
{
const SBUInt32 *buffer = sequence->stringBuffer;
SBCodepoint codepoint;
*index -= 1;
codepoint = buffer[*index];
if (SBCodepointIsValid(codepoint)) {
return codepoint;
}
return SBCodepointFaulty;
}

View file

@ -0,0 +1,25 @@
/*
* Copyright (C) 2016 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_CODEPOINT_SEQUENCE_H
#define _SB_INTERNAL_CODEPOINT_SEQUENCE_H
#include <SBConfig.h>
#include <SBCodepointSequence.h>
SB_INTERNAL SBBoolean SBCodepointSequenceIsValid(const SBCodepointSequence *codepointSequence);
#endif

View file

@ -0,0 +1,320 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "PairingLookup.h"
#include "SBAlgorithm.h"
#include "SBAssert.h"
#include "SBBase.h"
#include "SBCodepointSequence.h"
#include "SBParagraph.h"
#include "SBRun.h"
#include "SBLine.h"
typedef struct _LineContext {
const SBBidiType *refTypes;
SBLevel *fixedLevels;
SBUInteger runCount;
SBLevel maxLevel;
} LineContext, *LineContextRef;
static SBLevel CopyLevels(SBLevel *destination,
const SBLevel *source, SBUInteger length, SBUInteger *runCount)
{
SBLevel lastLevel = SBLevelInvalid;
SBLevel maxLevel = 0;
SBUInteger totalRuns = 0;
while (length--) {
SBLevel level = *(source++);
*(destination++) = level;
if (level != lastLevel) {
totalRuns += 1;
if (level > maxLevel) {
maxLevel = level;
}
}
}
*runCount = totalRuns;
return maxLevel;
}
static LineContextRef CreateLineContext(const SBBidiType *types, const SBLevel *levels, SBUInteger length)
{
const SBUInteger sizeContext = sizeof(LineContext);
const SBUInteger sizeLevels = sizeof(SBLevel) * length;
const SBUInteger sizeMemory = sizeContext + sizeLevels;
void *pointer = malloc(sizeMemory);
if (pointer) {
const SBUInteger offsetContext = 0;
const SBUInteger offsetLevels = offsetContext + sizeContext;
SBUInt8 *memory = (SBUInt8 *)pointer;
LineContextRef context = (LineContextRef)(memory + offsetContext);
SBLevel *fixedLevels = (SBLevel *)(memory + offsetLevels);
context->refTypes = types;
context->fixedLevels = fixedLevels;
context->maxLevel = CopyLevels(fixedLevels, levels, length, &context->runCount);
return context;
}
return NULL;
}
static void DisposeLineContext(LineContextRef context)
{
free(context);
}
static SBLineRef AllocateLine(SBUInteger runCount)
{
const SBUInteger sizeLine = sizeof(SBLine);
const SBUInteger sizeRuns = sizeof(SBRun) * runCount;
const SBUInteger sizeMemory = sizeLine + sizeRuns;
void *pointer = malloc(sizeMemory);
if (pointer) {
const SBUInteger offsetLine = 0;
const SBUInteger offsetRuns = offsetLine + sizeLine;
SBUInt8 *memory = (SBUInt8 *)pointer;
SBLineRef line = (SBLineRef)(memory + offsetLine);
SBRun *runs = (SBRun *)(memory + offsetRuns);
line->fixedRuns = runs;
return line;
}
return NULL;
}
static void SetNewLevel(SBLevel *levels, SBUInteger length, SBLevel newLevel)
{
SBUInteger index = length;
while (index--) {
levels[index] = newLevel;
}
}
static void ResetLevels(LineContextRef context, SBLevel baseLevel, SBUInteger charCount)
{
const SBBidiType *types = context->refTypes;
SBLevel *levels = context->fixedLevels;
SBUInteger index;
SBUInteger length;
SBBoolean reset;
index = charCount;
length = 0;
reset = SBTrue;
while (index--) {
SBBidiType type = types[index];
switch (type) {
case SBBidiTypeB:
case SBBidiTypeS:
SetNewLevel(levels + index, length + 1, baseLevel);
length = 0;
reset = SBTrue;
context->runCount += 1;
break;
case SBBidiTypeLRE:
case SBBidiTypeRLE:
case SBBidiTypeLRO:
case SBBidiTypeRLO:
case SBBidiTypePDF:
case SBBidiTypeBN:
length += 1;
break;
case SBBidiTypeWS:
case SBBidiTypeLRI:
case SBBidiTypeRLI:
case SBBidiTypeFSI:
case SBBidiTypePDI:
if (reset) {
SetNewLevel(levels + index, length + 1, baseLevel);
length = 0;
context->runCount += 1;
}
break;
default:
length = 0;
reset = SBFalse;
break;
}
}
}
static SBUInteger InitializeRuns(SBRun *runs,
const SBLevel *levels, SBUInteger length, SBUInteger lineOffset)
{
SBUInteger index;
SBUInteger runCount = 1;
(*runs).offset = lineOffset;
(*runs).level = levels[0];
for (index = 0; index < length; index++) {
SBLevel level = levels[index];
if (level != (*runs).level) {
(*runs).length = index + lineOffset - (*runs).offset;
++runs;
(*runs).offset = lineOffset + index;
(*runs).level = level;
runCount += 1;
}
}
(*runs).length = index + lineOffset - (*runs).offset;
return runCount;
}
static void ReverseRunSequence(SBRun *runs, SBUInteger runCount)
{
SBUInteger halfCount = runCount / 2;
SBUInteger finalIndex = runCount - 1;
SBUInteger index;
for (index = 0; index < halfCount; index++) {
SBUInteger tieIndex;
SBRun tempRun;
tieIndex = finalIndex - index;
tempRun = runs[index];
runs[index] = runs[tieIndex];
runs[tieIndex] = tempRun;
}
}
static void ReorderRuns(SBRun *runs, SBUInteger runCount, SBLevel maxLevel)
{
SBLevel newLevel;
for (newLevel = maxLevel; newLevel; newLevel--) {
SBUInteger start = runCount;
while (start--) {
if (runs[start].level >= newLevel) {
SBUInteger count = 1;
for (; start && runs[start - 1].level >= newLevel; start--) {
count += 1;
}
ReverseRunSequence(runs + start, count);
}
}
}
}
SB_INTERNAL SBLineRef SBLineCreate(SBParagraphRef paragraph,
SBUInteger lineOffset, SBUInteger lineLength)
{
SBUInteger innerOffset = lineOffset - paragraph->offset;
const SBBidiType *refTypes = paragraph->refTypes + innerOffset;
const SBLevel *refLevels = paragraph->fixedLevels + innerOffset;
LineContextRef context;
SBLineRef line;
/* Line range MUST be valid. */
SBAssert(lineOffset < (lineOffset + lineLength)
&& lineOffset >= paragraph->offset
&& (lineOffset + lineLength) <= (paragraph->offset + paragraph->length));
context = CreateLineContext(refTypes, refLevels, lineLength);
if (context) {
ResetLevels(context, paragraph->baseLevel, lineLength);
line = AllocateLine(context->runCount);
if (line) {
line->runCount = InitializeRuns(line->fixedRuns, context->fixedLevels, lineLength, lineOffset);
ReorderRuns(line->fixedRuns, line->runCount, context->maxLevel);
line->codepointSequence = paragraph->algorithm->codepointSequence;
line->offset = lineOffset;
line->length = lineLength;
line->retainCount = 1;
}
DisposeLineContext(context);
return line;
}
return NULL;
}
SBUInteger SBLineGetOffset(SBLineRef line)
{
return line->offset;
}
SBUInteger SBLineGetLength(SBLineRef line)
{
return line->length;
}
SBUInteger SBLineGetRunCount(SBLineRef line)
{
return line->runCount;
}
const SBRun *SBLineGetRunsPtr(SBLineRef line)
{
return line->fixedRuns;
}
SBLineRef SBLineRetain(SBLineRef line)
{
if (line) {
line->retainCount += 1;
}
return line;
}
void SBLineRelease(SBLineRef line)
{
if (line && --line->retainCount == 0) {
free(line);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_LINE_H
#define _SB_INTERNAL_LINE_H
#include <SBBase.h>
#include <SBCodepointSequence.h>
#include <SBConfig.h>
#include <SBLine.h>
#include <SBParagraph.h>
#include <SBRun.h>
typedef struct _SBLine {
SBCodepointSequence codepointSequence;
SBRun *fixedRuns;
SBUInteger runCount;
SBUInteger offset;
SBUInteger length;
SBUInteger retainCount;
} SBLine;
SB_INTERNAL SBLineRef SBLineCreate(SBParagraphRef paragraph,
SBUInteger lineOffset, SBUInteger lineLength);
#endif

View file

@ -0,0 +1,303 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#ifdef SB_CONFIG_LOG
#include "SBBase.h"
#include "SBBidiChain.h"
#include "SBBidiType.h"
#include "SBIsolatingRun.h"
#include "SBLog.h"
int _SBLogPosition = 0;
SB_INTERNAL void PrintBaseLevel(SBLevel baseLevel)
{
switch (baseLevel) {
case SBLevelDefaultLTR:
SB_LOG_STRING("Auto-LTR");
break;
case SBLevelDefaultRTL:
SB_LOG_STRING("Auto-RTL");
break;
case 0:
SB_LOG_STRING("LTR");
break;
case 1:
SB_LOG_STRING("RTL");
break;
default:
SB_LOG(("Level - %d", baseLevel));
break;
}
}
SB_INTERNAL void PrintBidiType(SBBidiType type)
{
switch (type) {
case SBBidiTypeNil:
SB_LOG_STRING("Nil");
break;
case SBBidiTypeL:
SB_LOG_STRING("L");
break;
case SBBidiTypeR:
SB_LOG_STRING("R");
break;
case SBBidiTypeAL:
SB_LOG_STRING("AL");
break;
case SBBidiTypeEN:
SB_LOG_STRING("EN");
break;
case SBBidiTypeES:
SB_LOG_STRING("ES");
break;
case SBBidiTypeET:
SB_LOG_STRING("EN");
break;
case SBBidiTypeAN:
SB_LOG_STRING("AN");
break;
case SBBidiTypeCS:
SB_LOG_STRING("CS");
break;
case SBBidiTypeNSM:
SB_LOG_STRING("NSM");
break;
case SBBidiTypeBN:
SB_LOG_STRING("BN");
break;
case SBBidiTypeB:
SB_LOG_STRING("B");
break;
case SBBidiTypeS:
SB_LOG_STRING("S");
break;
case SBBidiTypeWS:
SB_LOG_STRING("WS");
break;
case SBBidiTypeON:
SB_LOG_STRING("ON");
break;
case SBBidiTypeLRE:
SB_LOG_STRING("LRE");
break;
case SBBidiTypeRLE:
SB_LOG_STRING("RLE");
break;
case SBBidiTypeLRO:
SB_LOG_STRING("LRO");
break;
case SBBidiTypeRLO:
SB_LOG_STRING("RLO");
break;
case SBBidiTypePDF:
SB_LOG_STRING("PDF");
break;
case SBBidiTypeLRI:
SB_LOG_STRING("LRI");
break;
case SBBidiTypeRLI:
SB_LOG_STRING("RLI");
break;
case SBBidiTypeFSI:
SB_LOG_STRING("FSI");
break;
case SBBidiTypePDI:
SB_LOG_STRING("PDI");
break;
}
}
SB_INTERNAL void PrintCodepointSequence(const SBCodepointSequence *codepointSequence)
{
SBUInteger stringIndex = 0;
SBCodepoint codepoint;
while ((codepoint = SBCodepointSequenceGetCodepointAt(codepointSequence, &stringIndex)) != SBCodepointInvalid) {
SB_LOG(("%04X ", codepoint));
}
}
SB_INTERNAL void PrintBidiTypesArray(SBBidiType *types, SBUInteger length)
{
SBUInteger index;
for (index = 0; index < length; ++index) {
SB_LOG_BIDI_TYPE(types[index]);
SB_LOG_DIVIDER(1);
}
}
SB_INTERNAL void PrintLevelsArray(SBLevel *levels, SBUInteger length)
{
SBUInteger index;
for (index = 0; index < length; ++index) {
SB_LOG_LEVEL(levels[index]);
SB_LOG_DIVIDER(1);
}
}
typedef struct {
void *object;
BidiLink link;
SBUInteger length;
} IsolatingContext;
typedef void (*IsolatingConsumer)(IsolatingRunRef isolatingRun, IsolatingContext *context);
SB_INTERNAL void IsolatingRunForEach(IsolatingRunRef isolatingRun,
IsolatingContext *context, IsolatingConsumer consumer)
{
BidiChainRef bidiChain = isolatingRun->bidiChain;
LevelRunRef levelRun;
/* Iterate over individual level runs of the isolating run. */
for (levelRun = isolatingRun->baseLevelRun; levelRun; levelRun = levelRun->next) {
BidiLink breakLink = BidiChainGetNext(bidiChain, levelRun->lastLink);
BidiLink currentLink = levelRun->firstLink;
BidiLink subsequentLink = levelRun->subsequentLink;
/* Iterate over each link of the level run. */
while (currentLink != breakLink) {
BidiLink nextLink = BidiChainGetNext(bidiChain, currentLink);
SBUInteger linkOffset = BidiChainGetOffset(bidiChain, currentLink);
SBUInteger linkLength;
SBUInteger index;
if (nextLink != breakLink) {
linkLength = BidiChainGetOffset(bidiChain, nextLink) - linkOffset;
} else {
linkLength = BidiChainGetOffset(bidiChain, subsequentLink) - linkOffset;
}
/* Skip any sequence of BN character types. */
for (index = 1; index < linkLength; index++) {
SBBidiType bidiType = BidiChainGetType(bidiChain, currentLink + index);
if (bidiType == SBBidiTypeBN) {
linkLength = index;
break;
}
}
context->link = currentLink;
context->length = linkLength;
consumer(isolatingRun, context);
currentLink = nextLink;
}
}
}
static void PrintTypesOperation(IsolatingRunRef isolatingRun, IsolatingContext *context)
{
SBBidiType bidiType = BidiChainGetType(isolatingRun->bidiChain, context->link);
while (context->length--) {
SB_LOG_BIDI_TYPE(bidiType);
SB_LOG_DIVIDER(1);
}
}
SB_INTERNAL void PrintRunTypes(IsolatingRunRef isolatingRun)
{
IsolatingContext context;
IsolatingRunForEach(isolatingRun, &context, _SBPrintTypesOperation);
}
static void PrintLevelsOperation(IsolatingRunRef isolatingRun, IsolatingContext *context)
{
SBLevel charLevel = BidiChainGetLevel(isolatingRun->bidiChain, context->link);
while (context->length--) {
SB_LOG_LEVEL(charLevel);
SB_LOG_DIVIDER(1);
}
}
SB_INTERNAL void PrintRunLevels(IsolatingRunRef isolatingRun)
{
IsolatingContext context;
IsolatingRunForEach(isolatingRun, &context, _SBPrintLevelsOperation);
}
typedef struct {
SBUInteger offset;
SBUInteger length;
} IsolatingRange;
static void PrintRangeOperation(IsolatingRunRef isolatingRun, IsolatingContext *context)
{
IsolatingRange *range = context->object;
SBUInteger offset = BidiChainGetOffset(isolatingRun->bidiChain, context->link);
if (range->length == 0) {
range->offset = offset;
range->length = context->length;
} else if (offset == (range->offset + range->length)) {
range->length += context->length;
} else {
SB_LOG_RANGE(range->offset, range->length);
SB_LOG_DIVIDER(1);
range->offset = offset;
range->length = context->length;
}
}
SB_INTERNAL void PrintRunRange(IsolatingRunRef isolatingRun)
{
IsolatingRange range = { 0, 0 };
IsolatingContext context;
context.object = &range;
IsolatingRunForEach(isolatingRun, &context, _SBPrintRangeOperation);
SB_LOG_RANGE(range.offset, range.length);
SB_LOG_DIVIDER(1);
}
#endif

View file

@ -0,0 +1,153 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_LOG_H
#define _SB_INTERNAL_LOG_H
#include <SBConfig.h>
#ifdef SB_CONFIG_LOG
#include <stdio.h>
#include "SBBase.h"
#include "SBBidiType.h"
#include "SBCodepointSequence.h"
#include "SBIsolatingRun.h"
SB_INTERNAL void PrintBaseLevel(SBLevel baseLevel);
SB_INTERNAL void PrintBidiType(SBBidiType type);
SB_INTERNAL void PrintCodepointSequence(const SBCodepointSequence *codepointSequence);
SB_INTERNAL void PrintBidiTypesArray(SBBidiType *types, SBUInteger length);
SB_INTERNAL void PrintLevelsArray(SBLevel *levels, SBUInteger length);
SB_INTERNAL void PrintRunTypes(IsolatingRunRef isolatingRun);
SB_INTERNAL void PrintRunLevels(IsolatingRunRef isolatingRun);
SB_INTERNAL void PrintRunRange(IsolatingRunRef isolatingRun);
extern int _SBLogPosition;
#define SB_LOG_BEGIN() (++_SBLogPosition)
#define SB_LOG_END() (--_SBLogPosition)
#define SB_LOG(s) printf s
#define SB_LOG_NUMBER(n) \
SB_LOG(("%ld", (long)n))
#define SB_LOG_RANGE(o, l) \
SB_LOG(("[%ld, %ld]", (long)o, (long)(o + l - 1)))
#define SB_LOG_CHAR(c) \
SBLOG(("%c", c))
#define SB_LOG_STRING(s) \
SB_LOG(("%s", s))
#define SB_LOG_LEVEL(l) \
SB_LOG_NUMBER(l)
#define SB_LOG_BREAKER() \
SB_LOG(("\n"))
#define SB_LOG_DIVIDER(n) \
SB_LOG(("%.*s", n, "\t\t\t\t\t\t\t\t\t\t"))
#define SB_LOG_INITIATOR() \
SB_LOG_DIVIDER(_SBLogPosition)
#define SB_LOG_CAPTION(c) \
SB_LOG((c":"))
#define SB_LOG_STATEMENT_TEXT(t) \
(t)
#define SB_LOG_LINE(s) \
do { \
SB_LOG(s); \
SB_LOG_BREAKER(); \
} while (0)
#define SB_LOG_STATEMENT(c, d, t) \
do { \
SB_LOG_INITIATOR(); \
SB_LOG_CAPTION(c); \
SB_LOG_DIVIDER(d); \
SB_LOG_STATEMENT_TEXT(t); \
SB_LOG_BREAKER(); \
} while (0)
#define SB_LOG_BLOCK_OPENER(c) \
do { \
SB_LOG_INITIATOR(); \
SB_LOG_CAPTION(c); \
SB_LOG_BREAKER(); \
SB_LOG_BEGIN(); \
} while (0)
#define SB_LOG_BLOCK_CLOSER() SB_LOG_END()
#define SB_LOG_BASE_LEVEL(l) PrintBaseLevel(l)
#define SB_LOG_BIDI_TYPE(t) PrintBidiType(t)
#define SB_LOG_CODEPOINT_SEQUENCE(s) PrintCodepointSequence(s)
#define SB_LOG_BIDI_TYPES_ARRAY(a, l) PrintBidiTypesArray(a, l)
#define SB_LOG_LEVELS_ARRAY(a, l) PrintLevelsArray(a, l)
#define SB_LOG_RUN_TYPES(r) PrintRunTypes(r)
#define SB_LOG_RUN_LEVELS(r) PrintRunLevels(r)
#define SB_LOG_RUN_RANGE(r) PrintRunRange(r)
#else
#define SB_LOG_NONE()
#define SB_LOG(s) SB_LOG_NONE()
#define SB_LOG_NUMBER(n) SB_LOG_NONE()
#define SB_LOG_RANGE(o, l) SB_LOG_NONE()
#define SB_LOG_CHAR(c) SB_LOG_NONE()
#define SB_LOG_STRING(s) SB_LOG_NONE()
#define SB_LOG_LEVEL(l) SB_LOG_NONE()
#define SB_LOG_BREAKER() SB_LOG_NONE()
#define SB_LOG_DIVIDER(n) SB_LOG_NONE()
#define SB_LOG_INITIATOR() SB_LOG_NONE()
#define SB_LOG_CAPTION(c) SB_LOG_NONE()
#define SB_LOG_STATEMENT_TEXT(t) SB_LOG_NONE()
#define SB_LOG_LINE(s) SB_LOG_NONE()
#define SB_LOG_STATEMENT(c, d, t) SB_LOG_NONE()
#define SB_LOG_BLOCK_OPENER(c) SB_LOG_NONE()
#define SB_LOG_BLOCK_CLOSER() SB_LOG_NONE()
#define SB_LOG_BASE_LEVEL(l) SB_LOG_NONE()
#define SB_LOG_BIDI_TYPE(t) SB_LOG_NONE()
#define SB_LOG_CODEPOINT_SEQUENCE(s) SB_LOG_NONE()
#define SB_LOG_BIDI_TYPES_ARRAY(a, l) SB_LOG_NONE()
#define SB_LOG_LEVELS_ARRAY(a, l) SB_LOG_NONE()
#define SB_LOG_RUN_TYPES(r) SB_LOG_NONE()
#define SB_LOG_RUN_LEVELS(r) SB_LOG_NONE()
#define SB_LOG_RUN_RANGE(r) SB_LOG_NONE()
#endif
#endif

View file

@ -0,0 +1,123 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include <stdlib.h>
#include "PairingLookup.h"
#include "SBBase.h"
#include "SBLine.h"
#include "SBMirrorLocator.h"
SBMirrorLocatorRef SBMirrorLocatorCreate(void)
{
SBMirrorLocatorRef locator = malloc(sizeof(SBMirrorLocator));
if (locator) {
locator->_line = NULL;
locator->retainCount = 1;
SBMirrorLocatorReset(locator);
}
return locator;
}
void SBMirrorLocatorLoadLine(SBMirrorLocatorRef locator, SBLineRef line, void *stringBuffer)
{
SBLineRelease(locator->_line);
if (line && stringBuffer == line->codepointSequence.stringBuffer) {
locator->_line = SBLineRetain(line);
}
SBMirrorLocatorReset(locator);
}
const SBMirrorAgent *SBMirrorLocatorGetAgent(SBMirrorLocatorRef locator)
{
return &locator->agent;
}
SBBoolean SBMirrorLocatorMoveNext(SBMirrorLocatorRef locator)
{
SBLineRef line = locator->_line;
if (line) {
const SBCodepointSequence *sequence = &line->codepointSequence;
do {
const SBRun *run = &line->fixedRuns[locator->_runIndex];
if (run->level & 1) {
SBUInteger stringIndex;
SBUInteger stringLimit;
stringIndex = locator->_stringIndex;
if (stringIndex == SBInvalidIndex) {
stringIndex = run->offset;
}
stringLimit = run->offset + run->length;
while (stringIndex < stringLimit) {
SBUInteger initialIndex = stringIndex;
SBCodepoint codepoint = SBCodepointSequenceGetCodepointAt(sequence, &stringIndex);
SBCodepoint mirror = LookupMirror(codepoint);
if (mirror) {
locator->_stringIndex = stringIndex;
locator->agent.index = initialIndex;
locator->agent.mirror = mirror;
locator->agent.codepoint = codepoint;
return SBTrue;
}
}
}
locator->_stringIndex = SBInvalidIndex;
} while (++locator->_runIndex < line->runCount);
SBMirrorLocatorReset(locator);
}
return SBFalse;
}
void SBMirrorLocatorReset(SBMirrorLocatorRef locator)
{
locator->_runIndex = 0;
locator->_stringIndex = SBInvalidIndex;
locator->agent.index = SBInvalidIndex;
locator->agent.mirror = 0;
}
SBMirrorLocatorRef SBMirrorLocatorRetain(SBMirrorLocatorRef locator)
{
if (locator) {
locator->retainCount += 1;
}
return locator;
}
void SBMirrorLocatorRelease(SBMirrorLocatorRef locator)
{
if (locator && --locator->retainCount == 0) {
SBLineRelease(locator->_line);
free(locator);
}
}

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_MIRROR_LOCATOR_H
#define _SB_INTERNAL_MIRROR_LOCATOR_H
#include <SBBase.h>
#include <SBMirrorLocator.h>
#include <SBLine.h>
typedef struct _SBMirrorLocator {
SBLineRef _line;
SBUInteger _runIndex;
SBUInteger _stringIndex;
SBMirrorAgent agent;
SBUInteger retainCount;
} SBMirrorLocator;
#endif

View file

@ -0,0 +1,702 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "BidiChain.h"
#include "BidiTypeLookup.h"
#include "IsolatingRun.h"
#include "LevelRun.h"
#include "RunQueue.h"
#include "SBAlgorithm.h"
#include "SBAssert.h"
#include "SBBase.h"
#include "SBCodepointSequence.h"
#include "SBLine.h"
#include "SBLog.h"
#include "StatusStack.h"
#include "SBParagraph.h"
typedef struct _ParagraphContext {
BidiChain bidiChain;
StatusStack statusStack;
RunQueue runQueue;
IsolatingRun isolatingRun;
} ParagraphContext, *ParagraphContextRef;
static void PopulateBidiChain(BidiChainRef chain, const SBBidiType *types, SBUInteger length);
static SBBoolean ProcessRun(ParagraphContextRef context, const LevelRunRef levelRun, SBBoolean forceFinish);
static ParagraphContextRef CreateParagraphContext(const SBBidiType *types, SBLevel *levels, SBUInteger length)
{
const SBUInteger sizeContext = sizeof(ParagraphContext);
const SBUInteger sizeLinks = sizeof(BidiLink) * (length + 2);
const SBUInteger sizeTypes = sizeof(SBBidiType) * (length + 2);
const SBUInteger sizeMemory = sizeContext + sizeLinks + sizeTypes;
void *pointer = malloc(sizeMemory);
if (pointer) {
const SBUInteger offsetContext = 0;
const SBUInteger offsetLinks = offsetContext + sizeContext;
const SBUInteger offsetTypes = offsetLinks + sizeLinks;
SBUInt8 *memory = (SBUInt8 *)pointer;
ParagraphContextRef context = (ParagraphContextRef)(memory + offsetContext);
BidiLink *fixedLinks = (BidiLink *)(memory + offsetLinks);
SBBidiType *fixedTypes = (SBBidiType *)(memory + offsetTypes);
BidiChainInitialize(&context->bidiChain, fixedTypes, levels, fixedLinks);
StatusStackInitialize(&context->statusStack);
RunQueueInitialize(&context->runQueue);
IsolatingRunInitialize(&context->isolatingRun);
PopulateBidiChain(&context->bidiChain, types, length);
return context;
}
return NULL;
}
static void DisposeParagraphContext(ParagraphContextRef context)
{
StatusStackFinalize(&context->statusStack);
RunQueueFinalize(&context->runQueue);
IsolatingRunFinalize(&context->isolatingRun);
free(context);
}
static SBParagraphRef AllocateParagraph(SBUInteger length)
{
const SBUInteger sizeParagraph = sizeof(SBParagraph);
const SBUInteger sizeLevels = sizeof(SBLevel) * (length + 2);
const SBUInteger sizeMemory = sizeParagraph + sizeLevels;
void *pointer = malloc(sizeMemory);
if (pointer) {
const SBUInteger offsetParagraph = 0;
const SBUInteger offsetLevels = offsetParagraph + sizeParagraph;
SBUInt8 *memory = (SBUInt8 *)pointer;
SBParagraphRef paragraph = (SBParagraphRef)(memory + offsetParagraph);
SBLevel *levels = (SBLevel *)(memory + offsetLevels);
paragraph->fixedLevels = levels;
return paragraph;
}
return NULL;
}
static void DisposeParagraph(SBParagraphRef paragraph)
{
free(paragraph);
}
static SBUInteger DetermineBoundary(SBAlgorithmRef algorithm, SBUInteger paragraphOffset, SBUInteger suggestedLength)
{
SBBidiType *bidiTypes = algorithm->fixedTypes;
SBUInteger suggestedLimit = paragraphOffset + suggestedLength;
SBUInteger stringIndex;
for (stringIndex = paragraphOffset; stringIndex < suggestedLimit; stringIndex++) {
if (bidiTypes[stringIndex] == SBBidiTypeB) {
stringIndex += SBAlgorithmGetSeparatorLength(algorithm, stringIndex);
goto Return;
}
}
Return:
return (stringIndex - paragraphOffset);
}
static void PopulateBidiChain(BidiChainRef chain, const SBBidiType *types, SBUInteger length)
{
SBBidiType type = SBBidiTypeNil;
SBUInteger priorIndex = SBInvalidIndex;
SBUInteger index;
for (index = 0; index < length; index++) {
SBBidiType priorType = type;
type = types[index];
switch (type) {
case SBBidiTypeB:
case SBBidiTypeON:
case SBBidiTypeLRE:
case SBBidiTypeRLE:
case SBBidiTypeLRO:
case SBBidiTypeRLO:
case SBBidiTypePDF:
case SBBidiTypeLRI:
case SBBidiTypeRLI:
case SBBidiTypeFSI:
case SBBidiTypePDI:
BidiChainAdd(chain, type, index - priorIndex);
priorIndex = index;
if (type == SBBidiTypeB) {
index = length;
goto AddLast;
}
break;
default:
if (type != priorType) {
BidiChainAdd(chain, type, index - priorIndex);
priorIndex = index;
}
break;
}
}
AddLast:
BidiChainAdd(chain, SBBidiTypeNil, index - priorIndex);
}
static BidiLink SkipIsolatingRun(BidiChainRef chain, BidiLink skipLink, BidiLink breakLink)
{
BidiLink link = skipLink;
SBUInteger depth = 1;
while ((link = BidiChainGetNext(chain, link)) != breakLink) {
SBBidiType type = BidiChainGetType(chain, link);
switch (type) {
case SBBidiTypeLRI:
case SBBidiTypeRLI:
case SBBidiTypeFSI:
depth += 1;
break;
case SBBidiTypePDI:
if (--depth == 0) {
return link;
}
break;
}
}
return BidiLinkNone;
}
static SBLevel DetermineBaseLevel(BidiChainRef chain, BidiLink skipLink, BidiLink breakLink, SBLevel defaultLevel, SBBoolean isIsolate)
{
BidiLink link = skipLink;
/* Rules P2, P3 */
while ((link = BidiChainGetNext(chain, link)) != breakLink) {
SBBidiType type = BidiChainGetType(chain, link);
switch (type) {
case SBBidiTypeL:
return 0;
case SBBidiTypeAL:
case SBBidiTypeR:
return 1;
case SBBidiTypeLRI:
case SBBidiTypeRLI:
case SBBidiTypeFSI:
link = SkipIsolatingRun(chain, link, breakLink);
if (link == BidiLinkNone) {
goto Default;
}
break;
case SBBidiTypePDI:
if (isIsolate) {
/*
* In case of isolating run, the PDI will be the last code point.
* NOTE:
* The inner isolating runs will be skipped by the case above this one.
*/
goto Default;
}
break;
}
}
Default:
return defaultLevel;
}
static SBLevel DetermineParagraphLevel(BidiChainRef chain, SBLevel baseLevel)
{
if (baseLevel >= SBLevelMax) {
return DetermineBaseLevel(chain, chain->roller, chain->roller,
(baseLevel != SBLevelDefaultRTL ? 0 : 1),
SBFalse);
}
return baseLevel;
}
static SBBoolean DetermineLevels(ParagraphContextRef context, SBLevel baseLevel)
{
BidiChainRef chain = &context->bidiChain;
StatusStackRef stack = &context->statusStack;
BidiLink roller = chain->roller;
BidiLink link;
BidiLink priorLink;
BidiLink firstLink;
BidiLink lastLink;
SBLevel priorLevel;
SBBidiType sor;
SBBidiType eor;
SBUInteger overIsolate;
SBUInteger overEmbedding;
SBUInteger validIsolate;
priorLink = chain->roller;
firstLink = BidiLinkNone;
lastLink = BidiLinkNone;
priorLevel = baseLevel;
sor = SBBidiTypeNil;
/* Rule X1 */
overIsolate = 0;
overEmbedding = 0;
validIsolate = 0;
StatusStackPush(stack, baseLevel, SBBidiTypeON, SBFalse);
BidiChainForEach(chain, roller, link) {
SBBoolean forceFinish = SBFalse;
SBBoolean bnEquivalent = SBFalse;
SBBidiType type;
type = BidiChainGetType(chain, link);
#define LeastGreaterOddLevel() \
( \
(StatusStackGetEmbeddingLevel(stack) + 1) | 1 \
)
#define LeastGreaterEvenLevel() \
( \
(StatusStackGetEmbeddingLevel(stack) + 2) & ~1 \
)
#define MergeLinkIfNeeded() \
{ \
if (BidiChainMergeIfEqual(chain, priorLink, link)) { \
continue; \
} \
}
#define PushEmbedding(l, o) \
{ \
SBLevel newLevel = l; \
\
bnEquivalent = SBTrue; \
\
if (newLevel <= SBLevelMax && !overIsolate && !overEmbedding) { \
if (!StatusStackPush(stack, newLevel, o, SBFalse)) { \
return SBFalse; \
} \
} else { \
if (!overIsolate) { \
overEmbedding += 1; \
} \
} \
}
#define PushIsolate(l, o) \
{ \
SBBidiType priorStatus = StatusStackGetOverrideStatus(stack); \
SBLevel newLevel = l; \
\
BidiChainSetLevel(chain, link, \
StatusStackGetEmbeddingLevel(stack)); \
\
if (newLevel <= SBLevelMax && !overIsolate && !overEmbedding) { \
validIsolate += 1; \
\
if (!StatusStackPush(stack, newLevel, o, SBTrue)) { \
return SBFalse; \
} \
} else { \
overIsolate += 1; \
} \
\
if (priorStatus != SBBidiTypeON) { \
BidiChainSetType(chain, link, priorStatus); \
MergeLinkIfNeeded(); \
} \
}
switch (type) {
/* Rule X2 */
case SBBidiTypeRLE:
PushEmbedding(LeastGreaterOddLevel(), SBBidiTypeON);
break;
/* Rule X3 */
case SBBidiTypeLRE:
PushEmbedding(LeastGreaterEvenLevel(), SBBidiTypeON);
break;
/* Rule X4 */
case SBBidiTypeRLO:
PushEmbedding(LeastGreaterOddLevel(), SBBidiTypeR);
break;
/* Rule X5 */
case SBBidiTypeLRO:
PushEmbedding(LeastGreaterEvenLevel(), SBBidiTypeL);
break;
/* Rule X5a */
case SBBidiTypeRLI:
PushIsolate(LeastGreaterOddLevel(), SBBidiTypeON);
break;
/* Rule X5b */
case SBBidiTypeLRI:
PushIsolate(LeastGreaterEvenLevel(), SBBidiTypeON);
break;
/* Rule X5c */
case SBBidiTypeFSI:
{
SBBoolean isRTL = (DetermineBaseLevel(chain, link, roller, 0, SBTrue) == 1);
PushIsolate(isRTL ? LeastGreaterOddLevel() : LeastGreaterEvenLevel(), SBBidiTypeON);
break;
}
/* Rule X6 */
default:
BidiChainSetLevel(chain, link, StatusStackGetEmbeddingLevel(stack));
if (StatusStackGetOverrideStatus(stack) != SBBidiTypeON) {
BidiChainSetType(chain, link, StatusStackGetOverrideStatus(stack));
MergeLinkIfNeeded();
}
break;
/* Rule X6a */
case SBBidiTypePDI:
{
SBBidiType overrideStatus;
if (overIsolate != 0) {
overIsolate -= 1;
} else if (validIsolate == 0) {
/* Do nothing */
} else {
overEmbedding = 0;
while (!StatusStackGetIsolateStatus(stack)) {
StatusStackPop(stack);
}
StatusStackPop(stack);
validIsolate -= 1;
}
BidiChainSetLevel(chain, link, StatusStackGetEmbeddingLevel(stack));
overrideStatus = StatusStackGetOverrideStatus(stack);
if (overrideStatus != SBBidiTypeON) {
BidiChainSetType(chain, link, overrideStatus);
MergeLinkIfNeeded();
}
break;
}
/* Rule X7 */
case SBBidiTypePDF:
bnEquivalent = SBTrue;
if (overIsolate != 0) {
/* Do nothing */
} else if (overEmbedding != 0) {
overEmbedding -= 1;
} else if (!StatusStackGetIsolateStatus(stack) && stack->count >= 2) {
StatusStackPop(stack);
}
break;
/* Rule X8 */
case SBBidiTypeB:
/*
* These values are reset for clarity, in this implementation B can only occur as the
* last code in the array.
*/
StatusStackSetEmpty(stack);
StatusStackPush(stack, baseLevel, SBBidiTypeON, SBFalse);
overIsolate = 0;
overEmbedding = 0;
validIsolate = 0;
BidiChainSetLevel(chain, link, baseLevel);
break;
case SBBidiTypeBN:
bnEquivalent = SBTrue;
break;
case SBBidiTypeNil:
forceFinish = SBTrue;
BidiChainSetLevel(chain, link, baseLevel);
break;
}
/* Rule X9 */
if (bnEquivalent) {
/* The type of this link is BN equivalent, so abandon it and continue the loop. */
BidiChainSetType(chain, link, SBBidiTypeBN);
BidiChainAbandonNext(chain, priorLink);
continue;
}
if (sor == SBBidiTypeNil) {
sor = SBLevelAsNormalBidiType(SBNumberGetMax(baseLevel, BidiChainGetLevel(chain, link)));
firstLink = link;
priorLevel = BidiChainGetLevel(chain, link);
} else if (priorLevel != BidiChainGetLevel(chain, link) || forceFinish) {
LevelRun levelRun;
SBLevel currentLevel;
/* Since the level has changed at this link, therefore the run must end at prior link. */
lastLink = priorLink;
/* Save the current level i.e. level of the next run. */
currentLevel = BidiChainGetLevel(chain, link);
/*
* Now we have both the prior level and the current level i.e. unchanged levels of both
* the current run and the next run. So, identify eor of the current run.
* NOTE:
* sor of the run has been already determined at this stage.
*/
eor = SBLevelAsNormalBidiType(SBNumberGetMax(priorLevel, currentLevel));
LevelRunInitialize(&levelRun, chain, firstLink, lastLink, sor, eor);
if (!ProcessRun(context, &levelRun, forceFinish)) {
return SBFalse;
}
/* The sor of next run (if any) should be technically equal to eor of this run. */
sor = eor;
/* The next run (if any) will start from this index. */
firstLink = link;
priorLevel = currentLevel;
}
priorLink = link;
}
return SBTrue;
}
static SBBoolean ProcessRun(ParagraphContextRef context, const LevelRunRef levelRun, SBBoolean forceFinish)
{
RunQueueRef queue = &context->runQueue;
if (!RunQueueEnqueue(queue, levelRun)) {
return SBFalse;
}
if (queue->shouldDequeue || forceFinish) {
IsolatingRunRef isolatingRun = &context->isolatingRun;
LevelRunRef peek;
/* Rule X10 */
for (; queue->count != 0; RunQueueDequeue(queue)) {
peek = queue->peek;
if (RunKindIsAttachedTerminating(peek->kind)) {
continue;
}
isolatingRun->baseLevelRun = peek;
if (!IsolatingRunResolve(isolatingRun)) {
return SBFalse;
}
}
}
return SBTrue;
}
static void SaveLevels(BidiChainRef chain, SBLevel *levels, SBLevel baseLevel)
{
BidiLink roller = chain->roller;
BidiLink link;
SBUInteger index = 0;
SBLevel level = baseLevel;
BidiChainForEach(chain, roller, link) {
SBUInteger offset = BidiChainGetOffset(chain, link);
for (; index < offset; index++) {
levels[index] = level;
}
level = BidiChainGetLevel(chain, link);
}
}
static SBBoolean ResolveParagraph(SBParagraphRef paragraph,
SBAlgorithmRef algorithm, SBUInteger offset, SBUInteger length, SBLevel baseLevel)
{
const SBBidiType *bidiTypes = algorithm->fixedTypes + offset;
SBBoolean isSucceeded = SBFalse;
ParagraphContextRef context;
SBLevel resolvedLevel;
context = CreateParagraphContext(bidiTypes, paragraph->fixedLevels, length);
if (context) {
resolvedLevel = DetermineParagraphLevel(&context->bidiChain, baseLevel);
SB_LOG_BLOCK_OPENER("Determined Paragraph Level");
SB_LOG_STATEMENT("Base Level", 1, SB_LOG_LEVEL(resolvedLevel));
SB_LOG_BLOCK_CLOSER();
context->isolatingRun.codepointSequence = &algorithm->codepointSequence;
context->isolatingRun.bidiTypes = bidiTypes;
context->isolatingRun.bidiChain = &context->bidiChain;
context->isolatingRun.paragraphOffset = offset;
context->isolatingRun.paragraphLevel = resolvedLevel;
if (DetermineLevels(context, resolvedLevel)) {
SaveLevels(&context->bidiChain, ++paragraph->fixedLevels, resolvedLevel);
SB_LOG_BLOCK_OPENER("Determined Embedding Levels");
SB_LOG_STATEMENT("Levels", 1, SB_LOG_LEVELS_ARRAY(paragraph->fixedLevels, length));
SB_LOG_BLOCK_CLOSER();
paragraph->algorithm = SBAlgorithmRetain(algorithm);
paragraph->refTypes = bidiTypes;
paragraph->offset = offset;
paragraph->length = length;
paragraph->baseLevel = resolvedLevel;
paragraph->retainCount = 1;
isSucceeded = SBTrue;
}
DisposeParagraphContext(context);
}
return isSucceeded;
}
SB_INTERNAL SBParagraphRef SBParagraphCreate(SBAlgorithmRef algorithm,
SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel)
{
const SBCodepointSequence *codepointSequence = &algorithm->codepointSequence;
SBUInteger stringLength = codepointSequence->stringLength;
SBUInteger actualLength;
SBParagraphRef paragraph;
/* The given range MUST be valid. */
SBAssert(SBUIntegerVerifyRange(stringLength, paragraphOffset, suggestedLength) && suggestedLength > 0);
SB_LOG_BLOCK_OPENER("Paragraph Input");
SB_LOG_STATEMENT("Paragraph Offset", 1, SB_LOG_NUMBER(paragraphOffset));
SB_LOG_STATEMENT("Suggested Length", 1, SB_LOG_NUMBER(suggestedLength));
SB_LOG_STATEMENT("Base Direction", 1, SB_LOG_BASE_LEVEL(baseLevel));
SB_LOG_BLOCK_CLOSER();
actualLength = DetermineBoundary(algorithm, paragraphOffset, suggestedLength);
SB_LOG_BLOCK_OPENER("Determined Paragraph Boundary");
SB_LOG_STATEMENT("Actual Length", 1, SB_LOG_NUMBER(actualLength));
SB_LOG_BLOCK_CLOSER();
paragraph = AllocateParagraph(actualLength);
if (paragraph) {
if (ResolveParagraph(paragraph, algorithm, paragraphOffset, actualLength, baseLevel)) {
return paragraph;
}
DisposeParagraph(paragraph);
}
SB_LOG_BREAKER();
return NULL;
}
SBUInteger SBParagraphGetOffset(SBParagraphRef paragraph)
{
return paragraph->offset;
}
SBUInteger SBParagraphGetLength(SBParagraphRef paragraph)
{
return paragraph->length;
}
SBLevel SBParagraphGetBaseLevel(SBParagraphRef paragraph)
{
return paragraph->baseLevel;
}
const SBLevel *SBParagraphGetLevelsPtr(SBParagraphRef paragraph)
{
return paragraph->fixedLevels;
}
SBLineRef SBParagraphCreateLine(SBParagraphRef paragraph, SBUInteger lineOffset, SBUInteger lineLength)
{
SBUInteger paragraphOffset = paragraph->offset;
SBUInteger paragraphLength = paragraph->length;
SBUInteger paragraphLimit = paragraphOffset + paragraphLength;
SBUInteger lineLimit = lineOffset + lineLength;
if (lineOffset < lineLimit && lineOffset >= paragraphOffset && lineLimit <= paragraphLimit) {
return SBLineCreate(paragraph, lineOffset, lineLength);
}
return NULL;
}
SBParagraphRef SBParagraphRetain(SBParagraphRef paragraph)
{
if (paragraph) {
paragraph->retainCount += 1;
}
return paragraph;
}
void SBParagraphRelease(SBParagraphRef paragraph)
{
if (paragraph && --paragraph->retainCount == 0) {
SBAlgorithmRelease(paragraph->algorithm);
DisposeParagraph(paragraph);
}
}

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_PARAGRAPH_H
#define _SB_INTERNAL_PARAGRAPH_H
#include <SBAlgorithm.h>
#include <SBBase.h>
#include <SBConfig.h>
#include <SBParagraph.h>
typedef struct _SBParagraph {
SBAlgorithmRef algorithm;
const SBBidiType *refTypes;
SBLevel *fixedLevels;
SBUInteger offset;
SBUInteger length;
SBLevel baseLevel;
SBUInteger retainCount;
} SBParagraph;
SB_INTERNAL SBParagraphRef SBParagraphCreate(SBAlgorithmRef algorithm,
SBUInteger paragraphOffset, SBUInteger suggestedLength, SBLevel baseLevel);
#endif

View file

@ -0,0 +1,176 @@
/*
* Copyright (C) 2018-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include <stdlib.h>
#include "GeneralCategoryLookup.h"
#include "PairingLookup.h"
#include "SBBase.h"
#include "SBCodepointSequence.h"
#include "ScriptLookup.h"
#include "ScriptStack.h"
#include "SBScriptLocator.h"
static SBBoolean IsSimilarScript(SBScript lhs, SBScript rhs)
{
return SBScriptIsCommonOrInherited(lhs)
|| SBScriptIsCommonOrInherited(rhs)
|| lhs == rhs;
}
SBScriptLocatorRef SBScriptLocatorCreate(void)
{
SBScriptLocatorRef locator = malloc(sizeof(SBScriptLocator));
if (locator) {
locator->_codepointSequence.stringEncoding = SBStringEncodingUTF8;
locator->_codepointSequence.stringBuffer = NULL;
locator->_codepointSequence.stringLength = 0;
locator->retainCount = 1;
SBScriptLocatorReset(locator);
}
return locator;
}
void SBScriptLocatorLoadCodepoints(SBScriptLocatorRef locator, const SBCodepointSequence *codepointSequence)
{
locator->_codepointSequence = *codepointSequence;
SBScriptLocatorReset(locator);
}
const SBScriptAgent *SBScriptLocatorGetAgent(SBScriptLocatorRef locator)
{
return &locator->agent;
}
static void ResolveScriptRun(SBScriptLocatorRef locator, SBUInteger offset)
{
const SBCodepointSequence *sequence = &locator->_codepointSequence;
ScriptStackRef stack = &locator->_scriptStack;
SBScript result = SBScriptZYYY;
SBUInteger current = offset;
SBUInteger next = offset;
SBCodepoint codepoint;
/* Iterate over the code points of specified string buffer. */
while ((codepoint = SBCodepointSequenceGetCodepointAt(sequence, &next)) != SBCodepointInvalid) {
SBBoolean isStacked = SBFalse;
SBScript script;
script = LookupScript(codepoint);
/* Handle paired punctuations in case of a common script. */
if (script == SBScriptZYYY) {
SBGeneralCategory generalCategory = LookupGeneralCategory(codepoint);
/* Check if current code point is an open punctuation. */
if (generalCategory == SBGeneralCategoryPS) {
SBCodepoint mirror = LookupMirror(codepoint);
if (mirror) {
/* A closing pair exists for this punctuation, so push it onto the stack. */
ScriptStackPush(stack, result, mirror);
}
}
/* Check if current code point is a close punctuation. */
else if (generalCategory == SBGeneralCategoryPE) {
SBBoolean isMirrored = (LookupMirror(codepoint) != 0);
if (isMirrored) {
/* Find the matching entry in the stack, while popping the unmatched ones. */
while (!ScriptStackIsEmpty(stack)) {
SBCodepoint mirror = ScriptStackGetMirror(stack);
if (mirror != codepoint) {
ScriptStackPop(stack);
} else {
break;
}
}
if (!ScriptStackIsEmpty(stack)) {
isStacked = SBTrue;
/* Paired punctuation match the script of enclosing text. */
script = ScriptStackGetScript(stack);
}
}
}
}
if (IsSimilarScript(result, script)) {
if (SBScriptIsCommonOrInherited(result) && !SBScriptIsCommonOrInherited(script)) {
/* Set the concrete script of this code point as the result. */
result = script;
/* Seal the pending punctuations with the result. */
ScriptStackSealPairs(stack, result);
}
if (isStacked) {
/* Pop the paired punctuation from the stack. */
ScriptStackPop(stack);
}
} else {
/* The current code point has a different script, so finish the run. */
break;
}
current = next;
}
ScriptStackLeavePairs(stack);
/* Set the run info in agent. */
locator->agent.offset = offset;
locator->agent.length = current - offset;
locator->agent.script = result;
}
SBBoolean SBScriptLocatorMoveNext(SBScriptLocatorRef locator)
{
SBUInteger offset = locator->agent.offset + locator->agent.length;
if (offset < locator->_codepointSequence.stringLength) {
ResolveScriptRun(locator, offset);
return SBTrue;
}
SBScriptLocatorReset(locator);
return SBFalse;
}
void SBScriptLocatorReset(SBScriptLocatorRef locator)
{
ScriptStackReset(&locator->_scriptStack);
locator->agent.offset = 0;
locator->agent.length = 0;
locator->agent.script = SBScriptNil;
}
SBScriptLocatorRef SBScriptLocatorRetain(SBScriptLocatorRef locator)
{
if (locator) {
locator->retainCount += 1;
}
return locator;
}
void SBScriptLocatorRelease(SBScriptLocatorRef locator)
{
if (locator && --locator->retainCount == 0) {
free(locator);
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2018-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_SCRIPT_LOCATOR_H
#define _SB_INTERNAL_SCRIPT_LOCATOR_H
#include <SBBase.h>
#include <SBCodepointSequence.h>
#include <SBScriptLocator.h>
#include "ScriptStack.h"
typedef struct _SBScriptLocator {
SBCodepointSequence _codepointSequence;
ScriptStack _scriptStack;
SBScriptAgent agent;
SBUInteger retainCount;
} SBScriptLocator;
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,16 @@
/*
* Automatically generated by SheenBidiGenerator tool.
* DO NOT EDIT!!
*/
#ifndef _SB_INTERNAL_SCRIPT_LOOKUP_H
#define _SB_INTERNAL_SCRIPT_LOOKUP_H
#include <SBConfig.h>
#include <SBScript.h>
#include "SBBase.h"
SB_INTERNAL SBScript LookupScript(SBCodepoint codepoint);
#endif

View file

@ -0,0 +1,83 @@
/*
* Copyright (C) 2018-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include "SBAssert.h"
#include "SBBase.h"
#include "ScriptStack.h"
SB_INTERNAL void ScriptStackReset(ScriptStackRef stack)
{
stack->top = -1;
stack->count = 0;
stack->open = 0;
}
SB_INTERNAL void ScriptStackPush(ScriptStackRef stack, SBScript script, SBCodepoint mirror)
{
stack->count = SBNumberLimitIncrement(stack->count, _SBScriptStackCapacity);
stack->open = SBNumberLimitIncrement(stack->open, _SBScriptStackCapacity);
stack->top = SBNumberRingIncrement(stack->top, _SBScriptStackCapacity);
stack->_elements[stack->top].script = script;
stack->_elements[stack->top].mirror = mirror;
}
SB_INTERNAL void ScriptStackPop(ScriptStackRef stack)
{
/* There must be at least one entry in the stack. */
SBAssert(stack->count > 0);
stack->count -= 1;
stack->open = SBNumberLimitDecrement(stack->open, 0);
stack->top = SBNumberRingDecrement(stack->top, _SBScriptStackCapacity);
if (ScriptStackIsEmpty(stack)) {
stack->top = -1;
}
}
SB_INTERNAL void ScriptStackLeavePairs(ScriptStackRef stack)
{
stack->open = 0;
}
SB_INTERNAL void ScriptStackSealPairs(ScriptStackRef stack, SBScript script)
{
SBInteger index = SBNumberRingSubtract(stack->top, (SBInteger)stack->open, _SBScriptStackCapacity);
while (stack->open) {
index = SBNumberRingIncrement(index, _SBScriptStackCapacity);
stack->_elements[index].script = script;
stack->open -= 1;
}
}
SB_INTERNAL SBBoolean ScriptStackIsEmpty(ScriptStackRef stack)
{
return (stack->count == 0);
}
SB_INTERNAL SBScript ScriptStackGetScript(ScriptStackRef stack)
{
return stack->_elements[stack->top].script;
}
SB_INTERNAL SBCodepoint ScriptStackGetMirror(ScriptStackRef stack)
{
return stack->_elements[stack->top].mirror;
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2018-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_SCRIPT_STACK_H
#define _SB_INTERNAL_SCRIPT_STACK_H
#include <SBBase.h>
#include <SBConfig.h>
#define _SBScriptStackCapacity 63
typedef struct _SBScriptStackElement {
SBScript script;
SBCodepoint mirror;
} _SBScriptStackElement;
typedef struct _SBScriptStack {
_SBScriptStackElement _elements[_SBScriptStackCapacity];
SBInteger top;
SBUInteger count;
SBUInteger open;
} ScriptStack, *ScriptStackRef;
SB_INTERNAL void ScriptStackReset(ScriptStackRef stack);
SB_INTERNAL void ScriptStackPush(ScriptStackRef stack, SBScript script, SBCodepoint mirror);
SB_INTERNAL void ScriptStackPop(ScriptStackRef stack);
SB_INTERNAL void ScriptStackLeavePairs(ScriptStackRef stack);
SB_INTERNAL void ScriptStackSealPairs(ScriptStackRef stack, SBScript script);
SB_INTERNAL SBBoolean ScriptStackIsEmpty(ScriptStackRef stack);
SB_INTERNAL SBScript ScriptStackGetScript(ScriptStackRef stack);
SB_INTERNAL SBCodepoint ScriptStackGetMirror(ScriptStackRef stack);
#endif

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2014-2019 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <SheenBidi.h>
#ifdef SB_CONFIG_UNITY
#include "BidiChain.c"
#include "BidiTypeLookup.c"
#include "BracketQueue.c"
#include "GeneralCategoryLookup.c"
#include "IsolatingRun.c"
#include "LevelRun.c"
#include "PairingLookup.c"
#include "RunQueue.c"
#include "SBAlgorithm.c"
#include "SBBase.c"
#include "SBCodepointSequence.c"
#include "SBLine.c"
#include "SBLog.c"
#include "SBMirrorLocator.c"
#include "SBParagraph.c"
#include "SBScriptLocator.c"
#include "ScriptLookup.c"
#include "ScriptStack.c"
#include "StatusStack.c"
#endif

View file

@ -0,0 +1,124 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <SBConfig.h>
#include <stddef.h>
#include <stdlib.h>
#include "SBAssert.h"
#include "SBBase.h"
#include "StatusStack.h"
static SBBoolean StatusStackInsertElement(StatusStackRef stack)
{
if (stack->_peekTop != _StatusStackList_MaxIndex) {
stack->_peekTop += 1;
} else {
_StatusStackListRef previousList = stack->_peekList;
_StatusStackListRef peekList = previousList->next;
if (!peekList) {
peekList = malloc(sizeof(_StatusStackList));
if (!peekList) {
return SBFalse;
}
peekList->previous = previousList;
peekList->next = NULL;
previousList->next = peekList;
}
stack->_peekList = peekList;
stack->_peekTop = 0;
}
stack->count += 1;
return SBTrue;
}
SB_INTERNAL void StatusStackInitialize(StatusStackRef stack)
{
stack->_firstList.previous = NULL;
stack->_firstList.next = NULL;
StatusStackSetEmpty(stack);
}
SB_INTERNAL SBBoolean StatusStackPush(StatusStackRef stack,
SBLevel embeddingLevel, SBBidiType overrideStatus, SBBoolean isolateStatus)
{
/* The stack can hold upto 127 elements. */
SBAssert(stack->count <= 127);
if (StatusStackInsertElement(stack)) {
_StatusStackElementRef element = &stack->_peekList->elements[stack->_peekTop];
element->embeddingLevel = embeddingLevel;
element->overrideStatus = overrideStatus;
element->isolateStatus = isolateStatus;
return SBTrue;
}
return SBFalse;
}
SB_INTERNAL void StatusStackPop(StatusStackRef stack)
{
/* The stack should not be empty. */
SBAssert(stack->count != 0);
if (stack->_peekTop != 0) {
stack->_peekTop -= 1;
} else {
stack->_peekList = stack->_peekList->previous;
stack->_peekTop = _StatusStackList_MaxIndex;
}
stack->count -= 1;
}
SB_INTERNAL void StatusStackSetEmpty(StatusStackRef stack)
{
stack->_peekList = &stack->_firstList;
stack->_peekTop = 0;
stack->count = 0;
}
SB_INTERNAL SBLevel StatusStackGetEmbeddingLevel(StatusStackRef stack)
{
return stack->_peekList->elements[stack->_peekTop].embeddingLevel;
}
SB_INTERNAL SBBidiType StatusStackGetOverrideStatus(StatusStackRef stack)
{
return stack->_peekList->elements[stack->_peekTop].overrideStatus;
}
SB_INTERNAL SBBoolean StatusStackGetIsolateStatus(StatusStackRef stack)
{
return stack->_peekList->elements[stack->_peekTop].isolateStatus;
}
SB_INTERNAL void StatusStackFinalize(StatusStackRef stack)
{
_StatusStackListRef list = stack->_firstList.next;
while (list) {
_StatusStackListRef next = list->next;
free(list);
list = next;
};
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2014-2022 Muhammad Tayyab Akram
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _SB_INTERNAL_STATUS_STACK_H
#define _SB_INTERNAL_STATUS_STACK_H
#include <SBConfig.h>
#include "SBBase.h"
#define _StatusStackList_Length 16
#define _StatusStackList_MaxIndex (_StatusStackList_Length - 1)
typedef struct _StatusStackElement {
SBBoolean isolateStatus;
SBBidiType overrideStatus;
SBLevel embeddingLevel;
} _StatusStackElement, *_StatusStackElementRef;
typedef struct _StatusStackList {
_StatusStackElement elements[_StatusStackList_Length];
struct _StatusStackList *previous;
struct _StatusStackList *next;
} _StatusStackList, *_StatusStackListRef;
typedef struct _StatusStack {
_StatusStackList _firstList;
_StatusStackListRef _peekList;
SBUInteger _peekTop;
SBUInteger count;
} StatusStack, *StatusStackRef;
SB_INTERNAL void StatusStackInitialize(StatusStackRef stack);
SB_INTERNAL void StatusStackFinalize(StatusStackRef stack);
SB_INTERNAL SBBoolean StatusStackPush(StatusStackRef stack,
SBLevel embeddingLevel, SBBidiType overrideStatus, SBBoolean isolateStatus);
SB_INTERNAL void StatusStackPop(StatusStackRef stack);
SB_INTERNAL void StatusStackSetEmpty(StatusStackRef stack);
SB_INTERNAL SBLevel StatusStackGetEmbeddingLevel(StatusStackRef stack);
SB_INTERNAL SBBidiType StatusStackGetOverrideStatus(StatusStackRef stack);
SB_INTERNAL SBBoolean StatusStackGetIsolateStatus(StatusStackRef stack);
#endif