1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_i18npool.hxx"
26 
27 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
28 #include <breakiterator_ctl.hxx>
29 
30 #include <string.h>	// for memset
31 
32 using namespace ::com::sun::star::uno;
33 using namespace ::com::sun::star::lang;
34 using namespace ::rtl;
35 
36 namespace com { namespace sun { namespace star { namespace i18n {
37 
38 /**
39  * Constructor.
40  */
BreakIterator_CTL()41 BreakIterator_CTL::BreakIterator_CTL() :
42     cachedText(),
43     nextCellIndex( NULL ),
44     previousCellIndex( NULL ),
45     cellIndexSize( 512 )
46 {
47 	cBreakIterator = "com.sun.star.i18n.BreakIterator_CTL";
48 	// to improve performance, alloc big enough memory in construct.
49 	nextCellIndex = (sal_Int32*) calloc(cellIndexSize, sizeof(sal_Int32));
50 	previousCellIndex = (sal_Int32*) calloc(cellIndexSize, sizeof(sal_Int32));
51 	memset(nextCellIndex, 0, cellIndexSize * sizeof(sal_Int32));
52 }
53 
54 /**
55  * Deconstructor.
56  */
~BreakIterator_CTL()57 BreakIterator_CTL::~BreakIterator_CTL()
58 {
59 	free(nextCellIndex);
60 	free(previousCellIndex);
61 }
62 
previousCharacters(const OUString & Text,sal_Int32 nStartPos,const lang::Locale & rLocale,sal_Int16 nCharacterIteratorMode,sal_Int32 nCount,sal_Int32 & nDone)63 sal_Int32 SAL_CALL BreakIterator_CTL::previousCharacters( const OUString& Text,
64 	sal_Int32 nStartPos, const lang::Locale& rLocale,
65 	sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone )
66 	throw(RuntimeException)
67 {
68 	if (nCharacterIteratorMode == CharacterIteratorMode::SKIPCELL ) {
69 	    nDone = 0;
70 	    if (nStartPos > 0) { 	// for others to skip cell.
71 		makeIndex(Text, nStartPos);
72 
73 		if (nextCellIndex[nStartPos-1] == 0) // not a CTL character
74 		    return BreakIterator_Unicode::previousCharacters(Text, nStartPos, rLocale,
75 				nCharacterIteratorMode, nCount, nDone);
76 		else while (nCount > 0 && nextCellIndex[nStartPos - 1] > 0) {
77 		    nCount--; nDone++;
78 		    nStartPos = previousCellIndex[nStartPos - 1];
79 		}
80 	    } else
81 		nStartPos = 0;
82 	} else { // for BS to delete one char.
83 	    nDone = (nStartPos > nCount) ? nCount : nStartPos;
84 	    nStartPos -= nDone;
85 	}
86 
87 	return nStartPos;
88 }
89 
nextCharacters(const OUString & Text,sal_Int32 nStartPos,const lang::Locale & rLocale,sal_Int16 nCharacterIteratorMode,sal_Int32 nCount,sal_Int32 & nDone)90 sal_Int32 SAL_CALL BreakIterator_CTL::nextCharacters(const OUString& Text,
91 	sal_Int32 nStartPos, const lang::Locale& rLocale,
92 	sal_Int16 nCharacterIteratorMode, sal_Int32 nCount, sal_Int32& nDone)
93 	throw(RuntimeException)
94 {
95 	sal_Int32 len = Text.getLength();
96 	if (nCharacterIteratorMode == CharacterIteratorMode::SKIPCELL ) {
97 	    nDone = 0;
98 	    if (nStartPos < len) {
99 		makeIndex(Text, nStartPos);
100 
101 		if (nextCellIndex[nStartPos] == 0) // not a CTL character
102 		    return BreakIterator_Unicode::nextCharacters(Text, nStartPos, rLocale,
103 				nCharacterIteratorMode, nCount, nDone);
104 		else while (nCount > 0 && nextCellIndex[nStartPos] > 0) {
105 		    nCount--; nDone++;
106 		    nStartPos = nextCellIndex[nStartPos];
107 		}
108 	    } else
109 		nStartPos = len;
110 	} else {
111 	    nDone = (len - nStartPos > nCount) ? nCount : len - nStartPos;
112 	    nStartPos += nDone;
113 	}
114 
115 	return nStartPos;
116 }
117 
118 // This method should be overwritten by derived language specific class.
makeIndex(const OUString &,sal_Int32)119 void SAL_CALL BreakIterator_CTL::makeIndex(const OUString& /*text*/, sal_Int32 /*pos*/)
120 	throw(RuntimeException)
121 {
122 	throw RuntimeException();
123 }
124 
125 // Make sure line is broken on cell boundary if we implement cell iterator.
getLineBreak(const OUString & Text,sal_Int32 nStartPos,const lang::Locale & rLocale,sal_Int32 nMinBreakPos,const LineBreakHyphenationOptions & hOptions,const LineBreakUserOptions & bOptions)126 LineBreakResults SAL_CALL BreakIterator_CTL::getLineBreak(
127 	const OUString& Text, sal_Int32 nStartPos,
128 	const lang::Locale& rLocale, sal_Int32 nMinBreakPos,
129 	const LineBreakHyphenationOptions& hOptions,
130 	const LineBreakUserOptions& bOptions ) throw(RuntimeException)
131 {
132 	LineBreakResults lbr = BreakIterator_Unicode::getLineBreak(Text, nStartPos,
133 					rLocale, nMinBreakPos, hOptions, bOptions );
134     if (lbr.breakIndex < Text.getLength()) {
135         makeIndex(Text, lbr.breakIndex);
136         lbr.breakIndex = previousCellIndex[ lbr.breakIndex ];
137     }
138 	return lbr;
139 }
140 
141 } } } }
142