Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTL Language Support #2107

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -36,7 +36,8 @@
"ext-dom": "*",
"ext-mbstring": "*",
"phenx/php-font-lib": "^0.5.1",
"phenx/php-svg-lib": "^0.3.3"
"phenx/php-svg-lib": "^0.3.3",
"tecnickcom/tc-lib-unicode": "~1.3.11"
},
"require-dev": {
"phpunit/phpunit": "^7.5",
Expand Down
7 changes: 7 additions & 0 deletions src/Css/AttributeTranslator.php
Expand Up @@ -61,6 +61,7 @@ class AttributeTranslator
],
'rules' => '!set_table_rules',
'width' => 'width: %s;',
'dir' => 'direction: %s;'
],
'hr' => [
'align' => '!set_hr_align', // Need to grab width to set 'left' & 'right' correctly
Expand All @@ -70,6 +71,7 @@ class AttributeTranslator
],
'div' => [
'align' => 'text-align: %s;',
'dir' => 'direction: %s;'
],
'h1' => [
'align' => 'text-align: %s;',
Expand All @@ -95,6 +97,7 @@ class AttributeTranslator
],
'p' => [
'align' => 'text-align: %s;',
'dir' => 'direction: %s;'
],
// 'col' => array(
// 'align' => '',
Expand All @@ -115,6 +118,7 @@ class AttributeTranslator
'nowrap' => 'white-space: nowrap;',
'valign' => 'vertical-align: %s;',
'width' => 'width: %s;',
'dir' => 'direction: %s;'
],
'tfoot' => [
'align' => '!set_table_row_align',
Expand All @@ -127,6 +131,7 @@ class AttributeTranslator
'nowrap' => 'white-space: nowrap;',
'valign' => 'vertical-align: %s;',
'width' => 'width: %s;',
'dir' => 'direction: %s;'
],
'thead' => [
'align' => '!set_table_row_align',
Expand All @@ -142,6 +147,7 @@ class AttributeTranslator
'bgcolor' => '!set_background_color',
'link' => '!set_body_link',
'text' => '!set_color',
'dir' => 'direction: %s;'
],
'br' => [
'clear' => 'clear: %s;',
Expand Down Expand Up @@ -177,6 +183,7 @@ class AttributeTranslator
'li' => [
'type' => 'list-style-type: %s;',
'value' => 'counter-reset: -dompdf-default-counter %d;',
'dir' => 'direction: %s;'
],
'pre' => [
'width' => 'width: %s;',
Expand Down
38 changes: 35 additions & 3 deletions src/FrameReflower/Text.php
Expand Up @@ -8,6 +8,7 @@
*/
namespace Dompdf\FrameReflower;

use Com\Tecnick\Unicode\Bidi;
use Dompdf\FrameDecorator\Block as BlockFrameDecorator;
use Dompdf\FrameDecorator\Text as TextFrameDecorator;
use Dompdf\FontMetrics;
Expand Down Expand Up @@ -221,7 +222,15 @@ protected function _layout_line()
switch ($style->white_space) {
default:
case "normal":
$frame->set_text($text = $this->_collapse_white_space($text));
$text = $this->_collapse_white_space($text);

if ($style->direction === 'rtl') {
$bidi = new Bidi($text, null, null, 'R', true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think instead of passing in 'R' for forcertl we should pass in false. tc-lib-unicode appears to have some logic (ref) to determine if RTL is needed for the passed-in text. I did some basic testing using the following HTML and it seems to work as expected:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="Content-type" content="text/html; charset=UTF-8">

    <link href="https://fonts.googleapis.com/css2?family=Amiri&display=swap" rel="stylesheet">
    <style type="text/css">
        body{
            direction: rtl;
            font-family: Amiri, DejaVu Sans, monospace;
            font-size: 36pt;
        }
    </style>
</head>
<body>
<div class="control-body">
  <p>
    12 <span style="color: red">34</span> 56
  </p>
  <p>
    این یک متن تست جهت بررسی موضوع
  </p>
</div>
</body>
</html>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case a right-to-left direction is request I think it is safe to force it.
Which problems do you want to solve letting tc-lib-unciode decide what to do?

If we are doing the step to pass all text it is another story surely. But I don't know if browsers are having an auto detection. I doubt that as there is just the CSS value ltr or rtl.

EDIT:
In fact the browsers indeed are applying a RTL text transform and a missing direction:rtl style just is not doing a right aligning.

EDIT 2:
Even direction:ltr is not stopping the browsers from transforming the text. This style is moreover changing structure ordering (table columns, floating?, text aligning...) rather than the text itself?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can keep this initial release focused on the text itself. We can focus a future release on layout modification for rtl content. Conceptually this seems straightforward, just position from the right side of the container instead of the left. I think probably what will make it difficult is locating all the places where we need to add logic for this.

$text = $bidi->getString();
}

$frame->set_text($text);

if ($text == "") {
break;
}
Expand All @@ -230,15 +239,32 @@ protected function _layout_line()
break;

case "pre":
if ($style->direction === 'rtl') {
$bidi = new Bidi($text, null, null, 'R', true);
$text = $bidi->getString();
}

$split = $this->_newline_break($text);
$add_line = $split !== false;
break;

case "nowrap":
$frame->set_text($text = $this->_collapse_white_space($text));
$text = $this->_collapse_white_space($text);

if ($style->direction === 'rtl') {
$bidi = new Bidi($text, null, null, 'R', true);
$text = $bidi->getString();
}

$frame->set_text($text);
break;

case "pre-wrap":
if ($style->direction === 'rtl') {
$bidi = new Bidi($text, null, null, 'R', true);
$text = $bidi->getString();
}

$split = $this->_newline_break($text);

if (($tmp = $this->_line_break($text)) !== false) {
Expand All @@ -252,7 +278,13 @@ protected function _layout_line()

case "pre-line":
// Collapse white-space except for \n
$frame->set_text($text = preg_replace("/[ \t]+/u", " ", $text));
$text = preg_replace("/[ \t]+/u", " ", $text);

if ($style->direction === 'rtl') {
$bidi = new Bidi($text, null, null, 'R', true);
$text = $bidi->getString();
}
$frame->set_text($text);

if ($text == "") {
break;
Expand Down