Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <ctype.h>
30 : :
31 : : #include <com/sun/star/i18n/ScriptType.hpp>
32 : : #include <i18npool/mslangid.hxx>
33 : : #include <hintids.hxx> // CH_TXTATR
34 : : #include <SwPortionHandler.hxx>
35 : : #include <porlay.hxx>
36 : : #include <inftxt.hxx>
37 : : #include <guess.hxx> // SwTxtGuess, line break
38 : : #include <porglue.hxx>
39 : : #include <portab.hxx> // pLastTab->
40 : : #include <porfld.hxx> // SwFldPortion
41 : : #include <wrong.hxx>
42 : : #include <viewsh.hxx>
43 : : #include <IDocumentSettingAccess.hxx>
44 : : #include <viewopt.hxx> // SwViewOptions
45 : :
46 : : #include <IMark.hxx>
47 : : #include <pam.hxx>
48 : : #include <doc.hxx>
49 : : #include <xmloff/odffields.hxx>
50 : :
51 : : using namespace ::sw::mark;
52 : : using namespace ::com::sun::star;
53 : : using namespace ::com::sun::star::i18n::ScriptType;
54 : :
55 : : /*************************************************************************
56 : : * lcl_AddSpace
57 : : * Returns for how many characters an extra space has to be added
58 : : * (for justified alignment).
59 : : *************************************************************************/
60 : :
61 : 60 : sal_uInt16 lcl_AddSpace( const SwTxtSizeInfo &rInf, const XubString* pStr,
62 : : const SwLinePortion& rPor )
63 : : {
64 : : xub_StrLen nPos, nEnd;
65 : 60 : const SwScriptInfo* pSI = 0;
66 : :
67 [ - + ]: 60 : if ( pStr )
68 : : {
69 : : // passing a string means we are inside a field
70 : 0 : nPos = 0;
71 : 0 : nEnd = pStr->Len();
72 : : }
73 : : else
74 : : {
75 : 60 : nPos = rInf.GetIdx();
76 : 60 : nEnd = rInf.GetIdx() + rPor.GetLen();
77 : 60 : pStr = &rInf.GetTxt();
78 : 60 : pSI = &((SwParaPortion*)rInf.GetParaPortion())->GetScriptInfo();
79 : : }
80 : :
81 : 60 : sal_uInt16 nCnt = 0;
82 : 60 : sal_uInt8 nScript = 0;
83 : :
84 : : // If portion consists of Asian characters and language is not
85 : : // Korean, we add extra space to each character.
86 : : // first we get the script type
87 [ + - ]: 60 : if ( pSI )
88 : 60 : nScript = pSI->ScriptType( nPos );
89 [ # # ]: 0 : else if ( pBreakIt->GetBreakIter().is() )
90 [ # # ][ # # ]: 0 : nScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( *pStr, nPos );
[ # # ]
91 : :
92 : : // Note: rInf.GetIdx() can differ from nPos,
93 : : // e.g., when rPor is a field portion. nPos referes to the string passed
94 : : // to the function, rInf.GetIdx() referes to the original string.
95 : :
96 : : // We try to find out which justification mode is required. This is done by
97 : : // evaluating the script type and the language attribute set for this portion
98 : :
99 : : // Asian Justification: Each character get some extra space
100 [ + + ][ - + ]: 60 : if ( nEnd > nPos && ASIAN == nScript )
101 : : {
102 : : LanguageType aLang =
103 : 0 : rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
104 : :
105 [ # # ]: 0 : if (MsLangId::isKorean(aLang))
106 : : {
107 : 0 : const SwLinePortion* pPor = rPor.GetPortion();
108 [ # # # # : 0 : if ( pPor && ( pPor->IsKernPortion() ||
# # ][ # # ]
[ # # ]
109 : 0 : pPor->IsControlCharPortion() ||
110 : 0 : pPor->IsPostItsPortion() ) )
111 : 0 : pPor = pPor->GetPortion();
112 : :
113 : 0 : nCnt += nEnd - nPos;
114 : :
115 [ # # ][ # # ]: 0 : if ( !pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ||
[ # # # # ]
[ # # ]
116 : 0 : pPor->IsBreakPortion() )
117 : 0 : --nCnt;
118 : :
119 : 0 : return nCnt;
120 : : }
121 : : }
122 : :
123 : : // Kashida Justification: Insert Kashidas
124 [ + + ][ + - ]: 60 : if ( nEnd > nPos && pSI && COMPLEX == nScript )
[ - + ]
125 : : {
126 [ # # ][ # # ]: 0 : if ( SwScriptInfo::IsArabicText( *pStr, nPos, nEnd - nPos ) && pSI->CountKashida() )
[ # # ][ # # ]
[ # # ]
[ # # # # ]
127 : : {
128 : 0 : const sal_uInt16 nKashRes = pSI->KashidaJustify( 0, 0, nPos, nEnd - nPos );
129 : : // i60591: need to check result of KashidaJustify
130 : : // determine if kashida justification is applicable
131 [ # # ]: 0 : if( nKashRes != STRING_LEN )
132 : 0 : return nKashRes;
133 : : }
134 : : }
135 : :
136 : : // Thai Justification: Each character cell gets some extra space
137 [ + + ][ - + ]: 60 : if ( nEnd > nPos && COMPLEX == nScript )
138 : : {
139 : : LanguageType aLang =
140 : 0 : rInf.GetTxtFrm()->GetTxtNode()->GetLang( rInf.GetIdx(), 1, nScript );
141 : :
142 [ # # ]: 0 : if ( LANGUAGE_THAI == aLang )
143 : : {
144 [ # # ]: 0 : nCnt = SwScriptInfo::ThaiJustify( *pStr, 0, 0, nPos, nEnd - nPos );
145 : :
146 : 0 : const SwLinePortion* pPor = rPor.GetPortion();
147 [ # # # # : 0 : if ( pPor && ( pPor->IsKernPortion() ||
# # ][ # # ]
[ # # ]
148 : 0 : pPor->IsControlCharPortion() ||
149 : 0 : pPor->IsPostItsPortion() ) )
150 : 0 : pPor = pPor->GetPortion();
151 : :
152 [ # # ][ # # ]: 0 : if ( nCnt && ( ! pPor || pPor->IsHolePortion() || pPor->InFixMargGrp() ) )
[ # # ][ # # ]
[ # # ]
153 : 0 : --nCnt;
154 : :
155 : 0 : return nCnt;
156 : : }
157 : : }
158 : :
159 : : // Here starts the good old "Look for blanks and add space to them" part.
160 : : // Note: We do not want to add space to an isolated latin blank in front
161 : : // of some complex characters in RTL environment
162 : : const sal_Bool bDoNotAddSpace =
163 : : LATIN == nScript && ( nEnd == nPos + 1 ) && pSI &&
164 : : ( i18n::ScriptType::COMPLEX ==
165 : 0 : pSI->ScriptType( nPos + 1 ) ) &&
166 [ + - ][ - + ]: 60 : rInf.GetTxtFrm() && rInf.GetTxtFrm()->IsRightToLeft();
[ # # # # ]
[ # # ][ # # ]
167 : :
168 [ - + ]: 60 : if ( bDoNotAddSpace )
169 : 0 : return nCnt;
170 : :
171 [ + + ]: 340 : for ( ; nPos < nEnd; ++nPos )
172 : : {
173 [ - + ]: 280 : if( CH_BLANK == pStr->GetChar( nPos ) )
174 : 0 : ++nCnt;
175 : : }
176 : :
177 : : // We still have to examine the next character:
178 : : // If the next character is ASIAN and not KOREAN we have
179 : : // to add an extra space
180 : : // nPos referes to the original string, even if a field string has
181 : : // been passed to this function
182 : 60 : nPos = rInf.GetIdx() + rPor.GetLen();
183 [ - + ]: 60 : if ( nPos < rInf.GetTxt().Len() )
184 : : {
185 : 0 : sal_uInt8 nNextScript = 0;
186 : 0 : const SwLinePortion* pPor = rPor.GetPortion();
187 [ # # ][ # # ]: 0 : if ( pPor && pPor->IsKernPortion() )
[ # # ]
188 : 0 : pPor = pPor->GetPortion();
189 : :
190 [ # # ][ # # ]: 0 : if ( ! pBreakIt->GetBreakIter().is() || ! pPor || pPor->InFixMargGrp() )
[ # # ][ # # ]
[ # # ]
[ # # # # ]
191 : 0 : return nCnt;
192 : :
193 : : // next character is inside a field?
194 [ # # ][ # # ]: 0 : if ( CH_TXTATR_BREAKWORD == rInf.GetChar( nPos ) && pPor->InExpGrp() )
[ # # ]
195 : : {
196 : 0 : sal_Bool bOldOnWin = rInf.OnWin();
197 : 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False );
198 : :
199 [ # # ]: 0 : XubString aStr( aEmptyStr );
200 [ # # ]: 0 : pPor->GetExpTxt( rInf, aStr );
201 : 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
202 : :
203 [ # # ][ # # ]: 0 : nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( aStr, 0 );
[ # # ][ # # ]
[ # # ]
204 : : }
205 : : else
206 [ # # ][ # # ]: 0 : nNextScript = (sal_uInt8)pBreakIt->GetBreakIter()->getScriptType( rInf.GetTxt(), nPos );
[ # # ]
207 : :
208 [ # # ]: 0 : if( ASIAN == nNextScript )
209 : : {
210 : : LanguageType aLang =
211 : 0 : rInf.GetTxtFrm()->GetTxtNode()->GetLang( nPos, 1, nNextScript );
212 : :
213 [ # # ]: 0 : if (MsLangId::isKorean(aLang))
214 : 0 : ++nCnt;
215 : : }
216 : : }
217 : :
218 : 60 : return nCnt;
219 : : }
220 : :
221 : : /*************************************************************************
222 : : * class SwTxtPortion
223 : : *************************************************************************/
224 : :
225 : 2901 : SwTxtPortion::SwTxtPortion( const SwLinePortion &rPortion )
226 : 2901 : : SwLinePortion( rPortion )
227 : : {
228 : 2901 : SetWhichPor( POR_TXT );
229 : 2901 : }
230 : :
231 : : /*************************************************************************
232 : : * SwTxtPortion::BreakCut()
233 : : *************************************************************************/
234 : :
235 : 17701 : void SwTxtPortion::BreakCut( SwTxtFormatInfo &rInf, const SwTxtGuess &rGuess )
236 : : {
237 : : // The word/char is larger than the line
238 : : // Special case 1: The word is larger than the line
239 : : // We truncate ...
240 : 17701 : const KSHORT nLineWidth = (KSHORT)(rInf.Width() - rInf.X());
241 : 17701 : xub_StrLen nLen = rGuess.CutPos() - rInf.GetIdx();
242 [ + + ]: 17701 : if( nLen )
243 : : {
244 : : // special case: guess does not always provide the correct
245 : : // width, only in common cases.
246 [ + + ]: 15991 : if ( !rGuess.BreakWidth() )
247 : : {
248 : 133 : rInf.SetLen( nLen );
249 : 133 : SetLen( nLen );
250 : 133 : CalcTxtSize( rInf );
251 : :
252 : : // changing these values requires also changing them in
253 : : // guess.cxx
254 : 133 : KSHORT nItalic = 0;
255 [ # # ][ - + ]: 133 : if( ITALIC_NONE != rInf.GetFont()->GetItalic() && !rInf.NotEOL() )
[ - + ]
256 : : {
257 : 0 : nItalic = Height() / 12;
258 : : }
259 : 133 : Width( Width() + nItalic );
260 : : }
261 : : else
262 : : {
263 : 15858 : Width( rGuess.BreakWidth() );
264 : 15858 : SetLen( nLen );
265 : : }
266 : : }
267 : : // special case: first character does not fit to line
268 [ + - ]: 1710 : else if ( rGuess.CutPos() == rInf.GetLineStart() )
269 : : {
270 : 1710 : SetLen( 1 );
271 : 1710 : Width( nLineWidth );
272 : : }
273 : : else
274 : : {
275 : 0 : SetLen( 0 );
276 : 0 : Width( 0 );
277 : : }
278 : 17701 : }
279 : :
280 : : /*************************************************************************
281 : : * SwTxtPortion::BreakUnderflow()
282 : : *************************************************************************/
283 : :
284 : 0 : void SwTxtPortion::BreakUnderflow( SwTxtFormatInfo &rInf )
285 : : {
286 : 0 : Truncate();
287 : 0 : Height( 0 );
288 : 0 : Width( 0 );
289 : 0 : SetLen( 0 );
290 : 0 : SetAscent( 0 );
291 : 0 : rInf.SetUnderFlow( this );
292 : 0 : }
293 : :
294 : : /*************************************************************************
295 : : * SwTxtPortion::_Format()
296 : : *************************************************************************/
297 : :
298 : 0 : sal_Bool lcl_HasContent( const SwFldPortion& rFld, SwTxtFormatInfo &rInf )
299 : : {
300 [ # # ]: 0 : String aTxt;
301 [ # # ][ # # ]: 0 : return rFld.GetExpTxt( rInf, aTxt ) && aTxt.Len();
[ # # ][ # # ]
302 : : }
303 : :
304 : 52281 : sal_Bool SwTxtPortion::_Format( SwTxtFormatInfo &rInf )
305 : : {
306 : : // 5744: If only the hypen does not fit anymore, we still need to wrap
307 : : // the word, or else return sal_True!
308 [ - + ][ # # ]: 52281 : if( rInf.IsUnderFlow() && rInf.GetSoftHyphPos() )
[ - + ]
309 : : {
310 : : // soft hyphen portion has triggered an underflow event because
311 : : // of an alternative spelling position
312 : 0 : sal_Bool bFull = sal_False;
313 [ # # ]: 0 : const sal_Bool bHyph = rInf.ChgHyph( sal_True );
314 [ # # ][ # # ]: 0 : if( rInf.IsHyphenate() )
315 : : {
316 [ # # ]: 0 : SwTxtGuess aGuess;
317 : : // check for alternative spelling left from the soft hyphen
318 : : // this should usually be true but
319 [ # # ]: 0 : aGuess.AlternativeSpelling( rInf, rInf.GetSoftHyphPos() - 1 );
320 [ # # ]: 0 : bFull = CreateHyphen( rInf, aGuess );
321 [ # # ]: 0 : OSL_ENSURE( bFull, "Problem with hyphenation!!!" );
322 : : }
323 [ # # ]: 0 : rInf.ChgHyph( bHyph );
324 : 0 : rInf.SetSoftHyphPos( 0 );
325 : 0 : return bFull;
326 : : }
327 : :
328 [ + - ]: 52281 : SwTxtGuess aGuess;
329 [ + - ]: 52281 : const sal_Bool bFull = !aGuess.Guess( *this, rInf, Height() );
330 : :
331 : : // these are the possible cases:
332 : : // A Portion fits to current line
333 : : // B Portion does not fit to current line but a possible line break
334 : : // within the portion has been found by the break iterator, 2 subcases
335 : : // B1 break is hyphen
336 : : // B2 break is word end
337 : : // C Portion does not fit to current line and no possible line break
338 : : // has been found by break iterator, 2 subcases:
339 : : // C1 break iterator found a possible line break in portion before us
340 : : // ==> this break is used (underflow)
341 : : // C2 break iterator does not found a possible line break at all:
342 : : // ==> line break
343 : :
344 : : // case A: line not yet full
345 [ + + ]: 52281 : if ( !bFull )
346 : : {
347 : 11392 : Width( aGuess.BreakWidth() );
348 : : // Vorsicht !
349 [ + + ][ + + ]: 11392 : if( !InExpGrp() || InFldGrp() )
[ + + ]
350 : 11374 : SetLen( rInf.GetLen() );
351 : :
352 [ + - ]: 11392 : short nKern = rInf.GetFont()->CheckKerning();
353 [ + + ][ - + ]: 11392 : if( nKern > 0 && rInf.Width() < rInf.X() + Width() + nKern )
[ - + ]
354 : : {
355 : 0 : nKern = (short)(rInf.Width() - rInf.X() - Width() - 1);
356 [ # # ]: 0 : if( nKern < 0 )
357 : 0 : nKern = 0;
358 : : }
359 [ + + ]: 11392 : if( nKern )
360 [ + - ][ + - ]: 256 : new SwKernPortion( *this, nKern );
361 : : }
362 : : // special case: hanging portion
363 [ + - ][ - + ]: 40889 : else if( bFull && aGuess.GetHangingPortion() )
[ - + ]
364 : : {
365 : 0 : Width( aGuess.BreakWidth() );
366 : 0 : SetLen( aGuess.BreakPos() - rInf.GetIdx() );
367 [ # # ]: 0 : Insert( aGuess.GetHangingPortion() );
368 : 0 : aGuess.GetHangingPortion()->SetAscent( GetAscent() );
369 : 0 : aGuess.ClearHangingPortion();
370 : : }
371 : : // breakPos >= index
372 [ + - ][ + + ]: 40889 : else if ( aGuess.BreakPos() >= rInf.GetIdx() && aGuess.BreakPos() != STRING_LEN )
[ + + ]
373 : : {
374 : : // case B1
375 [ + - ][ - + ]: 23347 : if( aGuess.HyphWord().is() && aGuess.BreakPos() > rInf.GetLineStart()
[ # # # #
# # # # ]
[ + - ]
[ - + # # ]
376 : 0 : && ( aGuess.BreakPos() > rInf.GetIdx() ||
377 : 0 : ( rInf.GetLast() && ! rInf.GetLast()->IsFlyPortion() ) ) )
378 : : {
379 [ # # ]: 0 : CreateHyphen( rInf, aGuess );
380 [ # # ]: 0 : if ( rInf.GetFly() )
381 : 0 : rInf.GetRoot()->SetMidHyph( sal_True );
382 : : else
383 : 0 : rInf.GetRoot()->SetEndHyph( sal_True );
384 : : }
385 : : // case C1
386 : : // - Footnote portions with fake line start (i.e., not at beginning of line)
387 : : // should keep together with the text portion. (Note: no keep together
388 : : // with only footnote portions.
389 : : // - TabPortions not at beginning of line should keep together with the
390 : : // text portion, if they are not followed by a blank
391 : : // (work around different definition of tab stop character - breaking or
392 : : // non breaking character - in compatibility mode)
393 [ - + ][ # # : 93388 : else if ( ( IsFtnPortion() && rInf.IsFakeLineStart() &&
# # + - ]
[ + - - +
# # # # #
# # # ]
[ - + ]
394 : : //
395 : 0 : rInf.IsOtherThanFtnInside() ) ||
396 : 23347 : ( rInf.GetLast() &&
397 [ + - ][ + - ]: 23347 : rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::TAB_COMPAT) &&
398 : 23347 : rInf.GetLast()->InTabGrp() &&
399 : 0 : rInf.GetLineStart() + rInf.GetLast()->GetLen() < rInf.GetIdx() &&
400 : 0 : aGuess.BreakPos() == rInf.GetIdx() &&
401 : 0 : CH_BLANK != rInf.GetChar( rInf.GetIdx() ) &&
402 : 0 : 0x3000 != rInf.GetChar( rInf.GetIdx() ) ) )
403 [ # # ]: 0 : BreakUnderflow( rInf );
404 : : // case B2
405 [ + + + + : 48106 : else if( rInf.GetIdx() > rInf.GetLineStart() ||
+ - + - +
+ + - + -
- + # # #
# ][ # # ]
[ + + ]
406 : 23325 : aGuess.BreakPos() > rInf.GetIdx() ||
407 : : // this is weird: during formatting the follow of a field
408 : : // the values rInf.GetIdx and rInf.GetLineStart are replaced
409 : : // IsFakeLineStart indicates GetIdx > GetLineStart
410 : 319 : rInf.IsFakeLineStart() ||
411 : 319 : rInf.GetFly() ||
412 : 319 : rInf.IsFirstMulti() ||
413 : 159 : ( rInf.GetLast() &&
414 : 159 : ( rInf.GetLast()->IsFlyPortion() ||
415 : 159 : ( rInf.GetLast()->InFldGrp() &&
416 : 0 : ! rInf.GetLast()->InNumberGrp() &&
417 : 0 : ! rInf.GetLast()->IsErgoSumPortion() &&
418 [ # # ]: 0 : lcl_HasContent(*((SwFldPortion*)rInf.GetLast()),rInf ) ) ) ) )
419 : : {
420 [ + - ]: 23188 : if ( rInf.X() + aGuess.BreakWidth() <= rInf.Width() )
421 : 23188 : Width( aGuess.BreakWidth() );
422 : : else
423 : : // this actually should not happen
424 : 0 : Width( KSHORT(rInf.Width() - rInf.X()) );
425 : :
426 : 23188 : SetLen( aGuess.BreakPos() - rInf.GetIdx() );
427 : :
428 : : OSL_ENSURE( aGuess.BreakStart() >= aGuess.FieldDiff(),
429 : : "Trouble with expanded field portions during line break" );
430 : 23188 : const xub_StrLen nRealStart = aGuess.BreakStart() - aGuess.FieldDiff();
431 [ + - ][ + + ]: 23188 : if( aGuess.BreakPos() < nRealStart && !InExpGrp() )
[ + + ]
432 : : {
433 [ + - ][ + - ]: 1278 : SwHolePortion *pNew = new SwHolePortion( *this );
434 : 1278 : pNew->SetLen( nRealStart - aGuess.BreakPos() );
435 [ + - ]: 1278 : Insert( pNew );
436 : : }
437 : : }
438 : : else // case C2, last exit
439 [ + - ]: 159 : BreakCut( rInf, aGuess );
440 : : }
441 : : // breakPos < index or no breakpos at all
442 : : else
443 : : {
444 : 17542 : sal_Bool bFirstPor = rInf.GetLineStart() == rInf.GetIdx();
445 [ # # # # : 17542 : if( aGuess.BreakPos() != STRING_LEN &&
# # # # #
# ][ # # ]
[ - + ]
[ - + # # ]
446 : 0 : aGuess.BreakPos() != rInf.GetLineStart() &&
447 : 0 : ( !bFirstPor || rInf.GetFly() || rInf.GetLast()->IsFlyPortion() ||
448 : 0 : rInf.IsFirstMulti() ) &&
449 : 0 : ( !rInf.GetLast()->IsBlankPortion() || ((SwBlankPortion*)
450 [ # # ]: 0 : rInf.GetLast())->MayUnderFlow( rInf, rInf.GetIdx()-1, sal_True )))
451 : : { // case C1 (former BreakUnderflow())
452 [ # # ]: 0 : BreakUnderflow( rInf );
453 : : }
454 : : else
455 : : // case C2, last exit
456 [ + - ]: 17542 : BreakCut( rInf, aGuess );
457 : : }
458 : :
459 [ + - ]: 52281 : return bFull;
460 : : }
461 : :
462 : : /*************************************************************************
463 : : * virtual SwTxtPortion::Format()
464 : : *************************************************************************/
465 : :
466 : :
467 : :
468 : 52281 : sal_Bool SwTxtPortion::Format( SwTxtFormatInfo &rInf )
469 : : {
470 : : #if OSL_DEBUG_LEVEL > 1
471 : : const XubString aDbgTxt( rInf.GetTxt().Copy( rInf.GetIdx(), rInf.GetLen() ) );
472 : : #endif
473 : :
474 [ + - ][ + + ]: 52281 : if( rInf.X() > rInf.Width() || (!GetLen() && !InExpGrp()) )
[ - + ][ - + ]
475 : : {
476 : 0 : Height( 0 );
477 : 0 : Width( 0 );
478 : 0 : SetLen( 0 );
479 : 0 : SetAscent( 0 );
480 : 0 : SetPortion( NULL ); // ????
481 : 0 : return sal_True;
482 : : }
483 : :
484 : : OSL_ENSURE( rInf.RealWidth() || (rInf.X() == rInf.Width()),
485 : : "SwTxtPortion::Format: missing real width" );
486 : : OSL_ENSURE( Height(), "SwTxtPortion::Format: missing height" );
487 : :
488 : 52281 : return _Format( rInf );
489 : : }
490 : :
491 : : /*************************************************************************
492 : : * virtual SwTxtPortion::FormatEOL()
493 : : *************************************************************************/
494 : :
495 : : // Format end of line
496 : : // 5083: We can have awkward cases e.g.:
497 : : // "from {Santa}"
498 : : // Santa wraps, "from " turns into "from" and " " in a justified
499 : : // paragraph, in which the glue gets expanded instead of merged
500 : : // with the MarginPortion.
501 : : //
502 : : // rInf.nIdx points to the next word, nIdx-1 is the portion's last char
503 : :
504 : 373 : void SwTxtPortion::FormatEOL( SwTxtFormatInfo &rInf )
505 : : {
506 [ + + ][ + - : 1470 : if( ( !GetPortion() || ( GetPortion()->IsKernPortion() &&
+ - + + +
+ + - + -
+ - ][ + + ]
507 : 629 : !GetPortion()->GetPortion() ) ) && GetLen() &&
508 : 258 : rInf.GetIdx() < rInf.GetTxt().Len() &&
509 : 140 : 1 < rInf.GetIdx() && ' ' == rInf.GetChar( rInf.GetIdx() - 1 )
510 : 70 : && !rInf.GetLast()->IsHolePortion() )
511 : : {
512 : : // calculate number of blanks
513 : 70 : xub_StrLen nX = rInf.GetIdx() - 1;
514 : 70 : sal_uInt16 nHoleLen = 1;
515 [ + - ][ + - ]: 70 : while( nX && nHoleLen < GetLen() && CH_BLANK == rInf.GetChar( --nX ) )
[ - + ][ - + ]
516 : 0 : nHoleLen++;
517 : :
518 : : // First set ourselves and the insert, because there could be
519 : : // a SwLineLayout
520 : : KSHORT nBlankSize;
521 [ - + ]: 70 : if( nHoleLen == GetLen() )
522 : 0 : nBlankSize = Width();
523 : : else
524 [ + - ][ + - ]: 70 : nBlankSize = nHoleLen * rInf.GetTxtSize(rtl::OUString(' ')).Width();
[ + - ]
525 : 70 : Width( Width() - nBlankSize );
526 : 70 : rInf.X( rInf.X() - nBlankSize );
527 : 70 : SetLen( GetLen() - nHoleLen );
528 [ + - ]: 70 : SwLinePortion *pHole = new SwHolePortion( *this );
529 : 70 : ( (SwHolePortion *)pHole )->SetBlankWidth( nBlankSize );
530 : 70 : ( (SwHolePortion *)pHole )->SetLen( nHoleLen );
531 : 70 : Insert( pHole );
532 : : }
533 : 373 : }
534 : :
535 : : /*************************************************************************
536 : : * virtual SwTxtPortion::GetCrsrOfst()
537 : : *************************************************************************/
538 : 0 : xub_StrLen SwTxtPortion::GetCrsrOfst( const KSHORT nOfst ) const
539 : : {
540 : : OSL_ENSURE( !this, "SwTxtPortion::GetCrsrOfst: don't use this method!" );
541 : 0 : return SwLinePortion::GetCrsrOfst( nOfst );
542 : : }
543 : :
544 : : /*************************************************************************
545 : : * virtual SwTxtPortion::GetTxtSize()
546 : : *************************************************************************/
547 : : // The GetTxtSize() assumes that the own length is correct
548 : :
549 : 3329 : SwPosSize SwTxtPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
550 : : {
551 : 3329 : return rInf.GetTxtSize();
552 : : }
553 : :
554 : : /*************************************************************************
555 : : * virtual SwTxtPortion::Paint()
556 : : *************************************************************************/
557 : 26554 : void SwTxtPortion::Paint( const SwTxtPaintInfo &rInf ) const
558 : : {
559 [ + + ][ + + ]: 26554 : if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDEND==rInf.GetTxt().GetChar(rInf.GetIdx()))
[ - + ][ - + ]
560 : : {
561 [ # # ]: 0 : rInf.DrawBackBrush( *this );
562 : 0 : const rtl::OUString aTxt(CH_TXT_ATR_SUBST_FIELDEND);
563 [ # # ][ # # ]: 0 : rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
[ # # ]
564 : : }
565 [ + + ][ + + ]: 26554 : else if (rInf.OnWin() && 1==rInf.GetLen() && CH_TXT_ATR_FIELDSTART==rInf.GetTxt().GetChar(rInf.GetIdx()))
[ - + ][ - + ]
566 : : {
567 [ # # ]: 0 : rInf.DrawBackBrush( *this );
568 : 0 : const rtl::OUString aTxt(CH_TXT_ATR_SUBST_FIELDSTART);
569 [ # # ][ # # ]: 0 : rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
[ # # ]
570 : : }
571 [ + + ]: 26554 : else if( GetLen() )
572 : : {
573 : 24639 : rInf.DrawBackBrush( *this );
574 : :
575 : : // do we have to repaint a post it portion?
576 [ + + ][ + + ]: 24639 : if( rInf.OnWin() && pPortion && !pPortion->Width() )
[ + + ][ + + ]
577 : 1191 : pPortion->PrePaint( rInf, this );
578 : :
579 : 24639 : const SwWrongList *pWrongList = rInf.GetpWrongList();
580 : 24639 : const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList();
581 : : // SMARTTAGS
582 : 24639 : const SwWrongList *pSmarttags = rInf.GetSmartTags();
583 : :
584 : 24639 : const bool bWrong = 0 != pWrongList;
585 : 24639 : const bool bGrammarCheck = 0 != pGrammarCheckList;
586 : 24639 : const bool bSmartTags = 0 != pSmarttags;
587 : :
588 [ + - ][ + + ]: 24639 : if ( bWrong || bSmartTags || bGrammarCheck )
[ + + ]
589 : 22832 : rInf.DrawMarkedText( *this, rInf.GetLen(), sal_False, bWrong, bSmartTags, bGrammarCheck );
590 : : else
591 : 24639 : rInf.DrawText( *this, rInf.GetLen(), sal_False );
592 : : }
593 : 26554 : }
594 : :
595 : : /*************************************************************************
596 : : * virtual SwTxtPortion::GetExpTxt()
597 : : *************************************************************************/
598 : :
599 : :
600 : :
601 : 0 : sal_Bool SwTxtPortion::GetExpTxt( const SwTxtSizeInfo &, XubString & ) const
602 : : {
603 : 0 : return sal_False;
604 : : }
605 : :
606 : : /*************************************************************************
607 : : * xub_StrLen SwTxtPortion::GetSpaceCnt()
608 : : * long SwTxtPortion::CalcSpacing()
609 : : * Are responsible for the justified paragraph. They calculate the blank
610 : : * count and the resulting added space.
611 : : *************************************************************************/
612 : :
613 : 60 : xub_StrLen SwTxtPortion::GetSpaceCnt( const SwTxtSizeInfo &rInf,
614 : : xub_StrLen& rCharCnt ) const
615 : : {
616 : 60 : xub_StrLen nCnt = 0;
617 : 60 : xub_StrLen nPos = 0;
618 [ - + ]: 60 : if ( InExpGrp() )
619 : : {
620 [ # # ][ # # ]: 0 : if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
[ # # ][ # # ]
621 : : {
622 : : // OnWin() likes to return a blank instead of an empty string from
623 : : // time to time. We cannot use that here at all, however.
624 : 0 : sal_Bool bOldOnWin = rInf.OnWin();
625 : 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False );
626 : :
627 [ # # ]: 0 : XubString aStr( aEmptyStr );
628 [ # # ]: 0 : GetExpTxt( rInf, aStr );
629 : 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
630 : :
631 [ # # ]: 0 : nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
632 [ # # ]: 0 : nPos = aStr.Len();
633 : : }
634 : : }
635 [ + - ]: 60 : else if( !IsDropPortion() )
636 : : {
637 : 60 : nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
638 : 60 : nPos = GetLen();
639 : : }
640 : 60 : rCharCnt = rCharCnt + nPos;
641 : 60 : return nCnt;
642 : : }
643 : :
644 : 0 : long SwTxtPortion::CalcSpacing( long nSpaceAdd, const SwTxtSizeInfo &rInf ) const
645 : : {
646 : 0 : xub_StrLen nCnt = 0;
647 : :
648 [ # # ]: 0 : if ( InExpGrp() )
649 : : {
650 [ # # ][ # # ]: 0 : if( !IsBlankPortion() && !InNumberGrp() && !IsCombinedPortion() )
[ # # ][ # # ]
651 : : {
652 : : // OnWin() likes to return a blank instead of an empty string from
653 : : // time to time. We cannot use that here at all, however.
654 : 0 : sal_Bool bOldOnWin = rInf.OnWin();
655 : 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( sal_False );
656 : :
657 [ # # ]: 0 : XubString aStr( aEmptyStr );
658 [ # # ]: 0 : GetExpTxt( rInf, aStr );
659 : 0 : ((SwTxtSizeInfo &)rInf).SetOnWin( bOldOnWin );
660 [ # # ]: 0 : if( nSpaceAdd > 0 )
661 [ # # ]: 0 : nCnt = nCnt + lcl_AddSpace( rInf, &aStr, *this );
662 : : else
663 : : {
664 : 0 : nSpaceAdd = -nSpaceAdd;
665 : 0 : nCnt = aStr.Len();
666 [ # # ]: 0 : }
667 : : }
668 : : }
669 [ # # ]: 0 : else if( !IsDropPortion() )
670 : : {
671 [ # # ]: 0 : if( nSpaceAdd > 0 )
672 : 0 : nCnt = nCnt + lcl_AddSpace( rInf, 0, *this );
673 : : else
674 : : {
675 : 0 : nSpaceAdd = -nSpaceAdd;
676 : 0 : nCnt = GetLen();
677 : 0 : SwLinePortion* pPor = GetPortion();
678 : :
679 : : // we do not want an extra space in front of margin portions
680 [ # # ]: 0 : if ( nCnt )
681 : : {
682 [ # # ][ # # ]: 0 : while ( pPor && !pPor->Width() && ! pPor->IsHolePortion() )
[ # # ][ # # ]
683 : 0 : pPor = pPor->GetPortion();
684 : :
685 [ # # ][ # # ]: 0 : if ( !pPor || pPor->InFixMargGrp() || pPor->IsHolePortion() )
[ # # ][ # # ]
686 : 0 : --nCnt;
687 : : }
688 : : }
689 : : }
690 : :
691 : 0 : return nCnt * nSpaceAdd / SPACING_PRECISION_FACTOR;
692 : : }
693 : :
694 : : /*************************************************************************
695 : : * virtual SwTxtPortion::HandlePortion()
696 : : *************************************************************************/
697 : :
698 : 48 : void SwTxtPortion::HandlePortion( SwPortionHandler& rPH ) const
699 : : {
700 : 48 : rPH.Text( GetLen(), GetWhichPor(), Height(), Width() );
701 : 48 : }
702 : :
703 : : /*************************************************************************
704 : : * class SwHolePortion
705 : : *************************************************************************/
706 : :
707 : :
708 : :
709 : 1348 : SwHolePortion::SwHolePortion( const SwTxtPortion &rPor )
710 : 1348 : : nBlankWidth( 0 )
711 : : {
712 : 1348 : SetLen( 1 );
713 : 1348 : Height( rPor.Height() );
714 : 1348 : SetAscent( rPor.GetAscent() );
715 : 1348 : SetWhichPor( POR_HOLE );
716 : 1348 : }
717 : :
718 : 1348 : SwLinePortion *SwHolePortion::Compress() { return this; }
719 : :
720 : : /*************************************************************************
721 : : * virtual SwHolePortion::Paint()
722 : : *************************************************************************/
723 : :
724 : :
725 : :
726 : 509 : void SwHolePortion::Paint( const SwTxtPaintInfo &rInf ) const
727 : : {
728 : : // #i16816# tagged pdf support
729 [ + - ][ - + ]: 509 : if( rInf.GetVsh() && rInf.GetVsh()->GetViewOptions()->IsPDFExport() )
[ - + ]
730 : : {
731 : 0 : const rtl::OUString aTxt( ' ' );
732 [ # # ][ # # ]: 0 : rInf.DrawText( aTxt, *this, 0, 1, false );
[ # # ]
733 : : }
734 : 509 : }
735 : :
736 : : /*************************************************************************
737 : : * virtual SwHolePortion::Format()
738 : : *************************************************************************/
739 : :
740 : :
741 : :
742 : 0 : sal_Bool SwHolePortion::Format( SwTxtFormatInfo &rInf )
743 : : {
744 [ # # ][ # # ]: 0 : return rInf.IsFull() || rInf.X() >= rInf.Width();
745 : : }
746 : :
747 : : /*************************************************************************
748 : : * virtual SwHolePortion::HandlePortion()
749 : : *************************************************************************/
750 : :
751 : 0 : void SwHolePortion::HandlePortion( SwPortionHandler& rPH ) const
752 : : {
753 : 0 : rPH.Text( GetLen(), GetWhichPor() );
754 : 0 : }
755 : :
756 : 12 : void SwFieldMarkPortion::Paint( const SwTxtPaintInfo & /*rInf*/) const
757 : : {
758 : : // These shouldn't be painted!
759 : : // SwTxtPortion::Paint(rInf);
760 : 12 : }
761 : :
762 : 36 : sal_Bool SwFieldMarkPortion::Format( SwTxtFormatInfo & )
763 : : {
764 : 36 : sal_Bool ret=0;
765 : 36 : Width(0);
766 : 36 : return ret;
767 : : }
768 : :
769 : : namespace {
770 : 0 : static sal_Int32 getCurrentListIndex( IFieldmark* pBM,
771 : : ::rtl::OUString* io_pCurrentText = NULL )
772 : : {
773 [ # # ]: 0 : const IFieldmark::parameter_map_t* const pParameters = pBM->GetParameters();
774 : 0 : sal_Int32 nCurrentIdx = 0;
775 [ # # ][ # # ]: 0 : const IFieldmark::parameter_map_t::const_iterator pResult = pParameters->find(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODF_FORMDROPDOWN_RESULT)));
776 [ # # ]: 0 : if(pResult != pParameters->end())
777 : 0 : pResult->second >>= nCurrentIdx;
778 [ # # ]: 0 : if(io_pCurrentText)
779 : : {
780 [ # # ][ # # ]: 0 : const IFieldmark::parameter_map_t::const_iterator pListEntries = pParameters->find(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODF_FORMDROPDOWN_LISTENTRY)));
781 [ # # ]: 0 : if(pListEntries != pParameters->end())
782 : : {
783 [ # # ]: 0 : uno::Sequence< ::rtl::OUString > vListEntries;
784 [ # # ]: 0 : pListEntries->second >>= vListEntries;
785 [ # # ]: 0 : if(nCurrentIdx < vListEntries.getLength())
786 [ # # ][ # # ]: 0 : *io_pCurrentText = vListEntries[nCurrentIdx];
787 : : }
788 : : }
789 : 0 : return nCurrentIdx;
790 : : }
791 : : }
792 : :
793 : : //FIXME Fieldbk
794 : 0 : void SwFieldFormPortion::Paint( const SwTxtPaintInfo& rInf ) const
795 : : {
796 : 0 : SwTxtNode* pNd = const_cast<SwTxtNode*>(rInf.GetTxtFrm()->GetTxtNode());
797 : 0 : const SwDoc *doc=pNd->GetDoc();
798 [ # # ][ # # ]: 0 : SwIndex aIndex( pNd, rInf.GetIdx() );
799 [ # # ][ # # ]: 0 : SwPosition aPosition(*pNd, aIndex);
[ # # ]
800 : :
801 [ # # ][ # # ]: 0 : IFieldmark* pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
802 : :
803 : : OSL_ENSURE( pBM,
804 : : "SwFieldFormPortion::Paint(..)"
805 : : " - Where is my form field bookmark???");
806 : :
807 [ # # ]: 0 : if ( pBM != NULL )
808 : : {
809 [ # # ][ # # ]: 0 : if ( pBM->GetFieldname( ) == ODF_FORMCHECKBOX )
810 : : { // a checkbox...
811 [ # # ]: 0 : ICheckboxFieldmark* pCheckboxFm = dynamic_cast< ICheckboxFieldmark* >(pBM);
812 [ # # ]: 0 : bool checked = pCheckboxFm->IsChecked();
813 [ # # ]: 0 : rInf.DrawCheckBox(*this, checked);
814 : : }
815 [ # # ][ # # ]: 0 : else if ( pBM->GetFieldname( ) == ODF_FORMDROPDOWN )
816 : : { // a list...
817 : 0 : rtl::OUString aTxt;
818 [ # # ]: 0 : getCurrentListIndex( pBM, &aTxt );
819 [ # # ]: 0 : rInf.DrawViewOpt( *this, POR_FLD );
820 [ # # ][ # # ]: 0 : rInf.DrawText( aTxt, *this, 0, aTxt.getLength(), false );
[ # # ]
821 : : }
822 : : else
823 : : {
824 : : assert(0); // unknown type...
825 : : }
826 [ # # ][ # # ]: 0 : }
827 : 0 : }
828 : :
829 : 3 : sal_Bool SwFieldFormPortion::Format( SwTxtFormatInfo & rInf )
830 : : {
831 : 3 : sal_Bool ret = 0;
832 : 3 : SwTxtNode *pNd = const_cast < SwTxtNode * >( rInf.GetTxtFrm( )->GetTxtNode( ) );
833 : 3 : const SwDoc *doc = pNd->GetDoc( );
834 [ + - ][ + - ]: 3 : SwIndex aIndex( pNd, rInf.GetIdx( ) );
835 [ + - ][ + - ]: 3 : SwPosition aPosition( *pNd, aIndex );
[ + - ]
836 [ + - ][ + - ]: 3 : IFieldmark *pBM = doc->getIDocumentMarkAccess( )->getFieldmarkFor( aPosition );
837 : : OSL_ENSURE( pBM != NULL, "Where is my form field bookmark???" );
838 [ + - ]: 3 : if ( pBM != NULL )
839 : : {
840 [ + - ][ + - ]: 3 : if ( pBM->GetFieldname( ) == ODF_FORMCHECKBOX )
841 : : {
842 [ + - ]: 3 : Width( rInf.GetTxtHeight( ) );
843 [ + - ]: 3 : Height( rInf.GetTxtHeight( ) );
844 [ + - ]: 3 : SetAscent( rInf.GetAscent( ) );
845 : : }
846 [ # # ][ # # ]: 0 : else if ( pBM->GetFieldname( ) == ODF_FORMDROPDOWN )
847 : : {
848 : 0 : ::rtl::OUString aTxt;
849 [ # # ]: 0 : getCurrentListIndex( pBM, &aTxt );
850 [ # # ][ # # ]: 0 : SwPosSize aPosSize = rInf.GetTxtSize( aTxt );
[ # # ]
851 : 0 : Width( aPosSize.Width( ) );
852 : 0 : Height( aPosSize.Height( ) );
853 [ # # ]: 0 : SetAscent( rInf.GetAscent( ) );
854 : : }
855 : : else
856 : : {
857 : : assert( 0 ); // unknown type...
858 : : }
859 : : }
860 [ + - ][ + - ]: 3 : return ret;
861 : : }
862 : :
863 : :
864 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|