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