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 <ascharanchoredobjectposition.hxx>
30 : : #include <frame.hxx>
31 : : #include <txtfrm.hxx>
32 : : #include <flyfrms.hxx>
33 : : #include <svx/svdobj.hxx>
34 : : #include <dcontact.hxx>
35 : : #include <frmfmt.hxx>
36 : : #include <frmatr.hxx>
37 : : #include <editeng/lrspitem.hxx>
38 : : #include <editeng/ulspitem.hxx>
39 : : #include <fmtornt.hxx>
40 : :
41 : : #include <com/sun/star/text/HoriOrientation.hpp>
42 : :
43 : :
44 : : using namespace ::com::sun::star;
45 : : using namespace objectpositioning;
46 : :
47 : : /** constructor
48 : :
49 : : @author OD
50 : : */
51 : 4187 : SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition(
52 : : SdrObject& _rDrawObj,
53 : : const Point& _rProposedAnchorPos,
54 : : const AsCharFlags _nFlags,
55 : : const SwTwips _nLineAscent,
56 : : const SwTwips _nLineDescent,
57 : : const SwTwips _nLineAscentInclObjs,
58 : : const SwTwips _nLineDescentInclObjs )
59 : : : SwAnchoredObjectPosition( _rDrawObj ),
60 : : mrProposedAnchorPos( _rProposedAnchorPos ),
61 : : mnFlags( _nFlags ),
62 : : mnLineAscent( _nLineAscent ),
63 : : mnLineDescent( _nLineDescent ),
64 : : mnLineAscentInclObjs( _nLineAscentInclObjs ),
65 : : mnLineDescentInclObjs( _nLineDescentInclObjs ),
66 : : maAnchorPos ( Point() ),
67 : : mnRelPos ( 0 ),
68 : : maObjBoundRect ( SwRect() ),
69 : 4187 : mnLineAlignment ( 0 )
70 : 4187 : {}
71 : :
72 : : /** destructor
73 : :
74 : : @author OD
75 : : */
76 : 4187 : SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition()
77 [ - + ]: 4187 : {}
78 : :
79 : : /** method to cast <SwAnchoredObjectPosition::GetAnchorFrm()> to needed type
80 : :
81 : : @author OD
82 : : */
83 : 4187 : const SwTxtFrm& SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() const
84 : : {
85 : : OSL_ENSURE( GetAnchorFrm().ISA(SwTxtFrm),
86 : : "SwAsCharAnchoredObjectPosition::GetAnchorTxtFrm() - wrong anchor frame type" );
87 : :
88 : 4187 : return static_cast<const SwTxtFrm&>(GetAnchorFrm());
89 : : }
90 : :
91 : : /** calculate position for object
92 : :
93 : : OD 30.07.2003 #110978#
94 : : members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and
95 : : <mnLineAlignment> are calculated.
96 : : calculated position is set at the given object.
97 : :
98 : : @author OD
99 : : */
100 : 4187 : void SwAsCharAnchoredObjectPosition::CalcPosition()
101 : : {
102 : 4187 : const SwTxtFrm& rAnchorFrm = GetAnchorTxtFrm();
103 : : // swap anchor frame, if swapped. Note: destructor takes care of the 'undo'
104 [ + - ]: 4187 : SwFrmSwapper aFrmSwapper( &rAnchorFrm, false );
105 : :
106 [ + - ][ - + ]: 4187 : SWRECTFN( ( &rAnchorFrm ) )
[ # # ][ # # ]
[ - + ]
107 : :
108 : 4187 : Point aAnchorPos( mrProposedAnchorPos );
109 : :
110 : 4187 : const SwFrmFmt& rFrmFmt = GetFrmFmt();
111 : :
112 [ + - ]: 4187 : SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
113 [ + - ][ + - ]: 4187 : SwTwips nObjWidth = (aObjBoundRect.*fnRect->fnGetWidth)();
114 : :
115 : : // determine spacing values considering layout-/text-direction
116 [ + - ]: 4187 : const SvxLRSpaceItem& rLRSpace = rFrmFmt.GetLRSpace();
117 [ + - ]: 4187 : const SvxULSpaceItem& rULSpace = rFrmFmt.GetULSpace();
118 : : SwTwips nLRSpaceLeft, nLRSpaceRight, nULSpaceUpper, nULSpaceLower;
119 : : {
120 [ + - ][ - + ]: 4187 : if ( rAnchorFrm.IsVertical() )
121 : : {
122 : : // Seems to be easier to do it all the horizontal way
123 : : // So, from now on think horizontal.
124 [ # # ]: 0 : rAnchorFrm.SwitchVerticalToHorizontal( aObjBoundRect );
125 [ # # ]: 0 : rAnchorFrm.SwitchVerticalToHorizontal( aAnchorPos );
126 : :
127 : : // convert the spacing values
128 : 0 : nLRSpaceLeft = rULSpace.GetUpper();
129 : 0 : nLRSpaceRight = rULSpace.GetLower();
130 : 0 : nULSpaceUpper = rLRSpace.GetRight();
131 : 0 : nULSpaceLower = rLRSpace.GetLeft();
132 : : }
133 : : else
134 : : {
135 [ + - ][ - + ]: 4187 : if ( rAnchorFrm.IsRightToLeft() )
136 : : {
137 : 0 : nLRSpaceLeft = rLRSpace.GetRight();
138 : 0 : nLRSpaceRight = rLRSpace.GetLeft();
139 : : }
140 : : else
141 : : {
142 : 4187 : nLRSpaceLeft = rLRSpace.GetLeft();
143 : 4187 : nLRSpaceRight = rLRSpace.GetRight();
144 : : }
145 : :
146 : 4187 : nULSpaceUpper = rULSpace.GetUpper();
147 : 4187 : nULSpaceLower = rULSpace.GetLower();
148 : : }
149 : : }
150 : :
151 : : // consider left and upper spacing by adjusting anchor position.
152 : : // left spacing is only considered, if requested.
153 [ + + ]: 4187 : if( mnFlags & AS_CHAR_ULSPACE )
154 : : {
155 : 2921 : aAnchorPos.X() += nLRSpaceLeft;
156 : : }
157 : 4187 : aAnchorPos.Y() += nULSpaceUpper;
158 : :
159 : : // for drawing objects: consider difference between its bounding rectangle
160 : : // and its snapping rectangle by adjusting anchor position.
161 : : // left difference is only considered, if requested.
162 [ + + ]: 4187 : if( !IsObjFly() )
163 : : {
164 [ + - ][ + - ]: 2175 : SwRect aSnapRect = GetObject().GetSnapRect();
165 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsVertical() )
166 : : {
167 [ # # ]: 0 : rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect );
168 : : }
169 : :
170 [ + + ]: 2175 : if( mnFlags & AS_CHAR_ULSPACE )
171 : : {
172 : 1453 : aAnchorPos.X() += aSnapRect.Left() - aObjBoundRect.Left();
173 : : }
174 : 2175 : aAnchorPos.Y() += aSnapRect.Top() - aObjBoundRect.Top();
175 : : }
176 : :
177 : : // enlarge bounding rectangle of object by its spacing.
178 : 4187 : aObjBoundRect.Left( aObjBoundRect.Left() - nLRSpaceLeft );
179 : 4187 : aObjBoundRect.Width( aObjBoundRect.Width() + nLRSpaceRight );
180 : 4187 : aObjBoundRect.Top( aObjBoundRect.Top() - nULSpaceUpper );
181 : 4187 : aObjBoundRect.Height( aObjBoundRect.Height() + nULSpaceLower );
182 : :
183 : : // calculate relative position to given base line.
184 [ + - ]: 4187 : const SwFmtVertOrient& rVert = rFrmFmt.GetVertOrient();
185 : : const SwTwips nObjBoundHeight = ( mnFlags & AS_CHAR_ROTATE )
186 : : ? aObjBoundRect.Width()
187 [ - + ]: 4187 : : aObjBoundRect.Height();
188 : 4187 : const SwTwips nRelPos = _GetRelPosToBase( nObjBoundHeight, rVert );
189 : :
190 : : // for initial positioning:
191 : : // adjust the proposed anchor position by difference between
192 : : // calculated relative position to base line and current maximal line ascent.
193 : : // Note: In the following line formatting the base line will be adjusted
194 : : // by the same difference.
195 [ + + ][ + + ]: 4187 : if( mnFlags & AS_CHAR_INIT && nRelPos < 0 && mnLineAscentInclObjs < -nRelPos )
[ + + ]
196 : : {
197 [ - + ]: 436 : if( mnFlags & AS_CHAR_ROTATE )
198 : 0 : aAnchorPos.X() -= mnLineAscentInclObjs + nRelPos;
199 : : else
200 : 436 : aAnchorPos.Y() -= mnLineAscentInclObjs + nRelPos;
201 : : }
202 : :
203 : : // consider BIDI-multiportion by adjusting proposed anchor position
204 [ - + ]: 4187 : if( mnFlags & AS_CHAR_BIDI )
205 : 0 : aAnchorPos.X() -= aObjBoundRect.Width();
206 : :
207 : : // calculate relative position considering rotation and inside rotation
208 : : // reverse direction.
209 : 4187 : Point aRelPos;
210 : : {
211 [ - + ]: 4187 : if( mnFlags & AS_CHAR_ROTATE )
212 : : {
213 [ # # ]: 0 : if( mnFlags & AS_CHAR_REVERSE )
214 : 0 : aRelPos.X() = -nRelPos - aObjBoundRect.Width();
215 : : else
216 : : {
217 : 0 : aRelPos.X() = nRelPos;
218 : 0 : aRelPos.Y() = -aObjBoundRect.Height();
219 : : }
220 : : }
221 : : else
222 : 4187 : aRelPos.Y() = nRelPos;
223 : : }
224 : :
225 [ + + ]: 4187 : if( !IsObjFly() )
226 : : {
227 [ + - ]: 2175 : if( !( mnFlags & AS_CHAR_QUICK ) )
228 : : {
229 : : // save calculated Y-position value for 'automatic' vertical positioning,
230 : : // in order to avoid a switch to 'manual' vertical positioning in
231 : : // <SwDrawContact::_Changed(..)>.
232 : 2175 : const sal_Int16 eVertOrient = rVert.GetVertOrient();
233 [ + - ][ + + ]: 2175 : if( rVert.GetPos() != nRelPos && eVertOrient != text::VertOrientation::NONE )
[ + + ]
234 : : {
235 [ + - ]: 12 : SwFmtVertOrient aVert( rVert );
236 : 12 : aVert.SetPos( nRelPos );
237 : 12 : const_cast<SwFrmFmt&>(rFrmFmt).LockModify();
238 [ + - ]: 12 : const_cast<SwFrmFmt&>(rFrmFmt).SetFmtAttr( aVert );
239 [ + - ]: 12 : const_cast<SwFrmFmt&>(rFrmFmt).UnlockModify();
240 : : }
241 : :
242 : : // determine absolute anchor position considering layout directions.
243 : : // Note: Use copy of <aAnchorPos>, because it's needed for
244 : : // setting relative position.
245 : 2175 : Point aAbsAnchorPos( aAnchorPos );
246 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsRightToLeft() )
247 : : {
248 [ # # ]: 0 : rAnchorFrm.SwitchLTRtoRTL( aAbsAnchorPos );
249 : 0 : aAbsAnchorPos.X() -= nObjWidth;
250 : : }
251 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsVertical() )
252 [ # # ]: 0 : rAnchorFrm.SwitchHorizontalToVertical( aAbsAnchorPos );
253 : :
254 : : // set proposed anchor position at the drawing object.
255 : : // OD 2004-04-06 #i26791# - distinction between 'master' drawing
256 : : // object and 'virtual' drawing object no longer needed.
257 [ + - ]: 2175 : GetObject().SetAnchorPos( aAbsAnchorPos );
258 : :
259 : : // move drawing object to set its correct relative position.
260 : : {
261 [ + - ][ + - ]: 2175 : SwRect aSnapRect = GetObject().GetSnapRect();
262 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsVertical() )
263 [ # # ]: 0 : rAnchorFrm.SwitchVerticalToHorizontal( aSnapRect );
264 : :
265 : 2175 : Point aDiff;
266 [ - + ][ + - ]: 2175 : if ( rAnchorFrm.IsRightToLeft() )
267 [ # # ]: 0 : aDiff = aRelPos + aAbsAnchorPos - aSnapRect.TopLeft();
268 : : else
269 [ + - ]: 2175 : aDiff = aRelPos + aAnchorPos - aSnapRect.TopLeft();
270 : :
271 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsVertical() )
272 : 0 : aDiff = Point( -aDiff.Y(), aDiff.X() );
273 : :
274 : : // OD 2004-04-06 #i26791# - distinction between 'master' drawing
275 : : // object and 'virtual' drawing object no longer needed.
276 [ + - ]: 2175 : GetObject().Move( Size( aDiff.X(), aDiff.Y() ) );
277 : : }
278 : : }
279 : :
280 : : // switch horizontal, LTR anchor position to absolute values.
281 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsRightToLeft() )
282 : : {
283 [ # # ]: 0 : rAnchorFrm.SwitchLTRtoRTL( aAnchorPos );
284 : 0 : aAnchorPos.X() -= nObjWidth;
285 : : }
286 [ + - ][ - + ]: 2175 : if ( rAnchorFrm.IsVertical() )
287 [ # # ]: 0 : rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos );
288 : :
289 : : // #i44347# - keep last object rectangle at anchored object
290 : : OSL_ENSURE( GetAnchoredObj().ISA(SwAnchoredDrawObject),
291 : : "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." );
292 : : SwAnchoredDrawObject& rAnchoredDrawObj =
293 : 2175 : static_cast<SwAnchoredDrawObject&>( GetAnchoredObj() );
294 [ + - ][ + - ]: 2175 : rAnchoredDrawObj.SetLastObjRect( rAnchoredDrawObj.GetObjRect().SVRect() );
[ + - ]
295 : : }
296 : : else
297 : : {
298 : : // determine absolute anchor position and calculate corresponding
299 : : // relative position and its relative position attribute.
300 : : // Note: The relative position contains the spacing values.
301 : 2012 : Point aRelAttr;
302 [ - + ][ + - ]: 2012 : if ( rAnchorFrm.IsRightToLeft() )
303 : : {
304 [ # # ]: 0 : rAnchorFrm.SwitchLTRtoRTL( aAnchorPos );
305 : 0 : aAnchorPos.X() -= nObjWidth;
306 : : }
307 [ + - ][ - + ]: 2012 : if ( rAnchorFrm.IsVertical() )
308 : : {
309 [ # # ]: 0 : rAnchorFrm.SwitchHorizontalToVertical( aAnchorPos );
310 : 0 : aRelAttr = Point( -nRelPos, 0 );
311 : 0 : aRelPos = Point( -aRelPos.Y(), aRelPos.X() );
312 : : }
313 : : else
314 : 2012 : aRelAttr = Point( 0, nRelPos );
315 : :
316 : : // OD 2004-03-23 #i26791#
317 : : OSL_ENSURE( GetAnchoredObj().ISA(SwFlyInCntFrm),
318 : : "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." );
319 : : const SwFlyInCntFrm& rFlyInCntFrm =
320 [ + - ]: 2012 : static_cast<const SwFlyInCntFrm&>(GetAnchoredObj());
321 [ + - + + : 7291 : if ( !(mnFlags & AS_CHAR_QUICK) &&
+ + ][ + + ]
322 : 2012 : ( aAnchorPos != rFlyInCntFrm.GetRefPoint() ||
323 [ + - ][ + + ]: 3267 : aRelAttr != rFlyInCntFrm.GetCurrRelPos() ) )
[ # # ]
324 : : {
325 : : // set new anchor position and relative position
326 : 787 : SwFlyInCntFrm* pFlyInCntFrm = &(const_cast<SwFlyInCntFrm&>(rFlyInCntFrm));
327 [ + - ]: 787 : pFlyInCntFrm->SetRefPoint( aAnchorPos, aRelAttr, aRelPos );
328 [ + - ][ + - ]: 787 : if( nObjWidth != (pFlyInCntFrm->Frm().*fnRect->fnGetWidth)() )
[ - + ]
329 : : {
330 : : // recalculate object bound rectangle, if object width has changed.
331 [ # # ]: 0 : aObjBoundRect = GetAnchoredObj().GetObjRect();
332 : 0 : aObjBoundRect.Left( aObjBoundRect.Left() - rLRSpace.GetLeft() );
333 : 0 : aObjBoundRect.Width( aObjBoundRect.Width() + rLRSpace.GetRight() );
334 : 0 : aObjBoundRect.Top( aObjBoundRect.Top() - rULSpace.GetUpper() );
335 : 2012 : aObjBoundRect.Height( aObjBoundRect.Height() + rULSpace.GetLower() );
336 : : }
337 : : }
338 : : OSL_ENSURE( (rFlyInCntFrm.Frm().*fnRect->fnGetHeight)(),
339 : : "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" );
340 : : }
341 : :
342 : : // keep calculated values
343 : 4187 : maAnchorPos = aAnchorPos;
344 : 4187 : mnRelPos = nRelPos;
345 [ + - ]: 4187 : maObjBoundRect = aObjBoundRect;
346 : 4187 : }
347 : :
348 : : /** determine the relative position to base line for object position type AS_CHAR
349 : :
350 : : OD 29.07.2003 #110978#
351 : : Note about values set at member <mnLineAlignment> -
352 : : value gives feedback for the line formatting.
353 : : 0 - no feedback; 1|2|3 - proposed formatting of characters
354 : : at top|at center|at bottom of line.
355 : :
356 : : @author OD
357 : : */
358 : 4187 : SwTwips SwAsCharAnchoredObjectPosition::_GetRelPosToBase(
359 : : const SwTwips _nObjBoundHeight,
360 : : const SwFmtVertOrient& _rVert )
361 : : {
362 : 4187 : SwTwips nRelPosToBase = 0;
363 : :
364 : 4187 : mnLineAlignment = 0;
365 : :
366 : 4187 : const sal_Int16 eVertOrient = _rVert.GetVertOrient();
367 : :
368 [ + + ]: 4187 : if ( eVertOrient == text::VertOrientation::NONE )
369 : 2139 : nRelPosToBase = _rVert.GetPos();
370 : : else
371 : : {
372 [ - + ]: 2048 : if ( eVertOrient == text::VertOrientation::CENTER )
373 : 0 : nRelPosToBase -= _nObjBoundHeight / 2;
374 [ + + ]: 2048 : else if ( eVertOrient == text::VertOrientation::TOP )
375 : 467 : nRelPosToBase -= _nObjBoundHeight;
376 [ - + ]: 1581 : else if ( eVertOrient == text::VertOrientation::BOTTOM )
377 : 0 : nRelPosToBase = 0;
378 [ + - ]: 1581 : else if ( eVertOrient == text::VertOrientation::CHAR_CENTER )
379 : 1581 : nRelPosToBase -= ( _nObjBoundHeight + mnLineAscent - mnLineDescent ) / 2;
380 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::CHAR_TOP )
381 : 0 : nRelPosToBase -= mnLineAscent;
382 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::CHAR_BOTTOM )
383 : 0 : nRelPosToBase += mnLineDescent - _nObjBoundHeight;
384 : : else
385 : : {
386 [ # # ]: 0 : if( _nObjBoundHeight >= mnLineAscentInclObjs + mnLineDescentInclObjs )
387 : : {
388 : : // object is at least as high as the line. Thus, no more is
389 : : // positioning necessary. Also, the max. ascent isn't changed.
390 : 0 : nRelPosToBase -= mnLineAscentInclObjs;
391 [ # # ]: 0 : if ( eVertOrient == text::VertOrientation::LINE_CENTER )
392 : 0 : mnLineAlignment = 2;
393 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::LINE_TOP )
394 : 0 : mnLineAlignment = 1;
395 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM )
396 : 0 : mnLineAlignment = 3;
397 : : }
398 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::LINE_CENTER )
399 : : {
400 : 0 : nRelPosToBase -= ( _nObjBoundHeight + mnLineAscentInclObjs - mnLineDescentInclObjs ) / 2;
401 : 0 : mnLineAlignment = 2;
402 : : }
403 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::LINE_TOP )
404 : : {
405 : 0 : nRelPosToBase -= mnLineAscentInclObjs;
406 : 0 : mnLineAlignment = 1;
407 : : }
408 [ # # ]: 0 : else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM )
409 : : {
410 : 0 : nRelPosToBase += mnLineDescentInclObjs - _nObjBoundHeight;
411 : 0 : mnLineAlignment = 3;
412 : : }
413 : : }
414 : : }
415 : :
416 : 4187 : return nRelPosToBase;
417 : : }
418 : :
419 : : /** calculated anchored position for object position
420 : :
421 : : @author OD
422 : : */
423 : 4187 : Point SwAsCharAnchoredObjectPosition::GetAnchorPos() const
424 : : {
425 : 4187 : return maAnchorPos;
426 : : }
427 : :
428 : : /** calculated relative position to base line for object position
429 : :
430 : : @author OD
431 : : */
432 : 4187 : SwTwips SwAsCharAnchoredObjectPosition::GetRelPosY() const
433 : : {
434 : 4187 : return mnRelPos;
435 : : }
436 : :
437 : : /** determined object rectangle including spacing for object
438 : :
439 : : @author OD
440 : : */
441 : 4187 : SwRect SwAsCharAnchoredObjectPosition::GetObjBoundRectInclSpacing() const
442 : : {
443 : 4187 : return maObjBoundRect;
444 : : }
445 : :
446 : : /** determined line alignment
447 : :
448 : : @author OD
449 : : */
450 : 4187 : sal_uInt8 SwAsCharAnchoredObjectPosition::GetLineAlignment() const
451 : : {
452 : 4187 : return mnLineAlignment;
453 : : }
454 : :
455 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|