Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
58 / 58
CRAP
100.00% covered (success)
100.00%
1 / 1
Paragraph
100.00% covered (success)
100.00%
116 / 116
100.00% covered (success)
100.00%
58 / 58
68
100.00% covered (success)
100.00%
1 / 1
 setStyleValue
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 getStyleValues
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
1
 getAlignment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setAlignment
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getBasedOn
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setBasedOn
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getNext
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setNext
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getHanging
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIndent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIndentation
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIndentFirstLine
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIndentLeft
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getIndentRight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setHanging
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIndent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIndentation
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 setIndentHanging
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIndentFirstLine
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIndentFirstLineChars
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIndentLeft
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setIndentRight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSpace
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSpace
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getSpaceBefore
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSpaceBefore
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSpaceAfter
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSpaceAfter
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSpacing
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSpacing
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getSpacingLineRule
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSpacingLineRule
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getLineHeight
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setLineHeight
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
 hasWidowControl
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setWidowControl
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isKeepNext
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setKeepNext
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isKeepLines
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setKeepLines
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 hasPageBreakBefore
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setPageBreakBefore
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getNumStyle
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setNumStyle
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getNumLevel
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setNumLevel
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getTabs
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTabs
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 getShading
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setShading
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 hasContextualSpacing
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setContextualSpacing
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 isBidi
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setBidi
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getTextAlignment
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setTextAlignment
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 hasSuppressAutoHyphens
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 setSuppressAutoHyphens
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3/**
4 * This file is part of PHPWord - A pure PHP library for reading and writing
5 * word processing documents.
6 *
7 * PHPWord is free software distributed under the terms of the GNU Lesser
8 * General Public License version 3 as published by the Free Software Foundation.
9 *
10 * For the full copyright and license information, please read the LICENSE
11 * file that was distributed with this source code. For the full list of
12 * contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
13 *
14 * @see         https://github.com/PHPOffice/PHPWord
15 *
16 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17 */
18
19namespace PhpOffice\PhpWord\Style;
20
21use PhpOffice\PhpWord\Exception\InvalidStyleException;
22use PhpOffice\PhpWord\Settings;
23use PhpOffice\PhpWord\Shared\Text;
24use PhpOffice\PhpWord\SimpleType\Jc;
25use PhpOffice\PhpWord\SimpleType\TextAlignment;
26
27/**
28 * Paragraph style.
29 *
30 * OOXML:
31 * - General: alignment, outline level
32 * - Indentation: left, right, firstline, hanging
33 * - Spacing: before, after, line spacing
34 * - Pagination: widow control, keep next, keep line, page break before
35 * - Formatting exception: suppress line numbers, don't hyphenate
36 * - Textbox options
37 * - Tabs
38 * - Shading
39 * - Borders
40 *
41 * OpenOffice:
42 * - Indents & spacing
43 * - Alignment
44 * - Text flow
45 * - Outline & numbering
46 * - Tabs
47 * - Dropcaps
48 * - Tabs
49 * - Borders
50 * - Background
51 *
52 * @see  http://www.schemacentral.com/sc/ooxml/t-w_CT_PPr.html
53 */
54class Paragraph extends Border
55{
56    /**
57     * @const int One line height equals 240 twip
58     */
59    const LINE_HEIGHT = 240;
60
61    /**
62     * Aliases.
63     *
64     * @var array
65     */
66    protected $aliases = ['line-height' => 'lineHeight', 'line-spacing' => 'spacing'];
67
68    /**
69     * Parent style.
70     *
71     * @var string
72     */
73    private $basedOn = 'Normal';
74
75    /**
76     * Style for next paragraph.
77     *
78     * @var string
79     */
80    private $next;
81
82    /**
83     * @var string
84     */
85    private $alignment = '';
86
87    /**
88     * Indentation.
89     *
90     * @var null|Indentation
91     */
92    private $indentation;
93
94    /**
95     * Spacing.
96     *
97     * @var Spacing
98     */
99    private $spacing;
100
101    /**
102     * Text line height.
103     *
104     * @var null|float|int
105     */
106    private $lineHeight;
107
108    /**
109     * Allow first/last line to display on a separate page.
110     *
111     * @var bool
112     */
113    private $widowControl = true;
114
115    /**
116     * Keep paragraph with next paragraph.
117     *
118     * @var bool
119     */
120    private $keepNext = false;
121
122    /**
123     * Keep all lines on one page.
124     *
125     * @var bool
126     */
127    private $keepLines = false;
128
129    /**
130     * Start paragraph on next page.
131     *
132     * @var bool
133     */
134    private $pageBreakBefore = false;
135
136    /**
137     * Numbering style name.
138     *
139     * @var string
140     */
141    private $numStyle;
142
143    /**
144     * Numbering level.
145     *
146     * @var int
147     */
148    private $numLevel = 0;
149
150    /**
151     * Set of Custom Tab Stops.
152     *
153     * @var Tab[]
154     */
155    private $tabs = [];
156
157    /**
158     * Shading.
159     *
160     * @var Shading
161     */
162    private $shading;
163
164    /**
165     * Ignore Spacing Above and Below When Using Identical Styles.
166     *
167     * @var bool
168     */
169    private $contextualSpacing = false;
170
171    /**
172     * Right to Left Paragraph Layout.
173     *
174     * @var ?bool
175     */
176    private $bidi;
177
178    /**
179     * Vertical Character Alignment on Line.
180     *
181     * @var string
182     */
183    private $textAlignment;
184
185    /**
186     * Suppress hyphenation for paragraph.
187     *
188     * @var bool
189     */
190    private $suppressAutoHyphens = false;
191
192    /**
193     * Set Style value.
194     *
195     * @param string $key
196     * @param mixed $value
197     *
198     * @return self
199     */
200    public function setStyleValue($key, $value)
201    {
202        $key = Text::removeUnderscorePrefix($key);
203        if ('indent' == $key || 'hanging' == $key) {
204            $value = $value * 720;  // 720 twips is 0.5 inch
205        }
206
207        return parent::setStyleValue($key, $value);
208    }
209
210    /**
211     * Get style values.
212     *
213     * An experiment to retrieve all style values in one function. This will
214     * reduce function call and increase cohesion between functions. Should be
215     * implemented in all styles.
216     *
217     * @ignoreScrutinizerPatch
218     *
219     * @return array
220     */
221    public function getStyleValues()
222    {
223        $styles = [
224            'name' => $this->getStyleName(),
225            'basedOn' => $this->getBasedOn(),
226            'next' => $this->getNext(),
227            'alignment' => $this->getAlignment(),
228            'indentation' => $this->getIndentation(),
229            'spacing' => $this->getSpace(),
230            'pagination' => [
231                'widowControl' => $this->hasWidowControl(),
232                'keepNext' => $this->isKeepNext(),
233                'keepLines' => $this->isKeepLines(),
234                'pageBreak' => $this->hasPageBreakBefore(),
235            ],
236            'numbering' => [
237                'style' => $this->getNumStyle(),
238                'level' => $this->getNumLevel(),
239            ],
240            'tabs' => $this->getTabs(),
241            'shading' => $this->getShading(),
242            'contextualSpacing' => $this->hasContextualSpacing(),
243            'bidi' => $this->isBidi(),
244            'textAlignment' => $this->getTextAlignment(),
245            'suppressAutoHyphens' => $this->hasSuppressAutoHyphens(),
246        ];
247
248        return $styles;
249    }
250
251    /**
252     * @since 0.13.0
253     *
254     * @return string
255     */
256    public function getAlignment()
257    {
258        return $this->alignment;
259    }
260
261    /**
262     * @since 0.13.0
263     *
264     * @param string $value
265     *
266     * @return self
267     */
268    public function setAlignment($value)
269    {
270        if (Jc::isValid($value)) {
271            $this->alignment = $value;
272        }
273
274        return $this;
275    }
276
277    /**
278     * Get parent style ID.
279     *
280     * @return string
281     */
282    public function getBasedOn()
283    {
284        return $this->basedOn;
285    }
286
287    /**
288     * Set parent style ID.
289     *
290     * @param string $value
291     *
292     * @return self
293     */
294    public function setBasedOn($value = 'Normal')
295    {
296        $this->basedOn = $value;
297
298        return $this;
299    }
300
301    /**
302     * Get style for next paragraph.
303     *
304     * @return string
305     */
306    public function getNext()
307    {
308        return $this->next;
309    }
310
311    /**
312     * Set style for next paragraph.
313     *
314     * @param string $value
315     *
316     * @return self
317     */
318    public function setNext($value = null)
319    {
320        $this->next = $value;
321
322        return $this;
323    }
324
325    /**
326     * Get hanging.
327     */
328    public function getHanging(): ?float
329    {
330        return $this->getChildStyleValue($this->indentation, 'hanging');
331    }
332
333    /**
334     * Get indentation.
335     *
336     * @deprecated 1.4.0 Use getIndentLeft
337     */
338    public function getIndent(): ?float
339    {
340        return $this->getChildStyleValue($this->indentation, 'left');
341    }
342
343    /**
344     * Get indentation.
345     */
346    public function getIndentation(): ?Indentation
347    {
348        return $this->indentation;
349    }
350
351    /**
352     * Get firstLine.
353     */
354    public function getIndentFirstLine(): ?float
355    {
356        return $this->getChildStyleValue($this->indentation, 'firstLine');
357    }
358
359    /**
360     * Get left indentation.
361     */
362    public function getIndentLeft(): ?float
363    {
364        return $this->getChildStyleValue($this->indentation, 'left');
365    }
366
367    /**
368     * Get right indentation.
369     */
370    public function getIndentRight(): ?float
371    {
372        return $this->getChildStyleValue($this->indentation, 'right');
373    }
374
375    /**
376     * Set hanging.
377     *
378     * @deprecated 1.4.0 Use setIndentHanging
379     */
380    public function setHanging(?float $value = null): self
381    {
382        return $this->setIndentation(['hanging' => $value]);
383    }
384
385    /**
386     * Set indentation.
387     *
388     * @deprecated 1.4.0 Use setIndentLeft
389     */
390    public function setIndent(?float $value = null): self
391    {
392        return $this->setIndentation(['left' => $value]);
393    }
394
395    /**
396     * Set indentation.
397     *
398     * @param array{
399     *     left?:null|float|int|numeric-string,
400     *     right?:null|float|int|numeric-string,
401     *     hanging?:null|float|int|numeric-string,
402     *     firstLine?:null|float|int|numeric-string
403     * } $value
404     */
405    public function setIndentation(array $value = []): self
406    {
407        $value = array_map(function ($indent) {
408            if (is_string($indent) || is_numeric($indent)) {
409                $indent = $this->setFloatVal($indent);
410            }
411
412            return $indent;
413        }, $value);
414        $this->setObjectVal($value, 'Indentation', $this->indentation);
415
416        return $this;
417    }
418
419    /**
420     * Set hanging indentation.
421     */
422    public function setIndentHanging(?float $value = null): self
423    {
424        return $this->setIndentation(['hanging' => $value]);
425    }
426
427    /**
428     * Set firstline indentation.
429     */
430    public function setIndentFirstLine(?float $value = null): self
431    {
432        return $this->setIndentation(['firstLine' => $value]);
433    }
434
435    /**
436     * Set firstlineChars indentation.
437     */
438    public function setIndentFirstLineChars(int $value = 0): self
439    {
440        return $this->setIndentation(['firstLineChars' => $value]);
441    }
442
443    /**
444     * Set left indentation.
445     */
446    public function setIndentLeft(?float $value = null): self
447    {
448        return $this->setIndentation(['left' => $value]);
449    }
450
451    /**
452     * Set right indentation.
453     */
454    public function setIndentRight(?float $value = null): self
455    {
456        return $this->setIndentation(['right' => $value]);
457    }
458
459    /**
460     * Get spacing.
461     *
462     * @return Spacing
463     *
464     * @todo Rename to getSpacing in 1.0
465     */
466    public function getSpace()
467    {
468        return $this->spacing;
469    }
470
471    /**
472     * Set spacing.
473     *
474     * @param mixed $value
475     *
476     * @return self
477     *
478     * @todo Rename to setSpacing in 1.0
479     */
480    public function setSpace($value = null)
481    {
482        $this->setObjectVal($value, 'Spacing', $this->spacing);
483
484        return $this;
485    }
486
487    /**
488     * Get space before paragraph.
489     *
490     * @return null|float|int
491     */
492    public function getSpaceBefore()
493    {
494        return $this->getChildStyleValue($this->spacing, 'before');
495    }
496
497    /**
498     * Set space before paragraph.
499     *
500     * @param null|float|int $value
501     *
502     * @return self
503     */
504    public function setSpaceBefore($value = null)
505    {
506        return $this->setSpace(['before' => $value]);
507    }
508
509    /**
510     * Get space after paragraph.
511     *
512     * @return null|float|int
513     */
514    public function getSpaceAfter()
515    {
516        return $this->getChildStyleValue($this->spacing, 'after');
517    }
518
519    /**
520     * Set space after paragraph.
521     *
522     * @param null|float|int $value
523     *
524     * @return self
525     */
526    public function setSpaceAfter($value = null)
527    {
528        return $this->setSpace(['after' => $value]);
529    }
530
531    /**
532     * Get spacing between lines.
533     *
534     * @return null|float|int
535     */
536    public function getSpacing()
537    {
538        return $this->getChildStyleValue($this->spacing, 'line');
539    }
540
541    /**
542     * Set spacing between lines.
543     *
544     * @param null|float|int $value
545     *
546     * @return self
547     */
548    public function setSpacing($value = null)
549    {
550        return $this->setSpace(['line' => $value]);
551    }
552
553    /**
554     * Get spacing line rule.
555     *
556     * @return string
557     */
558    public function getSpacingLineRule()
559    {
560        return $this->getChildStyleValue($this->spacing, 'lineRule');
561    }
562
563    /**
564     * Set the spacing line rule.
565     *
566     * @param string $value Possible values are defined in LineSpacingRule
567     *
568     * @return Paragraph
569     */
570    public function setSpacingLineRule($value)
571    {
572        return $this->setSpace(['lineRule' => $value]);
573    }
574
575    /**
576     * Get line height.
577     *
578     * @return null|float|int
579     */
580    public function getLineHeight()
581    {
582        return $this->lineHeight;
583    }
584
585    /**
586     * Set the line height.
587     *
588     * @param float|int|string $lineHeight
589     *
590     * @return self
591     */
592    public function setLineHeight($lineHeight)
593    {
594        if (is_string($lineHeight)) {
595            $lineHeight = (float) (preg_replace('/[^0-9\.\,]/', '', $lineHeight));
596        }
597
598        if ((!is_int($lineHeight) && !is_float($lineHeight)) || !$lineHeight) {
599            throw new InvalidStyleException('Line height must be a valid number');
600        }
601
602        $this->lineHeight = $lineHeight;
603        $this->setSpacing(($lineHeight - 1) * self::LINE_HEIGHT);
604        $this->setSpacingLineRule(\PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO);
605
606        return $this;
607    }
608
609    /**
610     * Get allow first/last line to display on a separate page setting.
611     *
612     * @return bool
613     */
614    public function hasWidowControl()
615    {
616        return $this->widowControl;
617    }
618
619    /**
620     * Set keep paragraph with next paragraph setting.
621     *
622     * @param bool $value
623     *
624     * @return self
625     */
626    public function setWidowControl($value = true)
627    {
628        $this->widowControl = $this->setBoolVal($value, $this->widowControl);
629
630        return $this;
631    }
632
633    /**
634     * Get keep paragraph with next paragraph setting.
635     *
636     * @return bool
637     */
638    public function isKeepNext()
639    {
640        return $this->keepNext;
641    }
642
643    /**
644     * Set keep paragraph with next paragraph setting.
645     *
646     * @param bool $value
647     *
648     * @return self
649     */
650    public function setKeepNext($value = true)
651    {
652        $this->keepNext = $this->setBoolVal($value, $this->keepNext);
653
654        return $this;
655    }
656
657    /**
658     * Get keep all lines on one page setting.
659     *
660     * @return bool
661     */
662    public function isKeepLines()
663    {
664        return $this->keepLines;
665    }
666
667    /**
668     * Set keep all lines on one page setting.
669     *
670     * @param bool $value
671     *
672     * @return self
673     */
674    public function setKeepLines($value = true)
675    {
676        $this->keepLines = $this->setBoolVal($value, $this->keepLines);
677
678        return $this;
679    }
680
681    /**
682     * Get start paragraph on next page setting.
683     *
684     * @return bool
685     */
686    public function hasPageBreakBefore()
687    {
688        return $this->pageBreakBefore;
689    }
690
691    /**
692     * Set start paragraph on next page setting.
693     *
694     * @param bool $value
695     *
696     * @return self
697     */
698    public function setPageBreakBefore($value = true)
699    {
700        $this->pageBreakBefore = $this->setBoolVal($value, $this->pageBreakBefore);
701
702        return $this;
703    }
704
705    /**
706     * Get numbering style name.
707     *
708     * @return string
709     */
710    public function getNumStyle()
711    {
712        return $this->numStyle;
713    }
714
715    /**
716     * Set numbering style name.
717     *
718     * @param string $value
719     *
720     * @return self
721     */
722    public function setNumStyle($value)
723    {
724        $this->numStyle = $value;
725
726        return $this;
727    }
728
729    /**
730     * Get numbering level.
731     *
732     * @return int
733     */
734    public function getNumLevel()
735    {
736        return $this->numLevel;
737    }
738
739    /**
740     * Set numbering level.
741     *
742     * @param int $value
743     *
744     * @return self
745     */
746    public function setNumLevel($value = 0)
747    {
748        $this->numLevel = $this->setIntVal($value, $this->numLevel);
749
750        return $this;
751    }
752
753    /**
754     * Get tabs.
755     *
756     * @return Tab[]
757     */
758    public function getTabs()
759    {
760        return $this->tabs;
761    }
762
763    /**
764     * Set tabs.
765     *
766     * @param array $value
767     *
768     * @return self
769     */
770    public function setTabs($value = null)
771    {
772        if (is_array($value)) {
773            $this->tabs = $value;
774        }
775
776        return $this;
777    }
778
779    /**
780     * Get shading.
781     *
782     * @return Shading
783     */
784    public function getShading()
785    {
786        return $this->shading;
787    }
788
789    /**
790     * Set shading.
791     *
792     * @param mixed $value
793     *
794     * @return self
795     */
796    public function setShading($value = null)
797    {
798        $this->setObjectVal($value, 'Shading', $this->shading);
799
800        return $this;
801    }
802
803    /**
804     * Get contextualSpacing.
805     *
806     * @return bool
807     */
808    public function hasContextualSpacing()
809    {
810        return $this->contextualSpacing;
811    }
812
813    /**
814     * Set contextualSpacing.
815     *
816     * @param bool $contextualSpacing
817     *
818     * @return self
819     */
820    public function setContextualSpacing($contextualSpacing)
821    {
822        $this->contextualSpacing = $contextualSpacing;
823
824        return $this;
825    }
826
827    /**
828     * Get bidirectional.
829     *
830     * @return ?bool
831     */
832    public function isBidi()
833    {
834        return $this->bidi ?? Settings::isDefaultRtl();
835    }
836
837    /**
838     * Set bidi.
839     *
840     * @param ?bool $bidi
841     *            Set to true to write from right to left
842     *
843     * @return self
844     */
845    public function setBidi($bidi)
846    {
847        $this->bidi = $bidi;
848
849        return $this;
850    }
851
852    /**
853     * Get textAlignment.
854     *
855     * @return string
856     */
857    public function getTextAlignment()
858    {
859        return $this->textAlignment;
860    }
861
862    /**
863     * Set textAlignment.
864     *
865     * @param string $textAlignment
866     *
867     * @return self
868     */
869    public function setTextAlignment($textAlignment)
870    {
871        TextAlignment::validate($textAlignment);
872        $this->textAlignment = $textAlignment;
873
874        return $this;
875    }
876
877    /**
878     * @return bool
879     */
880    public function hasSuppressAutoHyphens()
881    {
882        return $this->suppressAutoHyphens;
883    }
884
885    /**
886     * @param bool $suppressAutoHyphens
887     */
888    public function setSuppressAutoHyphens($suppressAutoHyphens): void
889    {
890        $this->suppressAutoHyphens = (bool) $suppressAutoHyphens;
891    }
892}