summaryrefslogtreecommitdiff
path: root/bidi.cc
blob: 36ceb8ae34c3785f9d6a0cbc639ddd74c14d253c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright (C) 2003 Mooffie <mooffie@typo.co.il>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.

#include <config.h>

#include "bidi.h"
#include "dbg.h"

static ctype_t fribidi_dir(direction_t dir)
{
    switch (dir) {
    case dirLTR:  return FRIBIDI_TYPE_LTR;
    case dirRTL:  return FRIBIDI_TYPE_RTL;
    default:      return FRIBIDI_TYPE_ON;
    }
}

void BiDi::get_embedding_levels(unichar *str, idx_t len,
				direction_t dir,
				level_t *levels,
				int line_breaks_count,
				idx_t *line_breaks,
				bool disable_bidi)
{
    if (disable_bidi) {
	for (idx_t i = len-1; i >= 0; i--)
	    levels[i] = (dir == dirRTL) ? 1 :0;
    } else {
	ctype_t base_dir = fribidi_dir(dir);
	fribidi_log2vis_get_embedding_levels(str, len, &base_dir, levels);
    }

    // Do rule L1.4 of TR9: wspaces at end of lines.
    level_t para_embedding_level = (dir == dirRTL ? 1 : 0);
    int prev_line_break = 0;
    for (int i = 0; i < line_breaks_count; i++) {
	int pos = (int)line_breaks[i] - 1;
	while (pos >= prev_line_break && is_space(str[pos])) {
	    levels[pos] = para_embedding_level;
	    pos--;
	}
	prev_line_break = line_breaks[i];
    }
}

static void xsimple_log2vis(unichar *str, idx_t len, direction_t dir,
			    unichar *dest)
{
    ctype_t base_dir = fribidi_dir(dir);
    fribidi_log2vis(str, len, &base_dir, dest, NULL, NULL, NULL);
}

void BiDi::simple_log2vis(unistring &str, direction_t dir, unistring &dest)
{
    dest.resize(str.size() + 1); // fribidi_log2vis needs "+1" !!!!!!!!!!!!!
    xsimple_log2vis(str.begin(), str.size(), dir, dest.begin());
    dest.resize(str.size());
}

// determine_base_dir() - determines the base direction of a string.
// We provide the user with several algorithms. algoUnicode is described
// in P2,3 of TR9.
// 
// algoContext's implementation is divided into two: half is here and
// the other half is in EditBox::calc_contextual_dirs(). See documentation
// there.

direction_t BiDi::determine_base_dir(unichar *str, idx_t len,
				     diralgo_t dir_algo)
{
    ctype_t ctype;
    switch (dir_algo) {
	case algoContextRTL:
	{
	    // - if there's any RTL letter, set direction to LTR;
	    // - else: if there's any LTR letter, set direction to LTR;
	    // - else: set direction to neutral.
	    bool found_LTR = false;
	    for (idx_t i = 0; i < len; i++) {
		ctype = fribidi_get_type(str[i]);
		if (FRIBIDI_IS_LETTER(ctype)) {
		    if (FRIBIDI_IS_RTL(ctype))
			return dirRTL;
		    else
			found_LTR = true;
		}
	    }
	    if (found_LTR)
		return dirLTR;
	    else
		return dirN;
	}
	
	case algoUnicode:
	case algoContextStrong:
	{
	    // directionality is determined by the first strong letter.
	    for (idx_t i = 0; i < len; i++) {
		ctype = fribidi_get_type(str[i]);
		if (FRIBIDI_IS_LETTER(ctype)) {
		    if (FRIBIDI_IS_RTL(ctype))
			return dirRTL;
		    else
			return dirLTR;
		}
	    }
	    if (dir_algo == algoContextStrong)
		return dirN;
	    else
		return dirLTR;
	}

        case algoForceRTL:

	    return dirRTL;

	case algoForceLTR:
	default:

	    return dirLTR;
    };
}