Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
115 / 115
100.00% covered (success)
100.00%
57 / 57
CRAP
100.00% covered (success)
100.00%
1 / 1
Paragraph
100.00% covered (success)
100.00%
115 / 115
100.00% covered (success)
100.00%
57 / 57
67
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
 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 left indentation.
437     */
438    public function setIndentLeft(?float $value = null): self
439    {
440        return $this->setIndentation(['left' => $value]);
441    }
442
443    /**
444     * Set right indentation.
445     */
446    public function setIndentRight(?float $value = null): self
447    {
448        return $this->setIndentation(['right' => $value]);
449    }
450
451    /**
452     * Get spacing.
453     *
454     * @return Spacing
455     *
456     * @todo Rename to getSpacing in 1.0
457     */
458    public function getSpace()
459    {
460        return $this->spacing;
461    }
462
463    /**
464     * Set spacing.
465     *
466     * @param mixed $value
467     *
468     * @return self
469     *
470     * @todo Rename to setSpacing in 1.0
471     */
472    public function setSpace($value = null)
473    {
474        $this->setObjectVal($value, 'Spacing', $this->spacing);
475
476        return $this;
477    }
478
479    /**
480     * Get space before paragraph.
481     *
482     * @return null|float|int
483     */
484    public function getSpaceBefore()
485    {
486        return $this->getChildStyleValue($this->spacing, 'before');
487    }
488
489    /**
490     * Set space before paragraph.
491     *
492     * @param null|float|int $value
493     *
494     * @return self
495     */
496    public function setSpaceBefore($value = null)
497    {
498        return $this->setSpace(['before' => $value]);
499    }
500
501    /**
502     * Get space after paragraph.
503     *
504     * @return null|float|int
505     */
506    public function getSpaceAfter()
507    {
508        return $this->getChildStyleValue($this->spacing, 'after');
509    }
510
511    /**
512     * Set space after paragraph.
513     *
514     * @param null|float|int $value
515     *
516     * @return self
517     */
518    public function setSpaceAfter($value = null)
519    {
520        return $this->setSpace(['after' => $value]);
521    }
522
523    /**
524     * Get spacing between lines.
525     *
526     * @return null|float|int
527     */
528    public function getSpacing()
529    {
530        return $this->getChildStyleValue($this->spacing, 'line');
531    }
532
533    /**
534     * Set spacing between lines.
535     *
536     * @param null|float|int $value
537     *
538     * @return self
539     */
540    public function setSpacing($value = null)
541    {
542        return $this->setSpace(['line' => $value]);
543    }
544
545    /**
546     * Get spacing line rule.
547     *
548     * @return string
549     */
550    public function getSpacingLineRule()
551    {
552        return $this->getChildStyleValue($this->spacing, 'lineRule');
553    }
554
555    /**
556     * Set the spacing line rule.
557     *
558     * @param string $value Possible values are defined in LineSpacingRule
559     *
560     * @return Paragraph
561     */
562    public function setSpacingLineRule($value)
563    {
564        return $this->setSpace(['lineRule' => $value]);
565    }
566
567    /**
568     * Get line height.
569     *
570     * @return null|float|int
571     */
572    public function getLineHeight()
573    {
574        return $this->lineHeight;
575    }
576
577    /**
578     * Set the line height.
579     *
580     * @param float|int|string $lineHeight
581     *
582     * @return self
583     */
584    public function setLineHeight($lineHeight)
585    {
586        if (is_string($lineHeight)) {
587            $lineHeight = (float) (preg_replace('/[^0-9\.\,]/', '', $lineHeight));
588        }
589
590        if ((!is_int($lineHeight) && !is_float($lineHeight)) || !$lineHeight) {
591            throw new InvalidStyleException('Line height must be a valid number');
592        }
593
594        $this->lineHeight = $lineHeight;
595        $this->setSpacing(($lineHeight - 1) * self::LINE_HEIGHT);
596        $this->setSpacingLineRule(\PhpOffice\PhpWord\SimpleType\LineSpacingRule::AUTO);
597
598        return $this;
599    }
600
601    /**
602     * Get allow first/last line to display on a separate page setting.
603     *
604     * @return bool
605     */
606    public function hasWidowControl()
607    {
608        return $this->widowControl;
609    }
610
611    /**
612     * Set keep paragraph with next paragraph setting.
613     *
614     * @param bool $value
615     *
616     * @return self
617     */
618    public function setWidowControl($value = true)
619    {
620        $this->widowControl = $this->setBoolVal($value, $this->widowControl);
621
622        return $this;
623    }
624
625    /**
626     * Get keep paragraph with next paragraph setting.
627     *
628     * @return bool
629     */
630    public function isKeepNext()
631    {
632        return $this->keepNext;
633    }
634
635    /**
636     * Set keep paragraph with next paragraph setting.
637     *
638     * @param bool $value
639     *
640     * @return self
641     */
642    public function setKeepNext($value = true)
643    {
644        $this->keepNext = $this->setBoolVal($value, $this->keepNext);
645
646        return $this;
647    }
648
649    /**
650     * Get keep all lines on one page setting.
651     *
652     * @return bool
653     */
654    public function isKeepLines()
655    {
656        return $this->keepLines;
657    }
658
659    /**
660     * Set keep all lines on one page setting.
661     *
662     * @param bool $value
663     *
664     * @return self
665     */
666    public function setKeepLines($value = true)
667    {
668        $this->keepLines = $this->setBoolVal($value, $this->keepLines);
669
670        return $this;
671    }
672
673    /**
674     * Get start paragraph on next page setting.
675     *
676     * @return bool
677     */
678    public function hasPageBreakBefore()
679    {
680        return $this->pageBreakBefore;
681    }
682
683    /**
684     * Set start paragraph on next page setting.
685     *
686     * @param bool $value
687     *
688     * @return self
689     */
690    public function setPageBreakBefore($value = true)
691    {
692        $this->pageBreakBefore = $this->setBoolVal($value, $this->pageBreakBefore);
693
694        return $this;
695    }
696
697    /**
698     * Get numbering style name.
699     *
700     * @return string
701     */
702    public function getNumStyle()
703    {
704        return $this->numStyle;
705    }
706
707    /**
708     * Set numbering style name.
709     *
710     * @param string $value
711     *
712     * @return self
713     */
714    public function setNumStyle($value)
715    {
716        $this->numStyle = $value;
717
718        return $this;
719    }
720
721    /**
722     * Get numbering level.
723     *
724     * @return int
725     */
726    public function getNumLevel()
727    {
728        return $this->numLevel;
729    }
730
731    /**
732     * Set numbering level.
733     *
734     * @param int $value
735     *
736     * @return self
737     */
738    public function setNumLevel($value = 0)
739    {
740        $this->numLevel = $this->setIntVal($value, $this->numLevel);
741
742        return $this;
743    }
744
745    /**
746     * Get tabs.
747     *
748     * @return Tab[]
749     */
750    public function getTabs()
751    {
752        return $this->tabs;
753    }
754
755    /**
756     * Set tabs.
757     *
758     * @param array $value
759     *
760     * @return self
761     */
762    public function setTabs($value = null)
763    {
764        if (is_array($value)) {
765            $this->tabs = $value;
766        }
767
768        return $this;
769    }
770
771    /**
772     * Get shading.
773     *
774     * @return Shading
775     */
776    public function getShading()
777    {
778        return $this->shading;
779    }
780
781    /**
782     * Set shading.
783     *
784     * @param mixed $value
785     *
786     * @return self
787     */
788    public function setShading($value = null)
789    {
790        $this->setObjectVal($value, 'Shading', $this->shading);
791
792        return $this;
793    }
794
795    /**
796     * Get contextualSpacing.
797     *
798     * @return bool
799     */
800    public function hasContextualSpacing()
801    {
802        return $this->contextualSpacing;
803    }
804
805    /**
806     * Set contextualSpacing.
807     *
808     * @param bool $contextualSpacing
809     *
810     * @return self
811     */
812    public function setContextualSpacing($contextualSpacing)
813    {
814        $this->contextualSpacing = $contextualSpacing;
815
816        return $this;
817    }
818
819    /**
820     * Get bidirectional.
821     *
822     * @return ?bool
823     */
824    public function isBidi()
825    {
826        return $this->bidi ?? Settings::isDefaultRtl();
827    }
828
829    /**
830     * Set bidi.
831     *
832     * @param ?bool $bidi
833     *            Set to true to write from right to left
834     *
835     * @return self
836     */
837    public function setBidi($bidi)
838    {
839        $this->bidi = $bidi;
840
841        return $this;
842    }
843
844    /**
845     * Get textAlignment.
846     *
847     * @return string
848     */
849    public function getTextAlignment()
850    {
851        return $this->textAlignment;
852    }
853
854    /**
855     * Set textAlignment.
856     *
857     * @param string $textAlignment
858     *
859     * @return self
860     */
861    public function setTextAlignment($textAlignment)
862    {
863        TextAlignment::validate($textAlignment);
864        $this->textAlignment = $textAlignment;
865
866        return $this;
867    }
868
869    /**
870     * @return bool
871     */
872    public function hasSuppressAutoHyphens()
873    {
874        return $this->suppressAutoHyphens;
875    }
876
877    /**
878     * @param bool $suppressAutoHyphens
879     */
880    public function setSuppressAutoHyphens($suppressAutoHyphens): void
881    {
882        $this->suppressAutoHyphens = (bool) $suppressAutoHyphens;
883    }
884}