Update git submodules
[LibreOffice.git] / filter / source / graphicfilter / icgm / class5.cxx
blob7cfd9911c7d46125f60494672bbdbbca31b46c10
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 //#define VCL_NEED_BASETSD
22 #include <sal/log.hxx>
23 #include "cgm.hxx"
24 #include "elements.hxx"
25 #include "outact.hxx"
27 void CGM::ImplDoClass5()
29 switch ( mnElementID )
31 case 0x01 : /*Line Bundle Index*/
32 pElement->pLineBundle = static_cast<LineBundle*>(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aLineList, pElement->aLineBundle ));
33 break;
34 case 0x02 : /*Line Type*/
36 if ( pElement->nAspectSourceFlags & ASF_LINETYPE )
37 pElement->pLineBundle->eLineType = static_cast<LineType>(ImplGetI( pElement->nIndexPrecision ));
38 else
39 pElement->aLineBundle.eLineType = static_cast<LineType>(ImplGetI( pElement->nIndexPrecision ));
41 break;
42 case 0x03 : /*Line Width*/
44 double nWidth;
45 if ( pElement->eLineWidthSpecMode == SM_ABSOLUTE )
47 if ( pElement->eVDCType == VDC_REAL )
48 nWidth = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
49 else
50 nWidth = static_cast<double>(ImplGetI( pElement->nVDCIntegerPrecision ));
52 ImplMapDouble( nWidth );
54 else
55 nWidth = static_cast<sal_uInt32>(ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize )) * 25; // scaling in 1/4 mm
57 if ( pElement->nAspectSourceFlags & ASF_LINEWIDTH )
58 pElement->pLineBundle->nLineWidth = nWidth;
59 else
60 pElement->aLineBundle.nLineWidth = nWidth;
62 break;
63 case 0x04 : /*Line Color*/
65 if ( pElement->nAspectSourceFlags & ASF_LINECOLOR )
66 pElement->pLineBundle->SetColor( ImplGetBitmapColor() );
67 else
68 pElement->aLineBundle.SetColor( ImplGetBitmapColor() );
70 break;
71 case 0x05 : /*Marker Bundle Index*/
72 pElement->pMarkerBundle = static_cast<MarkerBundle*>(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aMarkerList, pElement->aMarkerBundle ));
73 break;
74 case 0x06 : /*Marker Type*/
76 if ( pElement->nAspectSourceFlags & ASF_MARKERTYPE )
77 pElement->pMarkerBundle->eMarkerType = static_cast<MarkerType>(ImplGetI( pElement->nIndexPrecision ));
78 else
79 pElement->aMarkerBundle.eMarkerType = static_cast<MarkerType>(ImplGetI( pElement->nIndexPrecision ));
81 break;
82 case 0x07 : /*Marker Size*/
84 double nWidth;
85 if ( pElement->eMarkerSizeSpecMode == SM_ABSOLUTE )
87 if ( pElement->eVDCType == VDC_REAL )
88 nWidth = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
89 else
90 nWidth = static_cast<double>(ImplGetI( pElement->nVDCIntegerPrecision ));
91 ImplMapDouble( nWidth );
93 else
94 nWidth = static_cast<sal_uInt32>(ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize )) * 25;
95 if ( pElement->nAspectSourceFlags & ASF_MARKERSIZE )
96 pElement->pMarkerBundle->nMarkerSize = nWidth;
97 else
98 pElement->aMarkerBundle.nMarkerSize = nWidth;
100 break;
101 case 0x08 : /*Marker Color*/
103 if ( pElement->nAspectSourceFlags & ASF_MARKERCOLOR )
104 pElement->pMarkerBundle->SetColor( ImplGetBitmapColor() );
105 else
106 pElement->aMarkerBundle.SetColor( ImplGetBitmapColor() );
108 break;
109 case 0x09 : /*Text Bundle Index*/
110 pElement->pTextBundle = static_cast<TextBundle*>(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aTextList, pElement->aTextBundle ));
111 break;
112 case 0x0a : /*Text Font Index*/
114 if ( pElement->nAspectSourceFlags & ASF_TEXTFONTINDEX )
115 pElement->pTextBundle->nTextFontIndex = ImplGetI( pElement->nIndexPrecision );
116 else
117 pElement->aTextBundle.nTextFontIndex = ImplGetI( pElement->nIndexPrecision );
119 break;
120 case 0x0b : /*Text Precision*/
122 TextBundle* pBundle;
123 if ( pElement->nAspectSourceFlags & ASF_TEXTPRECISION )
124 pBundle = pElement->pTextBundle;
125 else
126 pBundle = &pElement->aTextBundle;
127 switch( ImplGetUI16() )
129 case 0 : pBundle->eTextPrecision = TPR_STRING; break;
130 case 1 : pBundle->eTextPrecision = TPR_CHARACTER; break;
131 case 2 : pBundle->eTextPrecision = TPR_STROKE; break;
132 default : pBundle->eTextPrecision = TPR_UNDEFINED; break;
135 break;
136 case 0x0c : /*Character Expansion Factor*/
138 if ( pElement->nAspectSourceFlags & ASF_CHARACTEREXPANSION )
139 pElement->pTextBundle->nCharacterExpansion = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize );
140 else
141 pElement->aTextBundle.nCharacterExpansion = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize );
143 break;
144 case 0x0d : /*Character Spacing*/
146 if ( pElement->nAspectSourceFlags & ASF_CHARACTERSPACING )
147 pElement->pTextBundle->nCharacterSpacing = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize );
148 else
149 pElement->aTextBundle.nCharacterSpacing = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize );
151 break;
152 case 0x0e : /*Text Color*/
154 if ( pElement->nAspectSourceFlags & ASF_TEXTCOLOR )
155 pElement->pTextBundle->SetColor( ImplGetBitmapColor() );
156 else
157 pElement->aTextBundle.SetColor( ImplGetBitmapColor() );
159 break;
160 case 0x0f : /*Character Height*/
162 if ( pElement->eVDCType == VDC_INTEGER )
163 pElement->nCharacterHeight = ImplGetI( pElement->nVDCIntegerPrecision );
164 else // ->floating points
165 pElement->nCharacterHeight = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
166 ImplMapDouble( pElement->nCharacterHeight );
167 pElement->nCharacterHeight /= 18.0;
169 break;
170 case 0x10 : /*Character Orientation*/
172 if ( pElement->eVDCType == VDC_INTEGER )
174 pElement->nCharacterOrientation[0] = ImplGetI( pElement->nVDCIntegerPrecision );
175 pElement->nCharacterOrientation[1] = ImplGetI( pElement->nVDCIntegerPrecision );
176 pElement->nCharacterOrientation[2] = ImplGetI( pElement->nVDCIntegerPrecision );
177 pElement->nCharacterOrientation[3] = ImplGetI( pElement->nVDCIntegerPrecision );
179 else // ->floating points
181 pElement->nCharacterOrientation[0] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
182 pElement->nCharacterOrientation[1] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
183 pElement->nCharacterOrientation[2] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
184 pElement->nCharacterOrientation[3] = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
187 break;
188 case 0x11 : /*Text Path*/
190 switch( ImplGetUI16() )
192 case 0 : pElement->eTextPath = TPR_RIGHT; break;
193 case 1 : pElement->eTextPath = TPR_LEFT; break;
194 case 2 : pElement->eTextPath = TPR_UP; break;
195 case 3 : pElement->eTextPath = TPR_DOWN; break;
196 default : mbStatus = false; break;
199 break;
200 case 0x12 : /*Text Alignment*/
202 auto nTextAlign = ImplGetUI16();
203 if (nTextAlign > TextAlignmentH::TAH_CONT)
204 SAL_WARN("filter.icgm", "TextAlign out of range");
205 else
206 pElement->eTextAlignmentH = static_cast<TextAlignmentH>(nTextAlign);
207 nTextAlign = ImplGetUI16();
208 if (nTextAlign > TextAlignmentV::TAV_CONT)
209 SAL_WARN("filter.icgm", "TextAlign out of range");
210 else
211 pElement->eTextAlignmentV = static_cast<TextAlignmentV>(nTextAlign);
212 pElement->nTextAlignmentHCont = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize );
213 pElement->nTextAlignmentVCont = ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize );
215 break;
216 case 0x13 : /*Character Set Index*/
217 pElement->nCharacterSetIndex = ImplGetI( pElement->nIndexPrecision );
218 break;
219 case 0x14 : /*Alternate Character Set Index*/
220 pElement->nAlternateCharacterSetIndex = ImplGetI( pElement->nIndexPrecision );
221 break;
222 case 0x15 : /*Fill Bundle Index*/
223 pElement->pFillBundle = static_cast<FillBundle*>(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aFillList, pElement->aFillBundle ));
224 break;
225 case 0x16 : /*Fill Interior Style*/
227 if ( pElement->nAspectSourceFlags & ASF_FILLINTERIORSTYLE )
228 pElement->pFillBundle->eFillInteriorStyle = static_cast<FillInteriorStyle>(ImplGetUI16());
229 else
230 pElement->aFillBundle.eFillInteriorStyle = static_cast<FillInteriorStyle>(ImplGetUI16());
232 break;
233 case 0x17 : /*Fill Color*/
235 if ( pElement->nAspectSourceFlags & ASF_FILLCOLOR )
236 pElement->pFillBundle->SetColor( ImplGetBitmapColor() );
237 else
238 pElement->aFillBundle.SetColor( ImplGetBitmapColor() );
240 break;
241 case 0x18 : /*Fill Hatch Index*/
243 if ( pElement->nAspectSourceFlags & ASF_HATCHINDEX )
244 pElement->pFillBundle->nFillHatchIndex = ImplGetI( pElement->nIndexPrecision );
245 else
246 pElement->aFillBundle.nFillHatchIndex = ImplGetI( pElement->nIndexPrecision );
248 break;
249 case 0x19 : /*Fill Pattern Index*/
251 if ( pElement->nAspectSourceFlags & ASF_PATTERNINDEX )
252 pElement->pFillBundle->nFillPatternIndex = ImplGetI( pElement->nIndexPrecision );
253 else
254 pElement->aFillBundle.nFillPatternIndex = ImplGetI( pElement->nIndexPrecision );
256 break;
257 case 0x1a : /*Edge Bundle Index*/
258 pElement->pEdgeBundle = static_cast<EdgeBundle*>(CGMElements::GetBundleIndex( ImplGetI( pElement->nIndexPrecision ), pElement->aEdgeList, pElement->aEdgeBundle ));
259 break;
260 case 0x1b : /*Edge Type*/
262 if ( pElement->nAspectSourceFlags & ASF_EDGETYPE )
263 pElement->pEdgeBundle->eEdgeType = static_cast<EdgeType>(ImplGetI( pElement->nIndexPrecision ));
264 else
265 pElement->aEdgeBundle.eEdgeType = static_cast<EdgeType>(ImplGetI( pElement->nIndexPrecision ));
267 break;
268 case 0x1c : /*Edge Width*/
270 double nWidth;
271 if ( pElement->eEdgeWidthSpecMode == SM_ABSOLUTE )
273 if ( pElement->eVDCType == VDC_REAL )
274 nWidth = ImplGetFloat( pElement->eVDCRealPrecision, pElement->nVDCRealSize );
275 else
276 nWidth = static_cast<double>(ImplGetI( pElement->nVDCIntegerPrecision ));
278 ImplMapDouble( nWidth );
280 else
281 nWidth = static_cast<sal_uInt32>(ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize )) * 25;
282 if ( pElement->nAspectSourceFlags & ASF_EDGEWIDTH )
283 pElement->pEdgeBundle->nEdgeWidth = nWidth;
284 else
285 pElement->aEdgeBundle.nEdgeWidth = nWidth;
287 break;
288 case 0x1d : /*Edge Color*/
290 if ( pElement->nAspectSourceFlags & ASF_EDGECOLOR )
291 pElement->pEdgeBundle->SetColor( ImplGetBitmapColor() );
292 else
293 pElement->aEdgeBundle.SetColor( ImplGetBitmapColor() );
295 break;
296 case 0x1e : /*Edge Visibility*/
298 switch( ImplGetUI16() )
300 case 0 : pElement->eEdgeVisibility = EV_OFF; break;
301 case 1 : pElement->eEdgeVisibility = EV_ON; break;
302 default : mbStatus = false;
305 break;
306 case 0x1f : /*Fill Reference Point*/
307 ImplGetPoint( pElement->aFillRefPoint );
308 break;
309 case 0x20 : /*Pattern Table" )*/ break;
310 case 0x21 : /*Pattern Size" )*/ break;
311 case 0x22 : /*Color Table*/
313 sal_uInt32 nColorStartIndex = ImplGetUI( pElement->nColorIndexPrecision );
314 if ( ( nColorStartIndex > 255 ) ||
315 ( ( ( mnElementSize - pElement->nColorIndexPrecision ) % ( pElement->nColorPrecision * 3 ) ) != 0 ) )
317 mbStatus = false;
319 else
321 sal_uInt32 nColors = ( mnElementSize - pElement->nColorIndexPrecision ) / ( 3 * pElement->nColorPrecision );
322 if ( nColors )
324 sal_uInt32 nMaxColorIndex = nColorStartIndex + nColors - 1;
325 sal_uInt32 nIndex;
326 if ( nMaxColorIndex > 255 )
328 mbStatus = false;
329 break;
331 if ( pElement->nLatestColorMaximumIndex < nMaxColorIndex )
332 pElement->nLatestColorMaximumIndex = nMaxColorIndex;
334 for ( nIndex = nColorStartIndex; nIndex <= nMaxColorIndex; nIndex++ )
336 pElement->aLatestColorTable[ nIndex ] = ImplGetBitmapColor( true );
339 pElement->nColorMaximumIndex = pElement->nLatestColorMaximumIndex;
340 for ( nIndex = nColorStartIndex; nIndex <= nMaxColorIndex; nIndex++ )
342 if ( !pElement->aColorTableEntryIs[ nIndex ] )
344 pElement->aColorTableEntryIs[ nIndex ] = 1;
345 pElement->aColorTable[ nIndex ] = pElement->aLatestColorTable[ nIndex ];
351 break;
352 case 0x23 : /*Aspect Source Flags*/
354 int nFlags = mnElementSize >> 2;
355 while ( nFlags-- > 0 )
357 sal_uInt32 nFlag = 0;
358 switch( ImplGetUI16() )
360 case 0 : nFlag = ASF_LINETYPE; break;
361 case 1 : nFlag = ASF_LINEWIDTH; break;
362 case 2 : nFlag = ASF_LINECOLOR; break;
363 case 3 : nFlag = ASF_MARKERTYPE; break;
364 case 4 : nFlag = ASF_MARKERSIZE; break;
365 case 5 : nFlag = ASF_MARKERCOLOR; break;
366 case 6 : nFlag = ASF_FILLINTERIORSTYLE; break;
367 case 7 : nFlag = ASF_HATCHINDEX; break;
368 case 8 : nFlag = ASF_PATTERNINDEX; break;
369 case 9 : nFlag = ASF_BITMAPINDEX; break;
370 case 10 : nFlag = ASF_FILLCOLOR; break;
371 case 11 : nFlag = ASF_EDGETYPE; break;
372 case 12 : nFlag = ASF_EDGEWIDTH; break;
373 case 13 : nFlag = ASF_EDGECOLOR; break;
374 case 14 : nFlag = ASF_TEXTFONTINDEX; break;
375 case 15 : nFlag = ASF_TEXTPRECISION; break;
376 case 16 : nFlag = ASF_CHARACTEREXPANSION; break;
377 case 17 : nFlag = ASF_CHARACTERSPACING; break;
378 case 18 : nFlag = ASF_TEXTCOLOR; break;
379 default : mbStatus = false; break;
381 sal_uInt32 nASF = ImplGetUI16();
382 switch ( nASF )
384 case 0 : pElement->nAspectSourceFlags &= ~nFlag; break; // INDIVIDUAL
385 case 1 : pElement->nAspectSourceFlags |= nFlag; break; // BUNDLED
386 default : mbStatus = false; break;
390 break;
391 case 0x24 : /*Pick Identifier*/ break;
392 case 0x25 : /*Line Cap*/
394 switch( ImplGetUI16() )
396 case 0 : pElement->eLineCapType = LCT_BUTT; break;
397 case 1 : pElement->eLineCapType = LCT_ROUND; break;
398 case 2 : pElement->eLineCapType = LCT_SQUARE; break;
399 case 3 : pElement->eLineCapType = LCT_TRIANGLE; break;
400 case 4 : pElement->eLineCapType = LCT_ARROW; break;
401 default : pElement->eLineCapType = LCT_NONE; break;
404 break;
405 case 0x26 : /*Line Join*/
407 switch( ImplGetUI16() )
409 case 0 : pElement->eLineJoinType = LJT_MITER; break;
410 case 1 : pElement->eLineJoinType = LJT_ROUND; break;
411 case 2 : pElement->eLineJoinType = LJT_BEVEL; break;
412 default : pElement->eLineJoinType = LJT_NONE; break;
415 break;
416 case 0x27 : /*Line Type Continuation*/ break; // NS
417 case 0x28 : /*Line Type Initial Offset*/ break; // NS
418 case 0x29 : /*Text Score Type*/ break;
419 case 0x2a : /*Restricted Text Type*/ break;
420 case 0x2b : /*Interpolated interior*/ break;
421 case 0x2c : /*Edge Cap*/ break; // NS
422 case 0x2d : /*Edge Join*/ break;
423 case 0x2e : /*Edge Type Continuation*/ break; // NS
424 case 0x2f : /*Edge Type Initial Offset*/ break; // NS
425 case 0x30 : /*Symbol Library Index*/ break; // NS
426 case 0x31 : /*Symbol Color*/ break; // NS
427 case 0x32 : /*Symbol Size*/ break; // NS
428 case 0x33 : /*Symbol Orientation*/ break; // NS
429 case 0x50 : /*Block Text vcl::Region Margins*/ break;
430 case 0x51 : /*Block Text vcl::Region Expansion*/ break;
431 case 0x52 : /*Block Text vcl::Region Anchor*/ break;
432 case 0x53 : /*Block Text Paragraph Horizontal Alignment*/ break;
433 case 0x54 : /*Block Text Paragraph Vertical Alignment*/ break;
434 case 0x55 : /*Block Text Line Flow*/ break;
435 case 0x60 : /*Block Text Paragraph Spacing*/ break;
436 case 0x61 : /*Block Text Paragraph Indent*/ break;
437 case 0x62 : /*Block Text Paragraph Tabs*/ break;
438 case 0x63 : /*Block Text Paragraph Bullets*/ break;
439 case 0x64 : /*Block Text Paragraph Bullet Level*/ break;
440 case 0x65 : /*Block Text Paragraph Line Horizontal Alignment*/ break;
441 case 0x66 : /*Block Text Paragraph Line Vertical Alignment*/ break;
442 case 0x67 : /*Block Text Paragragh Line Spacing*/ break;
443 case 0x68 : /*Block Text Paragraph Word Wrap*/ break;
444 case 0x70 : /*Block Text Forward Advance Distance*/ break;
445 case 0x71 : /*Word Spacing*/ break;
446 case 0x72 : /*External Leading*/ break;
447 case 0x7a : /*set Gradient Offset*/
449 tools::Long nHorzOffset = ImplGetI( pElement->nIndexPrecision );
450 tools::Long nVertOffset = ImplGetI( pElement->nIndexPrecision );
451 (void)ImplGetUI16(); // nType
452 mpOutAct->SetGradientOffset( nHorzOffset, nVertOffset );
453 mnAct4PostReset |= ACT4_GRADIENT_ACTION;
455 break;
456 case 0x7b : /*set Gradient Edge*/
458 mnAct4PostReset |= ACT4_GRADIENT_ACTION;
460 break;
461 case 0x7c : /*set Gradient Angle*/
463 mpOutAct->SetGradientAngle( ImplGetI( pElement->nIndexPrecision ) );
464 mnAct4PostReset |= ACT4_GRADIENT_ACTION;
466 break;
467 case 0x7d : /*set Gradient Description*/
469 ImplGetI( pElement->nIndexPrecision ); // -Wall is this needed?
470 sal_uInt32 nNumberOfStages = ImplGetI( pElement->nIndexPrecision );
471 sal_uInt32 i, nColorFrom = 0;
472 sal_uInt32 nColorTo = 0xffffff;
474 const size_t nRemainingSize = mpEndValidSource - (mpSource + mnParaSize);
475 const size_t nMaxPossibleRecords = nRemainingSize/pElement->nRealSize;
477 if (nNumberOfStages > nMaxPossibleRecords)
479 mbStatus = false;
480 break;
483 for ( i = 0; i < nNumberOfStages; i++ )
485 ImplGetFloat(pElement->eRealPrecision, pElement->nRealSize);
488 for ( i = 0; i <= nNumberOfStages; i++ )
490 sal_uInt32 nPara = mnParaSize + 24;
491 if ( i == 0 )
493 nColorTo = ImplGetBitmapColor();
494 nColorFrom = nColorTo ^ 0xffffff;
496 else if ( i == 1 )
497 nColorFrom = ImplGetBitmapColor();
498 mnParaSize = nPara;
500 if ( nNumberOfStages > 1 )
501 mpOutAct->SetGradientStyle( 0xff );
503 mpOutAct->SetGradientDescriptor( nColorFrom, nColorTo );
504 mnAct4PostReset |= ACT4_GRADIENT_ACTION;
506 break;
507 case 0x7e : /*set Gradient Style*/
509 sal_uInt32 nStyle = ImplGetUI16();
510 (void)ImplGetFloat( pElement->eRealPrecision, pElement->nRealSize ); // fRatio
511 mpOutAct->SetGradientStyle( nStyle );
512 mnAct4PostReset |= ACT4_GRADIENT_ACTION;
514 break;
515 case 0xff : /*inquire Font metrics*/ break;
516 case 0xfe : /*inquire character widths*/ break;
517 case 0xfd : /*set Text Font*/ break;
518 case 0xfc : /*set current position*/ break;
519 case 0xfb : /*set current position mode*/ break;
520 case 0xfa : /*set character height mode*/ break;
521 case 0xf9 : /*set Transform matrix 2D*/ break;
522 case 0xf8 : /*set Transform matrix 3D*/ break;
523 case 0xf7 : /*pop transformation state*/ break;
524 case 0xf6 : /*clear transformation state*/ break;
525 case 0xf5 : /*set character widths*/ break;
526 case 0xf4 : /*set color name - for Pantone support*/ break;
527 default: break;
532 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */