Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
96 / 96
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
Paragraph
100.00% covered (success)
100.00%
96 / 96
100.00% covered (success)
100.00%
1 / 1
31
100.00% covered (success)
100.00%
1 / 1
 write
100.00% covered (success)
100.00%
96 / 96
100.00% covered (success)
100.00%
1 / 1
31
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\Writer\ODText\Style;
20
21use PhpOffice\PhpWord\Settings;
22use PhpOffice\PhpWord\Shared\Converter;
23use PhpOffice\PhpWord\SimpleType\Jc;
24use PhpOffice\PhpWord\Style;
25
26/**
27 * Font style writer.
28 *
29 * @since 0.10.0
30 */
31class Paragraph extends AbstractStyle
32{
33    private const BIDI_MAP = [
34        Jc::END => Jc::LEFT,
35        Jc::START => Jc::RIGHT,
36    ];
37
38    private const NON_BIDI_MAP = [
39        Jc::START => Jc::LEFT,
40        Jc::END => Jc::RIGHT,
41    ];
42
43    /**
44     * Write style.
45     */
46    public function write(): void
47    {
48        $style = $this->getStyle();
49        if (!$style instanceof Style\Paragraph) {
50            return;
51        }
52        $xmlWriter = $this->getXmlWriter();
53
54        $marginTop = $style->getSpaceBefore();
55        $marginBottom = $style->getSpaceAfter();
56
57        $xmlWriter->startElement('style:style');
58
59        $styleName = (string) $style->getStyleName();
60        $styleAuto = false;
61        $mpm = '';
62        $psm = '';
63        $pagestart = -1;
64        $breakafter = $breakbefore = $breakauto = false;
65        if ($style->isAuto()) {
66            if (substr($styleName, 0, 2) === 'PB') {
67                $styleAuto = true;
68                $breakafter = true;
69            } elseif (substr($styleName, 0, 2) === 'SB') {
70                $styleAuto = true;
71                $mpm = 'Standard' . substr($styleName, 2);
72                $psn = $style->getNumLevel();
73                $pagestart = $psn;
74            } elseif (substr($styleName, 0, 2) === 'HD') {
75                $styleAuto = true;
76                $psm = 'Heading_' . substr($styleName, 2);
77                $stylep = Style::getStyle($psm);
78                if ($stylep instanceof Style\Font) {
79                    if (method_exists($stylep, 'getParagraph')) {
80                        $stylep = $stylep->getParagraph();
81                    }
82                }
83                if ($stylep instanceof Style\Paragraph) {
84                    if ($stylep->hasPageBreakBefore()) {
85                        $breakbefore = true;
86                    }
87                }
88            } elseif (substr($styleName, 0, 2) === 'HE') {
89                $styleAuto = true;
90                $psm = 'Heading_' . substr($styleName, 2);
91                $breakauto = true;
92            } else {
93                $styleAuto = true;
94                $psm = 'Normal';
95                if (preg_match('/^P\\d+_(\\w+)$/', $styleName, $matches)) {
96                    $psm = $matches[1];
97                }
98            }
99        }
100
101        $xmlWriter->writeAttribute('style:name', $style->getStyleName());
102        $xmlWriter->writeAttribute('style:family', 'paragraph');
103        if ($styleAuto) {
104            $xmlWriter->writeAttributeIf($psm !== '', 'style:parent-style-name', $psm);
105            $xmlWriter->writeAttributeIf($mpm !== '', 'style:master-page-name', $mpm);
106        }
107
108        $xmlWriter->startElement('style:paragraph-properties');
109        if ($styleAuto) {
110            if ($breakafter) {
111                $xmlWriter->writeAttribute('fo:break-after', 'page');
112                $xmlWriter->writeAttribute('fo:margin-top', '0cm');
113                $xmlWriter->writeAttribute('fo:margin-bottom', '0cm');
114            } elseif ($breakbefore) {
115                $xmlWriter->writeAttribute('fo:break-before', 'page');
116            } elseif ($breakauto) {
117                $xmlWriter->writeAttribute('fo:break-before', 'auto');
118            }
119            if ($pagestart > 0) {
120                $xmlWriter->writeAttribute('style:page-number', $pagestart);
121            }
122        }
123        if (!$breakafter && !$breakbefore && !$breakauto) {
124            $twipToPoint = Converter::INCH_TO_TWIP / Converter::INCH_TO_POINT; // 20
125            $xmlWriter->writeAttributeIf($marginTop !== null, 'fo:margin-top', ($marginTop / $twipToPoint) . 'pt');
126            $xmlWriter->writeAttributeIf($marginBottom !== null, 'fo:margin-bottom', ($marginBottom / $twipToPoint) . 'pt');
127        }
128        $alignment = $style->getAlignment();
129        $bidi = $style->isBidi();
130        $defaultRtl = Settings::isDefaultRtl();
131        if ($alignment === '' && $bidi !== null) {
132            $alignment = Jc::START;
133        }
134        if ($bidi) {
135            $alignment = self::BIDI_MAP[$alignment] ?? $alignment;
136        } elseif ($defaultRtl !== null) {
137            $alignment = self::NON_BIDI_MAP[$alignment] ?? $alignment;
138        }
139        $xmlWriter->writeAttributeIf($alignment !== '', 'fo:text-align', $alignment);
140        $temp = $style->getLineHeight();
141        $xmlWriter->writeAttributeIf($temp !== null, 'fo:line-height', ((string) ($temp * 100) . '%'));
142        $xmlWriter->writeAttributeIf($style->hasPageBreakBefore() === true, 'fo:break-before', 'page');
143
144        $tabs = $style->getTabs();
145        if ($tabs !== null && count($tabs) > 0) {
146            $xmlWriter->startElement('style:tab-stops');
147            foreach ($tabs as $tab) {
148                $xmlWriter->startElement('style:tab-stop');
149                $xmlWriter->writeAttribute('style:type', $tab->getType());
150                $xmlWriter->writeAttribute('style:position', (string) ($tab->getPosition() / Converter::INCH_TO_TWIP) . 'in');
151                $xmlWriter->endElement();
152            }
153            $xmlWriter->endElement();
154        }
155
156        //Right to left
157        $xmlWriter->writeAttributeIf($style->isBidi(), 'style:writing-mode', 'rl-tb');
158
159        //Indentation
160        $indent = $style->getIndentation();
161        //if ($indent instanceof \PhpOffice\PhpWord\Style\Indentation) {
162        if (!empty($indent)) {
163            $marg = $indent->getLeft();
164            $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-left', (string) ($marg / Converter::INCH_TO_TWIP) . 'in');
165            $marg = $indent->getRight();
166            $xmlWriter->writeAttributeIf($marg !== null, 'fo:margin-right', (string) ($marg / Converter::INCH_TO_TWIP) . 'in');
167        }
168
169        $xmlWriter->endElement(); //style:paragraph-properties
170
171        if ($styleAuto && substr($styleName, 0, 2) === 'SB') {
172            $xmlWriter->startElement('style:text-properties');
173            $xmlWriter->writeAttribute('text:display', 'none');
174            $xmlWriter->endElement();
175        }
176
177        $xmlWriter->endElement(); //style:style
178    }
179}