mirror of
				https://github.com/python-pillow/Pillow.git
				synced 2025-11-04 01:47:47 +03:00 
			
		
		
		
	Merge remote-tracking branch 'upstream/main' into add-cygwin-to-ci
This commit is contained in:
		
						commit
						b582806887
					
				
							
								
								
									
										1
									
								
								.github/workflows/test-docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/test-docker.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -19,7 +19,6 @@ jobs:
 | 
				
			||||||
          amazon-2-amd64,
 | 
					          amazon-2-amd64,
 | 
				
			||||||
          arch,
 | 
					          arch,
 | 
				
			||||||
          centos-7-amd64,
 | 
					          centos-7-amd64,
 | 
				
			||||||
          centos-8-amd64,
 | 
					 | 
				
			||||||
          centos-stream-8-amd64,
 | 
					          centos-stream-8-amd64,
 | 
				
			||||||
          debian-10-buster-x86,
 | 
					          debian-10-buster-x86,
 | 
				
			||||||
          debian-11-bullseye-x86,
 | 
					          debian-11-bullseye-x86,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/workflows/test-mingw.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/test-mingw.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -4,7 +4,7 @@ on: [push, pull_request, workflow_dispatch]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
    runs-on: windows-2019
 | 
					    runs-on: windows-latest
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								.github/workflows/test-windows.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/test-windows.yml
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -4,7 +4,7 @@ on: [push, pull_request, workflow_dispatch]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
  build:
 | 
					  build:
 | 
				
			||||||
    runs-on: windows-2019
 | 
					    runs-on: windows-latest
 | 
				
			||||||
    strategy:
 | 
					    strategy:
 | 
				
			||||||
      fail-fast: false
 | 
					      fail-fast: false
 | 
				
			||||||
      matrix:
 | 
					      matrix:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										15
									
								
								CHANGES.rst
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								CHANGES.rst
									
									
									
									
									
								
							| 
						 | 
					@ -5,6 +5,12 @@ Changelog (Pillow)
 | 
				
			||||||
9.1.0 (unreleased)
 | 
					9.1.0 (unreleased)
 | 
				
			||||||
------------------
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Enable arm64 for MSVC on Windows #5811
 | 
				
			||||||
 | 
					  [gaborkertesz-linaro, gaborkertesz]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Keep IPython/Jupyter text/plain output stable #5891
 | 
				
			||||||
 | 
					  [shamrin, radarhere]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Raise an error when performing a negative crop #5972
 | 
					- Raise an error when performing a negative crop #5972
 | 
				
			||||||
  [radarhere, hugovk]
 | 
					  [radarhere, hugovk]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +32,15 @@ Changelog (Pillow)
 | 
				
			||||||
- Remove readonly from Image.__eq__ #5930
 | 
					- Remove readonly from Image.__eq__ #5930
 | 
				
			||||||
  [hugovk]
 | 
					  [hugovk]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					9.0.1 (2022-02-03)
 | 
				
			||||||
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- In show_file, use os.remove to remove temporary images. CVE-2022-24303 #6010
 | 
				
			||||||
 | 
					  [radarhere, hugovk]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Restrict builtins within lambdas for ImageMath.eval. CVE-2022-22817 #6009
 | 
				
			||||||
 | 
					  [radarhere]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
9.0.0 (2022-01-02)
 | 
					9.0.0 (2022-01-02)
 | 
				
			||||||
------------------
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,6 +58,15 @@ def test_sanity():
 | 
				
			||||||
        assert image2_scale2.format == "EPS"
 | 
					        assert image2_scale2.format == "EPS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
 | 
				
			||||||
 | 
					def test_load():
 | 
				
			||||||
 | 
					    with Image.open(FILE1) as im:
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (255, 255, 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test again now that it has already been loaded once
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (255, 255, 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_invalid_file():
 | 
					def test_invalid_file():
 | 
				
			||||||
    invalid_file = "Tests/images/flower.jpg"
 | 
					    invalid_file = "Tests/images/flower.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,20 +5,28 @@ from PIL import GbrImagePlugin, Image
 | 
				
			||||||
from .helper import assert_image_equal_tofile
 | 
					from .helper import assert_image_equal_tofile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_invalid_file():
 | 
					 | 
				
			||||||
    invalid_file = "Tests/images/flower.jpg"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    with pytest.raises(SyntaxError):
 | 
					 | 
				
			||||||
        GbrImagePlugin.GbrImageFile(invalid_file)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def test_gbr_file():
 | 
					def test_gbr_file():
 | 
				
			||||||
    with Image.open("Tests/images/gbr.gbr") as im:
 | 
					    with Image.open("Tests/images/gbr.gbr") as im:
 | 
				
			||||||
        assert_image_equal_tofile(im, "Tests/images/gbr.png")
 | 
					        assert_image_equal_tofile(im, "Tests/images/gbr.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_load():
 | 
				
			||||||
 | 
					    with Image.open("Tests/images/gbr.gbr") as im:
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (0, 0, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test again now that it has already been loaded once
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (0, 0, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_multiple_load_operations():
 | 
					def test_multiple_load_operations():
 | 
				
			||||||
    with Image.open("Tests/images/gbr.gbr") as im:
 | 
					    with Image.open("Tests/images/gbr.gbr") as im:
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
        assert_image_equal_tofile(im, "Tests/images/gbr.png")
 | 
					        assert_image_equal_tofile(im, "Tests/images/gbr.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_invalid_file():
 | 
				
			||||||
 | 
					    invalid_file = "Tests/images/flower.jpg"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    with pytest.raises(SyntaxError):
 | 
				
			||||||
 | 
					        GbrImagePlugin.GbrImageFile(invalid_file)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,6 +28,14 @@ def test_sanity():
 | 
				
			||||||
        assert im.format == "ICNS"
 | 
					        assert im.format == "ICNS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_load():
 | 
				
			||||||
 | 
					    with Image.open(TEST_FILE) as im:
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (0, 0, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test again now that it has already been loaded once
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (0, 0, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_save(tmp_path):
 | 
					def test_save(tmp_path):
 | 
				
			||||||
    temp_file = str(tmp_path / "temp.icns")
 | 
					    temp_file = str(tmp_path / "temp.icns")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,11 @@ def test_sanity():
 | 
				
			||||||
    assert im.get_format_mimetype() == "image/x-icon"
 | 
					    assert im.get_format_mimetype() == "image/x-icon"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_load():
 | 
				
			||||||
 | 
					    with Image.open(TEST_ICO_FILE) as im:
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == (1, 1, 9, 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_mask():
 | 
					def test_mask():
 | 
				
			||||||
    with Image.open("Tests/images/hopper_mask.ico") as im:
 | 
					    with Image.open("Tests/images/hopper_mask.ico") as im:
 | 
				
			||||||
        assert_image_equal_tofile(im, "Tests/images/hopper_mask.png")
 | 
					        assert_image_equal_tofile(im, "Tests/images/hopper_mask.png")
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,15 +2,11 @@ from PIL import WalImageFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .helper import assert_image_equal_tofile
 | 
					from .helper import assert_image_equal_tofile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
def test_open():
 | 
					 | 
				
			||||||
    # Arrange
 | 
					 | 
				
			||||||
TEST_FILE = "Tests/images/hopper.wal"
 | 
					TEST_FILE = "Tests/images/hopper.wal"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Act
 | 
					 | 
				
			||||||
    with WalImageFile.open(TEST_FILE) as im:
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Assert
 | 
					def test_open():
 | 
				
			||||||
 | 
					    with WalImageFile.open(TEST_FILE) as im:
 | 
				
			||||||
        assert im.format == "WAL"
 | 
					        assert im.format == "WAL"
 | 
				
			||||||
        assert im.format_description == "Quake2 Texture"
 | 
					        assert im.format_description == "Quake2 Texture"
 | 
				
			||||||
        assert im.mode == "P"
 | 
					        assert im.mode == "P"
 | 
				
			||||||
| 
						 | 
					@ -19,3 +15,11 @@ def test_open():
 | 
				
			||||||
        assert isinstance(im, WalImageFile.WalImageFile)
 | 
					        assert isinstance(im, WalImageFile.WalImageFile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        assert_image_equal_tofile(im, "Tests/images/hopper_wal.png")
 | 
					        assert_image_equal_tofile(im, "Tests/images/hopper_wal.png")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_load():
 | 
				
			||||||
 | 
					    with WalImageFile.open(TEST_FILE) as im:
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == 122
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Test again now that it has already been loaded once
 | 
				
			||||||
 | 
					        assert im.load()[0, 0] == 122
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,12 @@ def test_load_raw():
 | 
				
			||||||
            assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref.png", 2.0)
 | 
					            assert_image_similar_tofile(im, "Tests/images/drawing_wmf_ref.png", 2.0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_load():
 | 
				
			||||||
 | 
					    with Image.open("Tests/images/drawing.emf") as im:
 | 
				
			||||||
 | 
					        if hasattr(Image.core, "drawwmf"):
 | 
				
			||||||
 | 
					            assert im.load()[0, 0] == (255, 255, 255)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_register_handler(tmp_path):
 | 
					def test_register_handler(tmp_path):
 | 
				
			||||||
    class TestHandler:
 | 
					    class TestHandler:
 | 
				
			||||||
        methodCalled = False
 | 
					        methodCalled = False
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,9 +52,17 @@ def test_ops():
 | 
				
			||||||
    assert pixel(ImageMath.eval("float(B)**33", images)) == "F 8589934592.0"
 | 
					    assert pixel(ImageMath.eval("float(B)**33", images)) == "F 8589934592.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_prevent_exec():
 | 
					@pytest.mark.parametrize(
 | 
				
			||||||
 | 
					    "expression",
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					        "exec('pass')",
 | 
				
			||||||
 | 
					        "(lambda: exec('pass'))()",
 | 
				
			||||||
 | 
					        "(lambda: (lambda: exec('pass'))())()",
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					def test_prevent_exec(expression):
 | 
				
			||||||
    with pytest.raises(ValueError):
 | 
					    with pytest.raises(ValueError):
 | 
				
			||||||
        ImageMath.eval("exec('pass')")
 | 
					        ImageMath.eval(expression)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_logical():
 | 
					def test_logical():
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,11 +85,13 @@ def test_ipythonviewer():
 | 
				
			||||||
    not on_ci() or is_win32(),
 | 
					    not on_ci() or is_win32(),
 | 
				
			||||||
    reason="Only run on CIs; hangs on Windows CIs",
 | 
					    reason="Only run on CIs; hangs on Windows CIs",
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
def test_file_deprecated():
 | 
					def test_file_deprecated(tmp_path):
 | 
				
			||||||
 | 
					    f = str(tmp_path / "temp.jpg")
 | 
				
			||||||
    for viewer in ImageShow._viewers:
 | 
					    for viewer in ImageShow._viewers:
 | 
				
			||||||
 | 
					        hopper().save(f)
 | 
				
			||||||
        with pytest.warns(DeprecationWarning):
 | 
					        with pytest.warns(DeprecationWarning):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                viewer.show_file(file="test.jpg")
 | 
					                viewer.show_file(file=f)
 | 
				
			||||||
            except NotImplementedError:
 | 
					            except NotImplementedError:
 | 
				
			||||||
                pass
 | 
					                pass
 | 
				
			||||||
        with pytest.raises(TypeError):
 | 
					        with pytest.raises(TypeError):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,15 @@
 | 
				
			||||||
#!/bin/bash
 | 
					#!/bin/bash
 | 
				
			||||||
# install libimagequant
 | 
					# install libimagequant
 | 
				
			||||||
 | 
					
 | 
				
			||||||
archive=libimagequant-2.17.0
 | 
					archive=libimagequant-4.0.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
 | 
					./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pushd $archive
 | 
					pushd $archive/imagequant-sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
make shared
 | 
					cargo install cargo-c
 | 
				
			||||||
sudo cp libimagequant.so* /usr/lib/
 | 
					cargo cinstall --prefix=/usr --destdir=.
 | 
				
			||||||
sudo cp libimagequant.h /usr/include/
 | 
					sudo cp usr/lib/libimagequant.so* /usr/lib/
 | 
				
			||||||
 | 
					sudo cp usr/include/libimagequant.h /usr/include/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
popd
 | 
					popd
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
# install raqm
 | 
					# install raqm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
archive=libraqm-0.8.0
 | 
					archive=libraqm-0.9.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
 | 
					./download-and-extract.sh $archive https://raw.githubusercontent.com/python-pillow/pillow-depends/main/$archive.tar.gz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,7 +169,7 @@ Many of Pillow's features require external libraries:
 | 
				
			||||||
* **littlecms** provides color management
 | 
					* **littlecms** provides color management
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and
 | 
					  * Pillow version 2.2.1 and below uses liblcms1, Pillow 2.3.0 and
 | 
				
			||||||
    above uses liblcms2. Tested with **1.19** and **2.7-2.12**.
 | 
					    above uses liblcms2. Tested with **1.19** and **2.7-2.13**.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* **libwebp** provides the WebP format.
 | 
					* **libwebp** provides the WebP format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,7 +187,7 @@ Many of Pillow's features require external libraries:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* **libimagequant** provides improved color quantization
 | 
					* **libimagequant** provides improved color quantization
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  * Pillow has been tested with libimagequant **2.6-2.17.0**
 | 
					  * Pillow has been tested with libimagequant **2.6-4.0**
 | 
				
			||||||
  * Libimagequant is licensed GPLv3, which is more restrictive than
 | 
					  * Libimagequant is licensed GPLv3, which is more restrictive than
 | 
				
			||||||
    the Pillow license, therefore we will not be distributing binaries
 | 
					    the Pillow license, therefore we will not be distributing binaries
 | 
				
			||||||
    with libimagequant support enabled.
 | 
					    with libimagequant support enabled.
 | 
				
			||||||
| 
						 | 
					@ -453,8 +453,6 @@ These platforms are built and tested for every change.
 | 
				
			||||||
+----------------------------------+----------------------------+---------------------+
 | 
					+----------------------------------+----------------------------+---------------------+
 | 
				
			||||||
| CentOS 7                         | 3.9                        | x86-64              |
 | 
					| CentOS 7                         | 3.9                        | x86-64              |
 | 
				
			||||||
+----------------------------------+----------------------------+---------------------+
 | 
					+----------------------------------+----------------------------+---------------------+
 | 
				
			||||||
| CentOS 8                         | 3.9                        | x86-64              |
 | 
					 | 
				
			||||||
+----------------------------------+----------------------------+---------------------+
 | 
					 | 
				
			||||||
| CentOS Stream 8                  | 3.9                        | x86-64              |
 | 
					| CentOS Stream 8                  | 3.9                        | x86-64              |
 | 
				
			||||||
+----------------------------------+----------------------------+---------------------+
 | 
					+----------------------------------+----------------------------+---------------------+
 | 
				
			||||||
| Debian 10 Buster                 | 3.7                        | x86                 |
 | 
					| Debian 10 Buster                 | 3.7                        | x86                 |
 | 
				
			||||||
| 
						 | 
					@ -532,6 +530,8 @@ These platforms have been reported to work at the versions mentioned.
 | 
				
			||||||
+----------------------------------+---------------------------+------------------+--------------+
 | 
					+----------------------------------+---------------------------+------------------+--------------+
 | 
				
			||||||
| CentOS 6.3                       | 2.7, 3.3                  |                  |x86           |
 | 
					| CentOS 6.3                       | 2.7, 3.3                  |                  |x86           |
 | 
				
			||||||
+----------------------------------+---------------------------+------------------+--------------+
 | 
					+----------------------------------+---------------------------+------------------+--------------+
 | 
				
			||||||
 | 
					| CentOS 8                         | 3.9                       | 9.0.0            |x86-64        |
 | 
				
			||||||
 | 
					+----------------------------------+---------------------------+------------------+--------------+
 | 
				
			||||||
| Fedora 23                        | 2.7, 3.4                  | 3.1.0            |x86-64        |
 | 
					| Fedora 23                        | 2.7, 3.4                  | 3.1.0            |x86-64        |
 | 
				
			||||||
+----------------------------------+---------------------------+------------------+--------------+
 | 
					+----------------------------------+---------------------------+------------------+--------------+
 | 
				
			||||||
| Ubuntu Linux 12.04 LTS (Precise) | | 2.6, 3.2, 3.3, 3.4, 3.5 | 3.4.1            |x86,x86-64    |
 | 
					| Ubuntu Linux 12.04 LTS (Precise) | | 2.6, 3.2, 3.3, 3.4, 3.5 | 3.4.1            |x86,x86-64    |
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								docs/releasenotes/9.0.1.rst
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								docs/releasenotes/9.0.1.rst
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					9.0.1
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Security
 | 
				
			||||||
 | 
					========
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This release addresses several security problems.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:cve:`CVE-2022-24303`: If the path to the temporary directory on Linux or macOS
 | 
				
			||||||
 | 
					contained a space, this would break removal of the temporary image file after
 | 
				
			||||||
 | 
					``im.show()`` (and related actions), and potentially remove an unrelated file. This
 | 
				
			||||||
 | 
					has been present since PIL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:cve:`CVE-2022-22817`: While Pillow 9.0 restricted top-level builtins available to
 | 
				
			||||||
 | 
					:py:meth:`PIL.ImageMath.eval`, it did not prevent builtins available to lambda
 | 
				
			||||||
 | 
					expressions. These are now also restricted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Other Changes
 | 
				
			||||||
 | 
					=============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Pillow 9.0 added support for ``xdg-open`` as an image viewer, but there have been
 | 
				
			||||||
 | 
					reports that the temporary image file was removed too quickly to be loaded into the
 | 
				
			||||||
 | 
					final application. A delay has been added.
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ expected to be backported to earlier versions.
 | 
				
			||||||
.. toctree::
 | 
					.. toctree::
 | 
				
			||||||
  :maxdepth: 2
 | 
					  :maxdepth: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  9.0.1
 | 
				
			||||||
  9.0.0
 | 
					  9.0.0
 | 
				
			||||||
  8.4.0
 | 
					  8.4.0
 | 
				
			||||||
  8.3.2
 | 
					  8.3.2
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -329,12 +329,12 @@ class EpsImageFile(ImageFile.ImageFile):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load(self, scale=1, transparency=False):
 | 
					    def load(self, scale=1, transparency=False):
 | 
				
			||||||
        # Load EPS via Ghostscript
 | 
					        # Load EPS via Ghostscript
 | 
				
			||||||
        if not self.tile:
 | 
					        if self.tile:
 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
            self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency)
 | 
					            self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency)
 | 
				
			||||||
            self.mode = self.im.mode
 | 
					            self.mode = self.im.mode
 | 
				
			||||||
            self._size = self.im.size
 | 
					            self._size = self.im.size
 | 
				
			||||||
            self.tile = []
 | 
					            self.tile = []
 | 
				
			||||||
 | 
					        return Image.Image.load(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load_seek(self, *args, **kwargs):
 | 
					    def load_seek(self, *args, **kwargs):
 | 
				
			||||||
        # we can't incrementally load, so force ImageFile.parser to
 | 
					        # we can't incrementally load, so force ImageFile.parser to
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,12 +84,10 @@ class GbrImageFile(ImageFile.ImageFile):
 | 
				
			||||||
        self._data_size = width * height * color_depth
 | 
					        self._data_size = width * height * color_depth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load(self):
 | 
					    def load(self):
 | 
				
			||||||
        if self.im:
 | 
					        if not self.im:
 | 
				
			||||||
            # Already loaded
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.im = Image.core.new(self.mode, self.size)
 | 
					            self.im = Image.core.new(self.mode, self.size)
 | 
				
			||||||
            self.frombytes(self.fp.read(self._data_size))
 | 
					            self.frombytes(self.fp.read(self._data_size))
 | 
				
			||||||
 | 
					        return Image.Image.load(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -286,21 +286,22 @@ class IcnsImageFile(ImageFile.ImageFile):
 | 
				
			||||||
                self.best_size[1] * self.best_size[2],
 | 
					                self.best_size[1] * self.best_size[2],
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Image.Image.load(self)
 | 
					        px = Image.Image.load(self)
 | 
				
			||||||
        if self.im and self.im.size == self.size:
 | 
					        if self.im and self.im.size == self.size:
 | 
				
			||||||
            # Already loaded
 | 
					            # Already loaded
 | 
				
			||||||
            return
 | 
					            return px
 | 
				
			||||||
        self.load_prepare()
 | 
					        self.load_prepare()
 | 
				
			||||||
        # This is likely NOT the best way to do it, but whatever.
 | 
					        # This is likely NOT the best way to do it, but whatever.
 | 
				
			||||||
        im = self.icns.getimage(self.best_size)
 | 
					        im = self.icns.getimage(self.best_size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # If this is a PNG or JPEG 2000, it won't be loaded yet
 | 
					        # If this is a PNG or JPEG 2000, it won't be loaded yet
 | 
				
			||||||
        im.load()
 | 
					        px = im.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.im = im.im
 | 
					        self.im = im.im
 | 
				
			||||||
        self.mode = im.mode
 | 
					        self.mode = im.mode
 | 
				
			||||||
        self.size = im.size
 | 
					        self.size = im.size
 | 
				
			||||||
        self.load_end()
 | 
					
 | 
				
			||||||
 | 
					        return px
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _save(im, fp, filename):
 | 
					def _save(im, fp, filename):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -306,7 +306,7 @@ class IcoImageFile(ImageFile.ImageFile):
 | 
				
			||||||
    def load(self):
 | 
					    def load(self):
 | 
				
			||||||
        if self.im and self.im.size == self.size:
 | 
					        if self.im and self.im.size == self.size:
 | 
				
			||||||
            # Already loaded
 | 
					            # Already loaded
 | 
				
			||||||
            return
 | 
					            return Image.Image.load(self)
 | 
				
			||||||
        im = self.ico.getimage(self.size)
 | 
					        im = self.ico.getimage(self.size)
 | 
				
			||||||
        # if tile is PNG, it won't really be loaded yet
 | 
					        # if tile is PNG, it won't really be loaded yet
 | 
				
			||||||
        im.load()
 | 
					        im.load()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -328,6 +328,7 @@ class StubImageFile(ImageFile):
 | 
				
			||||||
        # become the other object (!)
 | 
					        # become the other object (!)
 | 
				
			||||||
        self.__class__ = image.__class__
 | 
					        self.__class__ = image.__class__
 | 
				
			||||||
        self.__dict__ = image.__dict__
 | 
					        self.__dict__ = image.__dict__
 | 
				
			||||||
 | 
					        return image.load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _load(self):
 | 
					    def _load(self):
 | 
				
			||||||
        """(Hook) Find actual image loader."""
 | 
					        """(Hook) Find actual image loader."""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -240,11 +240,18 @@ def eval(expression, _dict={}, **kw):
 | 
				
			||||||
        if hasattr(v, "im"):
 | 
					        if hasattr(v, "im"):
 | 
				
			||||||
            args[k] = _Operand(v)
 | 
					            args[k] = _Operand(v)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    code = compile(expression, "<string>", "eval")
 | 
					    compiled_code = compile(expression, "<string>", "eval")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def scan(code):
 | 
				
			||||||
 | 
					        for const in code.co_consts:
 | 
				
			||||||
 | 
					            if type(const) == type(compiled_code):
 | 
				
			||||||
 | 
					                scan(const)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for name in code.co_names:
 | 
					        for name in code.co_names:
 | 
				
			||||||
            if name not in args and name != "abs":
 | 
					            if name not in args and name != "abs":
 | 
				
			||||||
                raise ValueError(f"'{name}' not allowed")
 | 
					                raise ValueError(f"'{name}' not allowed")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    scan(compiled_code)
 | 
				
			||||||
    out = builtins.eval(expression, {"__builtins": {"abs": abs}}, args)
 | 
					    out = builtins.eval(expression, {"__builtins": {"abs": abs}}, args)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        return out.im
 | 
					        return out.im
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,7 +15,6 @@ import os
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import tempfile
 | 
					 | 
				
			||||||
import warnings
 | 
					import warnings
 | 
				
			||||||
from shlex import quote
 | 
					from shlex import quote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,6 +126,16 @@ class Viewer:
 | 
				
			||||||
        os.system(self.get_command(path, **options))
 | 
					        os.system(self.get_command(path, **options))
 | 
				
			||||||
        return 1
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _remove_path_after_delay(self, path):
 | 
				
			||||||
 | 
					        subprocess.Popen(
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                sys.executable,
 | 
				
			||||||
 | 
					                "-c",
 | 
				
			||||||
 | 
					                "import os, sys, time; time.sleep(20); os.remove(sys.argv[1])",
 | 
				
			||||||
 | 
					                path,
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# --------------------------------------------------------------------
 | 
					# --------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,16 +189,8 @@ class MacViewer(Viewer):
 | 
				
			||||||
                path = options.pop("file")
 | 
					                path = options.pop("file")
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                raise TypeError("Missing required argument: 'path'")
 | 
					                raise TypeError("Missing required argument: 'path'")
 | 
				
			||||||
        fd, temp_path = tempfile.mkstemp()
 | 
					        subprocess.call(["open", "-a", "Preview.app", path])
 | 
				
			||||||
        with os.fdopen(fd, "w") as f:
 | 
					        self._remove_path_after_delay(path)
 | 
				
			||||||
            f.write(path)
 | 
					 | 
				
			||||||
        with open(temp_path) as f:
 | 
					 | 
				
			||||||
            subprocess.Popen(
 | 
					 | 
				
			||||||
                ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
 | 
					 | 
				
			||||||
                shell=True,
 | 
					 | 
				
			||||||
                stdin=f,
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        os.remove(temp_path)
 | 
					 | 
				
			||||||
        return 1
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -205,6 +206,16 @@ class UnixViewer(Viewer):
 | 
				
			||||||
        command = self.get_command_ex(file, **options)[0]
 | 
					        command = self.get_command_ex(file, **options)[0]
 | 
				
			||||||
        return f"({command} {quote(file)}; rm -f {quote(file)})&"
 | 
					        return f"({command} {quote(file)}; rm -f {quote(file)})&"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class XDGViewer(UnixViewer):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    The freedesktop.org ``xdg-open`` command.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_command_ex(self, file, **options):
 | 
				
			||||||
 | 
					        command = executable = "xdg-open"
 | 
				
			||||||
 | 
					        return command, executable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def show_file(self, path=None, **options):
 | 
					    def show_file(self, path=None, **options):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Display given file.
 | 
					        Display given file.
 | 
				
			||||||
| 
						 | 
					@ -223,28 +234,11 @@ class UnixViewer(Viewer):
 | 
				
			||||||
                path = options.pop("file")
 | 
					                path = options.pop("file")
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                raise TypeError("Missing required argument: 'path'")
 | 
					                raise TypeError("Missing required argument: 'path'")
 | 
				
			||||||
        fd, temp_path = tempfile.mkstemp()
 | 
					        subprocess.Popen(["xdg-open", path])
 | 
				
			||||||
        with os.fdopen(fd, "w") as f:
 | 
					        self._remove_path_after_delay(path)
 | 
				
			||||||
            f.write(path)
 | 
					 | 
				
			||||||
        with open(temp_path) as f:
 | 
					 | 
				
			||||||
            command = self.get_command_ex(path, **options)[0]
 | 
					 | 
				
			||||||
            subprocess.Popen(
 | 
					 | 
				
			||||||
                ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
        os.remove(temp_path)
 | 
					 | 
				
			||||||
        return 1
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class XDGViewer(UnixViewer):
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
    The freedesktop.org ``xdg-open`` command.
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_command_ex(self, file, **options):
 | 
					 | 
				
			||||||
        command = executable = "xdg-open"
 | 
					 | 
				
			||||||
        return command, executable
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DisplayViewer(UnixViewer):
 | 
					class DisplayViewer(UnixViewer):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    The ImageMagick ``display`` command.
 | 
					    The ImageMagick ``display`` command.
 | 
				
			||||||
| 
						 | 
					@ -257,6 +251,32 @@ class DisplayViewer(UnixViewer):
 | 
				
			||||||
            command += f" -name {quote(title)}"
 | 
					            command += f" -name {quote(title)}"
 | 
				
			||||||
        return command, executable
 | 
					        return command, executable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_file(self, path=None, **options):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Display given file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
 | 
				
			||||||
 | 
					        and ``path`` should be used instead.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if path is None:
 | 
				
			||||||
 | 
					            if "file" in options:
 | 
				
			||||||
 | 
					                warnings.warn(
 | 
				
			||||||
 | 
					                    "The 'file' argument is deprecated and will be removed in Pillow "
 | 
				
			||||||
 | 
					                    "10 (2023-07-01). Use 'path' instead.",
 | 
				
			||||||
 | 
					                    DeprecationWarning,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                path = options.pop("file")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise TypeError("Missing required argument: 'path'")
 | 
				
			||||||
 | 
					        args = ["display"]
 | 
				
			||||||
 | 
					        if "title" in options:
 | 
				
			||||||
 | 
					            args += ["-name", options["title"]]
 | 
				
			||||||
 | 
					        args.append(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subprocess.Popen(args)
 | 
				
			||||||
 | 
					        os.remove(path)
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GmDisplayViewer(UnixViewer):
 | 
					class GmDisplayViewer(UnixViewer):
 | 
				
			||||||
    """The GraphicsMagick ``gm display`` command."""
 | 
					    """The GraphicsMagick ``gm display`` command."""
 | 
				
			||||||
| 
						 | 
					@ -266,6 +286,27 @@ class GmDisplayViewer(UnixViewer):
 | 
				
			||||||
        command = "gm display"
 | 
					        command = "gm display"
 | 
				
			||||||
        return command, executable
 | 
					        return command, executable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_file(self, path=None, **options):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Display given file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
 | 
				
			||||||
 | 
					        and ``path`` should be used instead.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if path is None:
 | 
				
			||||||
 | 
					            if "file" in options:
 | 
				
			||||||
 | 
					                warnings.warn(
 | 
				
			||||||
 | 
					                    "The 'file' argument is deprecated and will be removed in Pillow "
 | 
				
			||||||
 | 
					                    "10 (2023-07-01). Use 'path' instead.",
 | 
				
			||||||
 | 
					                    DeprecationWarning,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                path = options.pop("file")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise TypeError("Missing required argument: 'path'")
 | 
				
			||||||
 | 
					        subprocess.Popen(["gm", "display", path])
 | 
				
			||||||
 | 
					        os.remove(path)
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EogViewer(UnixViewer):
 | 
					class EogViewer(UnixViewer):
 | 
				
			||||||
    """The GNOME Image Viewer ``eog`` command."""
 | 
					    """The GNOME Image Viewer ``eog`` command."""
 | 
				
			||||||
| 
						 | 
					@ -275,6 +316,27 @@ class EogViewer(UnixViewer):
 | 
				
			||||||
        command = "eog -n"
 | 
					        command = "eog -n"
 | 
				
			||||||
        return command, executable
 | 
					        return command, executable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_file(self, path=None, **options):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Display given file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
 | 
				
			||||||
 | 
					        and ``path`` should be used instead.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if path is None:
 | 
				
			||||||
 | 
					            if "file" in options:
 | 
				
			||||||
 | 
					                warnings.warn(
 | 
				
			||||||
 | 
					                    "The 'file' argument is deprecated and will be removed in Pillow "
 | 
				
			||||||
 | 
					                    "10 (2023-07-01). Use 'path' instead.",
 | 
				
			||||||
 | 
					                    DeprecationWarning,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                path = options.pop("file")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise TypeError("Missing required argument: 'path'")
 | 
				
			||||||
 | 
					        subprocess.Popen(["eog", "-n", path])
 | 
				
			||||||
 | 
					        os.remove(path)
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class XVViewer(UnixViewer):
 | 
					class XVViewer(UnixViewer):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
| 
						 | 
					@ -290,6 +352,32 @@ class XVViewer(UnixViewer):
 | 
				
			||||||
            command += f" -name {quote(title)}"
 | 
					            command += f" -name {quote(title)}"
 | 
				
			||||||
        return command, executable
 | 
					        return command, executable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_file(self, path=None, **options):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Display given file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Before Pillow 9.1.0, the first argument was ``file``. This is now deprecated,
 | 
				
			||||||
 | 
					        and ``path`` should be used instead.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if path is None:
 | 
				
			||||||
 | 
					            if "file" in options:
 | 
				
			||||||
 | 
					                warnings.warn(
 | 
				
			||||||
 | 
					                    "The 'file' argument is deprecated and will be removed in Pillow "
 | 
				
			||||||
 | 
					                    "10 (2023-07-01). Use 'path' instead.",
 | 
				
			||||||
 | 
					                    DeprecationWarning,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                path = options.pop("file")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise TypeError("Missing required argument: 'path'")
 | 
				
			||||||
 | 
					        args = ["xv"]
 | 
				
			||||||
 | 
					        if "title" in options:
 | 
				
			||||||
 | 
					            args += ["-name", options["title"]]
 | 
				
			||||||
 | 
					        args.append(path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subprocess.Popen(args)
 | 
				
			||||||
 | 
					        os.remove(path)
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if sys.platform not in ("win32", "darwin"):  # unixoids
 | 
					if sys.platform not in ("win32", "darwin"):  # unixoids
 | 
				
			||||||
    if shutil.which("xdg-open"):
 | 
					    if shutil.which("xdg-open"):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,14 +51,11 @@ class WalImageFile(ImageFile.ImageFile):
 | 
				
			||||||
            self.info["next_name"] = next_name
 | 
					            self.info["next_name"] = next_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def load(self):
 | 
					    def load(self):
 | 
				
			||||||
        if self.im:
 | 
					        if not self.im:
 | 
				
			||||||
            # Already loaded
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.im = Image.core.new(self.mode, self.size)
 | 
					            self.im = Image.core.new(self.mode, self.size)
 | 
				
			||||||
            self.frombytes(self.fp.read(self.size[0] * self.size[1]))
 | 
					            self.frombytes(self.fp.read(self.size[0] * self.size[1]))
 | 
				
			||||||
            self.putpalette(quake2palette)
 | 
					            self.putpalette(quake2palette)
 | 
				
			||||||
        Image.Image.load(self)
 | 
					        return Image.Image.load(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def open(filename):
 | 
					def open(filename):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,7 +158,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
 | 
				
			||||||
                (x1 - x0) * self.info["dpi"] // self._inch,
 | 
					                (x1 - x0) * self.info["dpi"] // self._inch,
 | 
				
			||||||
                (y1 - y0) * self.info["dpi"] // self._inch,
 | 
					                (y1 - y0) * self.info["dpi"] // self._inch,
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        super().load()
 | 
					        return super().load()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _save(im, fp, filename):
 | 
					def _save(im, fp, filename):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								src/thirdparty/raqm/COPYING
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/thirdparty/raqm/COPYING
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
The MIT License (MIT)
 | 
					The MIT License (MIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
 | 
					Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
 | 
				
			||||||
Copyright © 2016-2021 Khaled Hosny <khaled@aliftype.com>
 | 
					Copyright © 2016-2022 Khaled Hosny <khaled@aliftype.com>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
of this software and associated documentation files (the "Software"), to deal
 | 
					of this software and associated documentation files (the "Software"), to deal
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/thirdparty/raqm/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								src/thirdparty/raqm/README.md
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -68,6 +68,7 @@ Projects using Raqm
 | 
				
			||||||
3. [FontView](https://github.com/googlei18n/fontview)
 | 
					3. [FontView](https://github.com/googlei18n/fontview)
 | 
				
			||||||
4. [Pillow](https://github.com/python-pillow)
 | 
					4. [Pillow](https://github.com/python-pillow)
 | 
				
			||||||
5. [mplcairo](https://github.com/anntzer/mplcairo)
 | 
					5. [mplcairo](https://github.com/anntzer/mplcairo)
 | 
				
			||||||
 | 
					6. [CEGUI](https://github.com/cegui/cegui)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The following projects have patches to support complex text layout using Raqm:
 | 
					The following projects have patches to support complex text layout using Raqm:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,8 +78,8 @@ The following projects have patches to support complex text layout using Raqm:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[1]: http://fribidi.org
 | 
					[1]: https://github.com/fribidi/fribidi
 | 
				
			||||||
[2]: https://github.com/Tehreer/SheenBidi
 | 
					[2]: https://github.com/Tehreer/SheenBidi
 | 
				
			||||||
[3]: http://harfbuzz.org
 | 
					[3]: https://github.com/harfbuzz/harfbuzz
 | 
				
			||||||
[4]: https://www.freetype.org
 | 
					[4]: https://www.freetype.org
 | 
				
			||||||
[5]: https://www.gtk.org/gtk-doc
 | 
					[5]: https://www.gtk.org/gtk-doc
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								src/thirdparty/raqm/raqm-version.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								src/thirdparty/raqm/raqm-version.h
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -32,10 +32,10 @@
 | 
				
			||||||
#define _RAQM_VERSION_H_
 | 
					#define _RAQM_VERSION_H_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RAQM_VERSION_MAJOR 0
 | 
					#define RAQM_VERSION_MAJOR 0
 | 
				
			||||||
#define RAQM_VERSION_MINOR 8
 | 
					#define RAQM_VERSION_MINOR 9
 | 
				
			||||||
#define RAQM_VERSION_MICRO 0
 | 
					#define RAQM_VERSION_MICRO 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RAQM_VERSION_STRING "0.8.0"
 | 
					#define RAQM_VERSION_STRING "0.9.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RAQM_VERSION_ATLEAST(major,minor,micro) \
 | 
					#define RAQM_VERSION_ATLEAST(major,minor,micro) \
 | 
				
			||||||
    ((major)*10000+(minor)*100+(micro) <= \
 | 
					    ((major)*10000+(minor)*100+(micro) <= \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										469
									
								
								src/thirdparty/raqm/raqm.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										469
									
								
								src/thirdparty/raqm/raqm.c
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
 | 
					 * Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
 | 
				
			||||||
 * Copyright © 2016-2021 Khaled Hosny <khaled@aliftype.com>
 | 
					 * Copyright © 2016-2022 Khaled Hosny <khaled@aliftype.com>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to
 | 
					 * of this software and associated documentation files (the "Software"), to
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#undef HAVE_CONFIG_H  // Workaround for Fribidi 1.0.5 and earlier
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
| 
						 | 
					@ -38,29 +37,11 @@
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#include "../fribidi-shim/fribidi.h"
 | 
					#include "../fribidi-shim/fribidi.h"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#if FRIBIDI_MAJOR_VERSION >= 1
 | 
					 | 
				
			||||||
#define USE_FRIBIDI_EX_API
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <hb.h>
 | 
					#include <hb.h>
 | 
				
			||||||
#include <hb-ft.h>
 | 
					#include <hb-ft.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if FREETYPE_MAJOR > 2 || \
 | 
					 | 
				
			||||||
    FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 11
 | 
					 | 
				
			||||||
#define HAVE_FT_GET_TRANSFORM
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if HB_VERSION_ATLEAST(2, 0, 0)
 | 
					 | 
				
			||||||
#define HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if HB_VERSION_ATLEAST(1, 8, 0)
 | 
					 | 
				
			||||||
#define HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES 1
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES 0
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "raqm.h"
 | 
					#include "raqm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -190,13 +171,9 @@
 | 
				
			||||||
  typedef FriBidiLevel _raqm_bidi_level_t;
 | 
					  typedef FriBidiLevel _raqm_bidi_level_t;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum {
 | 
					 | 
				
			||||||
  RAQM_FLAG_NONE = 0,
 | 
					 | 
				
			||||||
  RAQM_FLAG_UTF8 = 1 << 0
 | 
					 | 
				
			||||||
} _raqm_flags_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
  FT_Face       ftface;
 | 
					  FT_Face       ftface;
 | 
				
			||||||
 | 
					  int           ftloadflags;
 | 
				
			||||||
  hb_language_t lang;
 | 
					  hb_language_t lang;
 | 
				
			||||||
  hb_script_t   script;
 | 
					  hb_script_t   script;
 | 
				
			||||||
} _raqm_text_info;
 | 
					} _raqm_text_info;
 | 
				
			||||||
| 
						 | 
					@ -209,6 +186,7 @@ struct _raqm {
 | 
				
			||||||
  uint32_t        *text;
 | 
					  uint32_t        *text;
 | 
				
			||||||
  char            *text_utf8;
 | 
					  char            *text_utf8;
 | 
				
			||||||
  size_t           text_len;
 | 
					  size_t           text_len;
 | 
				
			||||||
 | 
					  size_t           text_capacity_bytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _raqm_text_info *text_info;
 | 
					  _raqm_text_info *text_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,17 +197,17 @@ struct _raqm {
 | 
				
			||||||
  size_t           features_len;
 | 
					  size_t           features_len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  raqm_run_t      *runs;
 | 
					  raqm_run_t      *runs;
 | 
				
			||||||
 | 
					  raqm_run_t      *runs_pool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  raqm_glyph_t    *glyphs;
 | 
					  raqm_glyph_t    *glyphs;
 | 
				
			||||||
 | 
					  size_t           glyphs_capacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _raqm_flags_t    flags;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  int              ft_loadflags;
 | 
					 | 
				
			||||||
  int              invisible_glyph;
 | 
					  int              invisible_glyph;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct _raqm_run {
 | 
					struct _raqm_run {
 | 
				
			||||||
  int            pos;
 | 
					  uint32_t       pos;
 | 
				
			||||||
  int            len;
 | 
					  uint32_t       len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  hb_direction_t direction;
 | 
					  hb_direction_t direction;
 | 
				
			||||||
  hb_script_t    script;
 | 
					  hb_script_t    script;
 | 
				
			||||||
| 
						 | 
					@ -243,31 +221,21 @@ static uint32_t
 | 
				
			||||||
_raqm_u8_to_u32_index (raqm_t   *rq,
 | 
					_raqm_u8_to_u32_index (raqm_t   *rq,
 | 
				
			||||||
                       uint32_t  index);
 | 
					                       uint32_t  index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static void
 | 
				
			||||||
_raqm_init_text_info (raqm_t *rq)
 | 
					_raqm_init_text_info (raqm_t *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  hb_language_t default_lang;
 | 
					  hb_language_t default_lang = hb_language_get_default ();
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (rq->text_info)
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->text_info = malloc (sizeof (_raqm_text_info) * rq->text_len);
 | 
					 | 
				
			||||||
  if (!rq->text_info)
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  default_lang = hb_language_get_default ();
 | 
					 | 
				
			||||||
  for (size_t i = 0; i < rq->text_len; i++)
 | 
					  for (size_t i = 0; i < rq->text_len; i++)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    rq->text_info[i].ftface = NULL;
 | 
					    rq->text_info[i].ftface = NULL;
 | 
				
			||||||
 | 
					    rq->text_info[i].ftloadflags = -1;
 | 
				
			||||||
    rq->text_info[i].lang = default_lang;
 | 
					    rq->text_info[i].lang = default_lang;
 | 
				
			||||||
    rq->text_info[i].script = HB_SCRIPT_INVALID;
 | 
					    rq->text_info[i].script = HB_SCRIPT_INVALID;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  return true;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
_raqm_free_text_info (raqm_t *rq)
 | 
					_raqm_release_text_info (raqm_t *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  if (!rq->text_info)
 | 
					  if (!rq->text_info)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
| 
						 | 
					@ -277,9 +245,6 @@ _raqm_free_text_info (raqm_t *rq)
 | 
				
			||||||
    if (rq->text_info[i].ftface)
 | 
					    if (rq->text_info[i].ftface)
 | 
				
			||||||
      FT_Done_Face (rq->text_info[i].ftface);
 | 
					      FT_Done_Face (rq->text_info[i].ftface);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  free (rq->text_info);
 | 
					 | 
				
			||||||
  rq->text_info = NULL;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
| 
						 | 
					@ -289,6 +254,9 @@ _raqm_compare_text_info (_raqm_text_info a,
 | 
				
			||||||
  if (a.ftface != b.ftface)
 | 
					  if (a.ftface != b.ftface)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (a.ftloadflags != b.ftloadflags)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (a.lang != b.lang)
 | 
					  if (a.lang != b.lang)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,6 +266,88 @@ _raqm_compare_text_info (_raqm_text_info a,
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					_raqm_free_text(raqm_t* rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  free (rq->text);
 | 
				
			||||||
 | 
					  rq->text = NULL;
 | 
				
			||||||
 | 
					  rq->text_info = NULL;
 | 
				
			||||||
 | 
					  rq->text_utf8 = NULL;
 | 
				
			||||||
 | 
					  rq->text_len = 0;
 | 
				
			||||||
 | 
					  rq->text_capacity_bytes = 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					_raqm_alloc_text(raqm_t *rq,
 | 
				
			||||||
 | 
					                 size_t  len,
 | 
				
			||||||
 | 
					                 bool    need_utf8)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  /* Allocate contiguous memory block for texts and text_info */
 | 
				
			||||||
 | 
					  size_t mem_size = (sizeof (uint32_t) + sizeof (_raqm_text_info)) * len;
 | 
				
			||||||
 | 
					  if (need_utf8)
 | 
				
			||||||
 | 
					    mem_size += sizeof (char) * len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (mem_size > rq->text_capacity_bytes)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    void* new_mem = realloc (rq->text, mem_size);
 | 
				
			||||||
 | 
					    if (!new_mem)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      _raqm_free_text (rq);
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rq->text_capacity_bytes = mem_size;
 | 
				
			||||||
 | 
					    rq->text = new_mem;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rq->text_info = (_raqm_text_info*)(rq->text + len);
 | 
				
			||||||
 | 
					  rq->text_utf8 = need_utf8 ? (char*)(rq->text_info + len) : NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static raqm_run_t*
 | 
				
			||||||
 | 
					_raqm_alloc_run (raqm_t *rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  raqm_run_t *run = rq->runs_pool;
 | 
				
			||||||
 | 
					  if (run)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    rq->runs_pool = run->next;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    run = malloc (sizeof (raqm_run_t));
 | 
				
			||||||
 | 
					    run->font = NULL;
 | 
				
			||||||
 | 
					    run->buffer = NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  run->pos = 0;
 | 
				
			||||||
 | 
					  run->len = 0;
 | 
				
			||||||
 | 
					  run->direction = HB_DIRECTION_INVALID;
 | 
				
			||||||
 | 
					  run->script = HB_SCRIPT_INVALID;
 | 
				
			||||||
 | 
					  run->next = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return run;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					_raqm_free_runs (raqm_run_t *runs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  while (runs)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    raqm_run_t *run = runs;
 | 
				
			||||||
 | 
					    runs = runs->next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (run->buffer)
 | 
				
			||||||
 | 
					      hb_buffer_destroy (run->buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (run->font)
 | 
				
			||||||
 | 
					      hb_font_destroy (run->font);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    free (run);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * raqm_create:
 | 
					 * raqm_create:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -322,26 +372,26 @@ raqm_create (void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->ref_count = 1;
 | 
					  rq->ref_count = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->text = NULL;
 | 
					 | 
				
			||||||
  rq->text_utf8 = NULL;
 | 
					 | 
				
			||||||
  rq->text_len = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->text_info = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->base_dir = RAQM_DIRECTION_DEFAULT;
 | 
					  rq->base_dir = RAQM_DIRECTION_DEFAULT;
 | 
				
			||||||
  rq->resolved_dir = RAQM_DIRECTION_DEFAULT;
 | 
					  rq->resolved_dir = RAQM_DIRECTION_DEFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->features = NULL;
 | 
					  rq->features = NULL;
 | 
				
			||||||
  rq->features_len = 0;
 | 
					  rq->features_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->runs = NULL;
 | 
					 | 
				
			||||||
  rq->glyphs = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->flags = RAQM_FLAG_NONE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->ft_loadflags = -1;
 | 
					 | 
				
			||||||
  rq->invisible_glyph = 0;
 | 
					  rq->invisible_glyph = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rq->text = NULL;
 | 
				
			||||||
 | 
					  rq->text_utf8 = NULL;
 | 
				
			||||||
 | 
					  rq->text_info = NULL;
 | 
				
			||||||
 | 
					  rq->text_capacity_bytes = 0;
 | 
				
			||||||
 | 
					  rq->text_len = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rq->runs = NULL;
 | 
				
			||||||
 | 
					  rq->runs_pool = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rq->glyphs = NULL;
 | 
				
			||||||
 | 
					  rq->glyphs_capacity = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return rq;
 | 
					  return rq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -366,28 +416,13 @@ raqm_reference (raqm_t *rq)
 | 
				
			||||||
  return rq;
 | 
					  return rq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
_raqm_free_runs (raqm_t *rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  raqm_run_t *runs = rq->runs;
 | 
					 | 
				
			||||||
  while (runs)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    raqm_run_t *run = runs;
 | 
					 | 
				
			||||||
    runs = runs->next;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    hb_buffer_destroy (run->buffer);
 | 
					 | 
				
			||||||
    hb_font_destroy (run->font);
 | 
					 | 
				
			||||||
    free (run);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * raqm_destroy:
 | 
					 * raqm_destroy:
 | 
				
			||||||
 * @rq: a #raqm_t.
 | 
					 * @rq: a #raqm_t.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Decreases the reference count on @rq by one. If the result is zero, then @rq
 | 
					 * Decreases the reference count on @rq by one. If the result is zero, then @rq
 | 
				
			||||||
 * and all associated resources are freed.
 | 
					 * and all associated resources are freed.
 | 
				
			||||||
 * See cairo_reference().
 | 
					 * See raqm_reference().
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Since: 0.1
 | 
					 * Since: 0.1
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -397,14 +432,60 @@ raqm_destroy (raqm_t *rq)
 | 
				
			||||||
  if (!rq || --rq->ref_count != 0)
 | 
					  if (!rq || --rq->ref_count != 0)
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  free (rq->text);
 | 
					  _raqm_release_text_info (rq);
 | 
				
			||||||
  free (rq->text_utf8);
 | 
					  _raqm_free_text (rq);
 | 
				
			||||||
  _raqm_free_text_info (rq);
 | 
					  _raqm_free_runs (rq->runs);
 | 
				
			||||||
  _raqm_free_runs (rq);
 | 
					  _raqm_free_runs (rq->runs_pool);
 | 
				
			||||||
  free (rq->glyphs);
 | 
					  free (rq->glyphs);
 | 
				
			||||||
 | 
					  free (rq->features);
 | 
				
			||||||
  free (rq);
 | 
					  free (rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * raqm_clear_contents:
 | 
				
			||||||
 | 
					 * @rq: a #raqm_t.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Clears internal state of previously used raqm_t object, making it ready
 | 
				
			||||||
 | 
					 * for reuse and keeping some of allocated memory to increase performance.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Since: 0.9
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					raqm_clear_contents (raqm_t *rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (!rq)
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _raqm_release_text_info (rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Return allocated runs to the pool, keep hb buffers for reuse */
 | 
				
			||||||
 | 
					  raqm_run_t *run = rq->runs;
 | 
				
			||||||
 | 
					  while (run)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (run->buffer)
 | 
				
			||||||
 | 
					      hb_buffer_reset (run->buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (run->font)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      hb_font_destroy (run->font);
 | 
				
			||||||
 | 
					      run->font = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!run->next)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      run->next = rq->runs_pool;
 | 
				
			||||||
 | 
					      rq->runs_pool = rq->runs;
 | 
				
			||||||
 | 
					      rq->runs = NULL;
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    run = run->next;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rq->text_len = 0;
 | 
				
			||||||
 | 
					  rq->resolved_dir = RAQM_DIRECTION_DEFAULT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * raqm_set_text:
 | 
					 * raqm_set_text:
 | 
				
			||||||
 * @rq: a #raqm_t.
 | 
					 * @rq: a #raqm_t.
 | 
				
			||||||
| 
						 | 
					@ -429,23 +510,20 @@ raqm_set_text (raqm_t         *rq,
 | 
				
			||||||
  if (!rq || !text)
 | 
					  if (!rq || !text)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->text_len = len;
 | 
					  /* Call raqm_clear_contents to reuse this raqm_t */
 | 
				
			||||||
 | 
					  if (rq->text_len)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Empty string, don’t fail but do nothing */
 | 
					  /* Empty string, don’t fail but do nothing */
 | 
				
			||||||
  if (!len)
 | 
					  if (!len)
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  free (rq->text);
 | 
					  if (!_raqm_alloc_text(rq, len, false))
 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->text = malloc (sizeof (uint32_t) * rq->text_len);
 | 
					 | 
				
			||||||
  if (!rq->text)
 | 
					 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  _raqm_free_text_info (rq);
 | 
					  rq->text_len = len;
 | 
				
			||||||
  if (!_raqm_init_text_info (rq))
 | 
					  memcpy (rq->text, text, sizeof (uint32_t) * len);
 | 
				
			||||||
    return false;
 | 
					  _raqm_init_text_info (rq);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  memcpy (rq->text, text, sizeof (uint32_t) * rq->text_len);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -515,37 +593,25 @@ raqm_set_text_utf8 (raqm_t         *rq,
 | 
				
			||||||
                    const char *text,
 | 
					                    const char *text,
 | 
				
			||||||
                    size_t      len)
 | 
					                    size_t      len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  uint32_t *unicode;
 | 
					 | 
				
			||||||
  size_t ulen;
 | 
					 | 
				
			||||||
  bool ok;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!rq || !text)
 | 
					  if (!rq || !text)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Call raqm_clear_contents to reuse this raqm_t */
 | 
				
			||||||
 | 
					  if (rq->text_len)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Empty string, don’t fail but do nothing */
 | 
					  /* Empty string, don’t fail but do nothing */
 | 
				
			||||||
  if (!len)
 | 
					  if (!len)
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    rq->text_len = len;
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->flags |= RAQM_FLAG_UTF8;
 | 
					  if (!_raqm_alloc_text(rq, len, true))
 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->text_utf8 = malloc (sizeof (char) * len);
 | 
					 | 
				
			||||||
  if (!rq->text_utf8)
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  unicode = malloc (sizeof (uint32_t) * len);
 | 
					 | 
				
			||||||
  if (!unicode)
 | 
					 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rq->text_len = _raqm_u8_to_u32 (text, len, rq->text);
 | 
				
			||||||
  memcpy (rq->text_utf8, text, sizeof (char) * len);
 | 
					  memcpy (rq->text_utf8, text, sizeof (char) * len);
 | 
				
			||||||
 | 
					  _raqm_init_text_info (rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ulen = _raqm_u8_to_u32 (text, len, unicode);
 | 
					  return true;
 | 
				
			||||||
  ok = raqm_set_text (rq, unicode, ulen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  free (unicode);
 | 
					 | 
				
			||||||
  return ok;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -561,7 +627,7 @@ raqm_set_text_utf8 (raqm_t         *rq,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The default is #RAQM_DIRECTION_DEFAULT, which determines the paragraph
 | 
					 * The default is #RAQM_DIRECTION_DEFAULT, which determines the paragraph
 | 
				
			||||||
 * direction based on the first character with strong bidi type (see [rule
 | 
					 * direction based on the first character with strong bidi type (see [rule
 | 
				
			||||||
 * P2](http://unicode.org/reports/tr9/#P2) in Unicode Bidirectional Algorithm),
 | 
					 * P2](https://unicode.org/reports/tr9/#P2) in Unicode Bidirectional Algorithm),
 | 
				
			||||||
 * which can be good enough for many cases but has problems when a mainly
 | 
					 * which can be good enough for many cases but has problems when a mainly
 | 
				
			||||||
 * right-to-left paragraph starts with a left-to-right character and vice versa
 | 
					 * right-to-left paragraph starts with a left-to-right character and vice versa
 | 
				
			||||||
 * as the detected paragraph direction will be the wrong one, or when text does
 | 
					 * as the detected paragraph direction will be the wrong one, or when text does
 | 
				
			||||||
| 
						 | 
					@ -629,7 +695,7 @@ raqm_set_language (raqm_t       *rq,
 | 
				
			||||||
  if (!rq->text_len)
 | 
					  if (!rq->text_len)
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rq->flags & RAQM_FLAG_UTF8)
 | 
					  if (rq->text_utf8)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    start = _raqm_u8_to_u32_index (rq, start);
 | 
					    start = _raqm_u8_to_u32_index (rq, start);
 | 
				
			||||||
    end = _raqm_u8_to_u32_index (rq, end);
 | 
					    end = _raqm_u8_to_u32_index (rq, end);
 | 
				
			||||||
| 
						 | 
					@ -686,13 +752,14 @@ raqm_add_font_feature (raqm_t     *rq,
 | 
				
			||||||
  ok = hb_feature_from_string (feature, len, &fea);
 | 
					  ok = hb_feature_from_string (feature, len, &fea);
 | 
				
			||||||
  if (ok)
 | 
					  if (ok)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    rq->features_len++;
 | 
					    void* new_features = realloc (rq->features,
 | 
				
			||||||
    rq->features = realloc (rq->features,
 | 
					                                  sizeof (hb_feature_t) * (rq->features_len + 1));
 | 
				
			||||||
                            sizeof (hb_feature_t) * (rq->features_len));
 | 
					    if (!new_features)
 | 
				
			||||||
    if (!rq->features)
 | 
					 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rq->features[rq->features_len - 1] = fea;
 | 
					    rq->features = new_features;
 | 
				
			||||||
 | 
					    rq->features[rq->features_len] = fea;
 | 
				
			||||||
 | 
					    rq->features_len++;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return ok;
 | 
					  return ok;
 | 
				
			||||||
| 
						 | 
					@ -700,12 +767,13 @@ raqm_add_font_feature (raqm_t     *rq,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static hb_font_t *
 | 
					static hb_font_t *
 | 
				
			||||||
_raqm_create_hb_font (raqm_t *rq,
 | 
					_raqm_create_hb_font (raqm_t *rq,
 | 
				
			||||||
                      FT_Face face)
 | 
					                      FT_Face face,
 | 
				
			||||||
 | 
					                      int     loadflags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  hb_font_t *font = hb_ft_font_create_referenced (face);
 | 
					  hb_font_t *font = hb_ft_font_create_referenced (face);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rq->ft_loadflags >= 0)
 | 
					  if (loadflags >= 0)
 | 
				
			||||||
    hb_ft_font_set_load_flags (font, rq->ft_loadflags);
 | 
					    hb_ft_font_set_load_flags (font, loadflags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return font;
 | 
					  return font;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -796,7 +864,7 @@ raqm_set_freetype_face_range (raqm_t *rq,
 | 
				
			||||||
  if (!rq->text_len)
 | 
					  if (!rq->text_len)
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rq->flags & RAQM_FLAG_UTF8)
 | 
					  if (rq->text_utf8)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    start = _raqm_u8_to_u32_index (rq, start);
 | 
					    start = _raqm_u8_to_u32_index (rq, start);
 | 
				
			||||||
    end = _raqm_u8_to_u32_index (rq, end);
 | 
					    end = _raqm_u8_to_u32_index (rq, end);
 | 
				
			||||||
| 
						 | 
					@ -805,6 +873,30 @@ raqm_set_freetype_face_range (raqm_t *rq,
 | 
				
			||||||
  return _raqm_set_freetype_face (rq, face, start, end);
 | 
					  return _raqm_set_freetype_face (rq, face, start, end);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool
 | 
				
			||||||
 | 
					_raqm_set_freetype_load_flags (raqm_t *rq,
 | 
				
			||||||
 | 
					                               int     flags,
 | 
				
			||||||
 | 
					                               size_t  start,
 | 
				
			||||||
 | 
					                               size_t  end)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (!rq)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!rq->text_len)
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (start >= rq->text_len || end > rq->text_len)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!rq->text_info)
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (size_t i = start; i < end; i++)
 | 
				
			||||||
 | 
					    rq->text_info[i].ftloadflags = flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * raqm_set_freetype_load_flags:
 | 
					 * raqm_set_freetype_load_flags:
 | 
				
			||||||
 * @rq: a #raqm_t.
 | 
					 * @rq: a #raqm_t.
 | 
				
			||||||
| 
						 | 
					@ -825,12 +917,57 @@ bool
 | 
				
			||||||
raqm_set_freetype_load_flags (raqm_t *rq,
 | 
					raqm_set_freetype_load_flags (raqm_t *rq,
 | 
				
			||||||
                              int     flags)
 | 
					                              int     flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  return _raqm_set_freetype_load_flags(rq, flags, 0, rq->text_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * raqm_set_freetype_load_flags_range:
 | 
				
			||||||
 | 
					 * @rq: a #raqm_t.
 | 
				
			||||||
 | 
					 * @flags: FreeType load flags.
 | 
				
			||||||
 | 
					 * @start: index of first character that should use @flags.
 | 
				
			||||||
 | 
					 * @len: number of characters using @flags.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Sets the load flags passed to FreeType when loading glyphs for @len-number
 | 
				
			||||||
 | 
					 * of characters staring at @start. Flags should be the same as used by the
 | 
				
			||||||
 | 
					 * client when rendering corresponding FreeType glyphs. The @start and @len
 | 
				
			||||||
 | 
					 * are input string array indices (i.e. counting bytes in UTF-8 and scaler
 | 
				
			||||||
 | 
					 * values in UTF-32).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This method can be used repeatedly to set different flags for different
 | 
				
			||||||
 | 
					 * parts of the text. It is the responsibility of the client to make sure that
 | 
				
			||||||
 | 
					 * flag ranges cover the whole text.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This requires version of HarfBuzz that has hb_ft_font_set_load_flags(), for
 | 
				
			||||||
 | 
					 * older version the flags will be ignored.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * See also raqm_set_freetype_load_flags().
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Return value:
 | 
				
			||||||
 | 
					 * %true if no errors happened, %false otherwise.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Since: 0.9
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					raqm_set_freetype_load_flags_range (raqm_t *rq,
 | 
				
			||||||
 | 
					                                    int     flags,
 | 
				
			||||||
 | 
					                                    size_t  start,
 | 
				
			||||||
 | 
					                                    size_t  len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  size_t end = start + len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!rq)
 | 
					  if (!rq)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rq->ft_loadflags = flags;
 | 
					  if (!rq->text_len)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (rq->text_utf8)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    start = _raqm_u8_to_u32_index (rq, start);
 | 
				
			||||||
 | 
					    end = _raqm_u8_to_u32_index (rq, end);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return _raqm_set_freetype_load_flags (rq, flags, start, end);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -841,17 +978,10 @@ raqm_set_freetype_load_flags (raqm_t *rq,
 | 
				
			||||||
 * Sets the glyph id to be used for invisible glyhphs.
 | 
					 * Sets the glyph id to be used for invisible glyhphs.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If @gid is negative, invisible glyphs will be suppressed from the output.
 | 
					 * If @gid is negative, invisible glyphs will be suppressed from the output.
 | 
				
			||||||
 * This requires HarfBuzz 1.8.0 or later. If raqm is used with an earlier
 | 
					 | 
				
			||||||
 * HarfBuzz version, the return value will be %false and the shaping behavior
 | 
					 | 
				
			||||||
 * does not change.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If @gid is zero, invisible glyphs will be rendered as space.
 | 
					 * If @gid is zero, invisible glyphs will be rendered as space.
 | 
				
			||||||
 * This works on all versions of HarfBuzz.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * If @gid is a positive number, it will be used for invisible glyphs.
 | 
					 * If @gid is a positive number, it will be used for invisible glyphs.
 | 
				
			||||||
 * This requires a version of HarfBuzz that has
 | 
					 | 
				
			||||||
 * hb_buffer_set_invisible_glyph(). For older versions, the return value
 | 
					 | 
				
			||||||
 * will be %false and the shaping behavior does not change.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Return value:
 | 
					 * Return value:
 | 
				
			||||||
 * %true if no errors happened, %false otherwise.
 | 
					 * %true if no errors happened, %false otherwise.
 | 
				
			||||||
| 
						 | 
					@ -865,17 +995,6 @@ raqm_set_invisible_glyph (raqm_t *rq,
 | 
				
			||||||
  if (!rq)
 | 
					  if (!rq)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH
 | 
					 | 
				
			||||||
  if (gid > 0)
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if !defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) || \
 | 
					 | 
				
			||||||
    !HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES
 | 
					 | 
				
			||||||
  if (gid < 0)
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->invisible_glyph = gid;
 | 
					  rq->invisible_glyph = gid;
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -961,18 +1080,21 @@ raqm_get_glyphs (raqm_t *rq,
 | 
				
			||||||
  for (raqm_run_t *run = rq->runs; run != NULL; run = run->next)
 | 
					  for (raqm_run_t *run = rq->runs; run != NULL; run = run->next)
 | 
				
			||||||
    count += hb_buffer_get_length (run->buffer);
 | 
					    count += hb_buffer_get_length (run->buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  *length = count;
 | 
					  if (count > rq->glyphs_capacity)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
  if (rq->glyphs)
 | 
					    void* new_mem = realloc (rq->glyphs, sizeof (raqm_glyph_t) * count);
 | 
				
			||||||
    free (rq->glyphs);
 | 
					    if (!new_mem)
 | 
				
			||||||
 | 
					 | 
				
			||||||
  rq->glyphs = malloc (sizeof (raqm_glyph_t) * count);
 | 
					 | 
				
			||||||
  if (!rq->glyphs)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      *length = 0;
 | 
					      *length = 0;
 | 
				
			||||||
      return NULL;
 | 
					      return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rq->glyphs = new_mem;
 | 
				
			||||||
 | 
					    rq->glyphs_capacity = count;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *length = count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  RAQM_TEST ("Glyph information:\n");
 | 
					  RAQM_TEST ("Glyph information:\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  count = 0;
 | 
					  count = 0;
 | 
				
			||||||
| 
						 | 
					@ -1005,7 +1127,7 @@ raqm_get_glyphs (raqm_t *rq,
 | 
				
			||||||
    count += len;
 | 
					    count += len;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rq->flags & RAQM_FLAG_UTF8)
 | 
					  if (rq->text_utf8)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
#ifdef RAQM_TESTING
 | 
					#ifdef RAQM_TESTING
 | 
				
			||||||
    RAQM_TEST ("\nUTF-32 clusters:");
 | 
					    RAQM_TEST ("\nUTF-32 clusters:");
 | 
				
			||||||
| 
						 | 
					@ -1276,24 +1398,14 @@ _raqm_bidi_itemize (raqm_t *rq, size_t *run_count)
 | 
				
			||||||
  FriBidiCharType *types;
 | 
					  FriBidiCharType *types;
 | 
				
			||||||
  _raqm_bidi_level_t *levels;
 | 
					  _raqm_bidi_level_t *levels;
 | 
				
			||||||
  int max_level = 0;
 | 
					  int max_level = 0;
 | 
				
			||||||
#ifdef USE_FRIBIDI_EX_API
 | 
					 | 
				
			||||||
  FriBidiBracketType *btypes;
 | 
					  FriBidiBracketType *btypes;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  types = calloc (rq->text_len, sizeof (FriBidiCharType));
 | 
					  types = calloc (rq->text_len, sizeof (FriBidiCharType));
 | 
				
			||||||
#ifdef USE_FRIBIDI_EX_API
 | 
					 | 
				
			||||||
  btypes = calloc (rq->text_len, sizeof (FriBidiBracketType));
 | 
					  btypes = calloc (rq->text_len, sizeof (FriBidiBracketType));
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  levels = calloc (rq->text_len, sizeof (_raqm_bidi_level_t));
 | 
					  levels = calloc (rq->text_len, sizeof (_raqm_bidi_level_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!types || !levels
 | 
					  if (!types || !levels || !btypes)
 | 
				
			||||||
#ifdef USE_FRIBIDI_EX_API
 | 
					 | 
				
			||||||
      || !btypes
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
      )
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    goto done;
 | 
					    goto done;
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rq->base_dir == RAQM_DIRECTION_RTL)
 | 
					  if (rq->base_dir == RAQM_DIRECTION_RTL)
 | 
				
			||||||
    par_type = FRIBIDI_PAR_RTL;
 | 
					    par_type = FRIBIDI_PAR_RTL;
 | 
				
			||||||
| 
						 | 
					@ -1301,15 +1413,10 @@ _raqm_bidi_itemize (raqm_t *rq, size_t *run_count)
 | 
				
			||||||
    par_type = FRIBIDI_PAR_LTR;
 | 
					    par_type = FRIBIDI_PAR_LTR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fribidi_get_bidi_types (rq->text, rq->text_len, types);
 | 
					  fribidi_get_bidi_types (rq->text, rq->text_len, types);
 | 
				
			||||||
#ifdef USE_FRIBIDI_EX_API
 | 
					 | 
				
			||||||
  fribidi_get_bracket_types (rq->text, rq->text_len, types, btypes);
 | 
					  fribidi_get_bracket_types (rq->text, rq->text_len, types, btypes);
 | 
				
			||||||
  max_level = fribidi_get_par_embedding_levels_ex (types, btypes,
 | 
					  max_level = fribidi_get_par_embedding_levels_ex (types, btypes,
 | 
				
			||||||
                                                   rq->text_len, &par_type,
 | 
					                                                   rq->text_len, &par_type,
 | 
				
			||||||
                                                   levels);
 | 
					                                                   levels);
 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
  max_level = fribidi_get_par_embedding_levels (types, rq->text_len,
 | 
					 | 
				
			||||||
                                                &par_type, levels);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (par_type == FRIBIDI_PAR_LTR)
 | 
					  if (par_type == FRIBIDI_PAR_LTR)
 | 
				
			||||||
    rq->resolved_dir = RAQM_DIRECTION_LTR;
 | 
					    rq->resolved_dir = RAQM_DIRECTION_LTR;
 | 
				
			||||||
| 
						 | 
					@ -1325,9 +1432,7 @@ _raqm_bidi_itemize (raqm_t *rq, size_t *run_count)
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
  free (types);
 | 
					  free (types);
 | 
				
			||||||
  free (levels);
 | 
					  free (levels);
 | 
				
			||||||
#ifdef USE_FRIBIDI_EX_API
 | 
					 | 
				
			||||||
  free (btypes);
 | 
					  free (btypes);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return runs;
 | 
					  return runs;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1403,7 +1508,7 @@ _raqm_itemize (raqm_t *rq)
 | 
				
			||||||
  last = NULL;
 | 
					  last = NULL;
 | 
				
			||||||
  for (size_t i = 0; i < run_count; i++)
 | 
					  for (size_t i = 0; i < run_count; i++)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    raqm_run_t *run = calloc (1, sizeof (raqm_run_t));
 | 
					    raqm_run_t *run = _raqm_alloc_run (rq);
 | 
				
			||||||
    if (!run)
 | 
					    if (!run)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      ok = false;
 | 
					      ok = false;
 | 
				
			||||||
| 
						 | 
					@ -1422,13 +1527,14 @@ _raqm_itemize (raqm_t *rq)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      run->pos = runs[i].pos + runs[i].len - 1;
 | 
					      run->pos = runs[i].pos + runs[i].len - 1;
 | 
				
			||||||
      run->script = rq->text_info[run->pos].script;
 | 
					      run->script = rq->text_info[run->pos].script;
 | 
				
			||||||
      run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface);
 | 
					      run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface,
 | 
				
			||||||
 | 
					          rq->text_info[run->pos].ftloadflags);
 | 
				
			||||||
      for (int j = runs[i].len - 1; j >= 0; j--)
 | 
					      for (int j = runs[i].len - 1; j >= 0; j--)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        _raqm_text_info info = rq->text_info[runs[i].pos + j];
 | 
					        _raqm_text_info info = rq->text_info[runs[i].pos + j];
 | 
				
			||||||
        if (!_raqm_compare_text_info (rq->text_info[run->pos], info))
 | 
					        if (!_raqm_compare_text_info (rq->text_info[run->pos], info))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t));
 | 
					          raqm_run_t *newrun = _raqm_alloc_run (rq);
 | 
				
			||||||
          if (!newrun)
 | 
					          if (!newrun)
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            ok = false;
 | 
					            ok = false;
 | 
				
			||||||
| 
						 | 
					@ -1438,7 +1544,8 @@ _raqm_itemize (raqm_t *rq)
 | 
				
			||||||
          newrun->len = 1;
 | 
					          newrun->len = 1;
 | 
				
			||||||
          newrun->direction = _raqm_hb_dir (rq, runs[i].level);
 | 
					          newrun->direction = _raqm_hb_dir (rq, runs[i].level);
 | 
				
			||||||
          newrun->script = info.script;
 | 
					          newrun->script = info.script;
 | 
				
			||||||
          newrun->font = _raqm_create_hb_font (rq, info.ftface);
 | 
					          newrun->font = _raqm_create_hb_font (rq, info.ftface,
 | 
				
			||||||
 | 
					              info.ftloadflags);
 | 
				
			||||||
          run->next = newrun;
 | 
					          run->next = newrun;
 | 
				
			||||||
          run = newrun;
 | 
					          run = newrun;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -1453,13 +1560,14 @@ _raqm_itemize (raqm_t *rq)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      run->pos = runs[i].pos;
 | 
					      run->pos = runs[i].pos;
 | 
				
			||||||
      run->script = rq->text_info[run->pos].script;
 | 
					      run->script = rq->text_info[run->pos].script;
 | 
				
			||||||
      run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface);
 | 
					      run->font = _raqm_create_hb_font (rq, rq->text_info[run->pos].ftface,
 | 
				
			||||||
 | 
					          rq->text_info[run->pos].ftloadflags);
 | 
				
			||||||
      for (size_t j = 0; j < runs[i].len; j++)
 | 
					      for (size_t j = 0; j < runs[i].len; j++)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        _raqm_text_info info = rq->text_info[runs[i].pos + j];
 | 
					        _raqm_text_info info = rq->text_info[runs[i].pos + j];
 | 
				
			||||||
        if (!_raqm_compare_text_info (rq->text_info[run->pos], info))
 | 
					        if (!_raqm_compare_text_info (rq->text_info[run->pos], info))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          raqm_run_t *newrun = calloc (1, sizeof (raqm_run_t));
 | 
					          raqm_run_t *newrun = _raqm_alloc_run (rq);
 | 
				
			||||||
          if (!newrun)
 | 
					          if (!newrun)
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
            ok = false;
 | 
					            ok = false;
 | 
				
			||||||
| 
						 | 
					@ -1469,7 +1577,8 @@ _raqm_itemize (raqm_t *rq)
 | 
				
			||||||
          newrun->len = 1;
 | 
					          newrun->len = 1;
 | 
				
			||||||
          newrun->direction = _raqm_hb_dir (rq, runs[i].level);
 | 
					          newrun->direction = _raqm_hb_dir (rq, runs[i].level);
 | 
				
			||||||
          newrun->script = info.script;
 | 
					          newrun->script = info.script;
 | 
				
			||||||
          newrun->font = _raqm_create_hb_font (rq, info.ftface);
 | 
					          newrun->font = _raqm_create_hb_font (rq, info.ftface,
 | 
				
			||||||
 | 
					              info.ftloadflags);
 | 
				
			||||||
          run->next = newrun;
 | 
					          run->next = newrun;
 | 
				
			||||||
          run = newrun;
 | 
					          run = newrun;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -1758,7 +1867,6 @@ _raqm_resolve_scripts (raqm_t *rq)
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_FT_GET_TRANSFORM
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
_raqm_ft_transform (int      *x,
 | 
					_raqm_ft_transform (int      *x,
 | 
				
			||||||
                    int      *y,
 | 
					                    int      *y,
 | 
				
			||||||
| 
						 | 
					@ -1773,21 +1881,18 @@ _raqm_ft_transform (int      *x,
 | 
				
			||||||
  *x = vector.x;
 | 
					  *x = vector.x;
 | 
				
			||||||
  *y = vector.y;
 | 
					  *y = vector.y;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool
 | 
					static bool
 | 
				
			||||||
_raqm_shape (raqm_t *rq)
 | 
					_raqm_shape (raqm_t *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  hb_buffer_flags_t hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT;
 | 
					  hb_buffer_flags_t hb_buffer_flags = HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES) && \
 | 
					 | 
				
			||||||
    HAVE_DECL_HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES
 | 
					 | 
				
			||||||
  if (rq->invisible_glyph < 0)
 | 
					  if (rq->invisible_glyph < 0)
 | 
				
			||||||
    hb_buffer_flags |= HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES;
 | 
					    hb_buffer_flags |= HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES;
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (raqm_run_t *run = rq->runs; run != NULL; run = run->next)
 | 
					  for (raqm_run_t *run = rq->runs; run != NULL; run = run->next)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    if (!run->buffer)
 | 
				
			||||||
      run->buffer = hb_buffer_create ();
 | 
					      run->buffer = hb_buffer_create ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hb_buffer_add_utf32 (run->buffer, rq->text, rq->text_len,
 | 
					    hb_buffer_add_utf32 (run->buffer, rq->text, rq->text_len,
 | 
				
			||||||
| 
						 | 
					@ -1797,15 +1902,12 @@ _raqm_shape (raqm_t *rq)
 | 
				
			||||||
    hb_buffer_set_direction (run->buffer, run->direction);
 | 
					    hb_buffer_set_direction (run->buffer, run->direction);
 | 
				
			||||||
    hb_buffer_set_flags (run->buffer, hb_buffer_flags);
 | 
					    hb_buffer_set_flags (run->buffer, hb_buffer_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_HB_BUFFER_SET_INVISIBLE_GLYPH
 | 
					 | 
				
			||||||
    if (rq->invisible_glyph > 0)
 | 
					    if (rq->invisible_glyph > 0)
 | 
				
			||||||
      hb_buffer_set_invisible_glyph (run->buffer, rq->invisible_glyph);
 | 
					      hb_buffer_set_invisible_glyph (run->buffer, rq->invisible_glyph);
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    hb_shape_full (run->font, run->buffer, rq->features, rq->features_len,
 | 
					    hb_shape_full (run->font, run->buffer, rq->features, rq->features_len,
 | 
				
			||||||
                   NULL);
 | 
					                   NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_FT_GET_TRANSFORM
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      FT_Matrix matrix;
 | 
					      FT_Matrix matrix;
 | 
				
			||||||
      hb_glyph_position_t *pos;
 | 
					      hb_glyph_position_t *pos;
 | 
				
			||||||
| 
						 | 
					@ -1819,7 +1921,6 @@ _raqm_shape (raqm_t *rq)
 | 
				
			||||||
        _raqm_ft_transform (&pos[i].x_offset, &pos[i].y_offset, matrix);
 | 
					        _raqm_ft_transform (&pos[i].x_offset, &pos[i].y_offset, matrix);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
| 
						 | 
					@ -1917,7 +2018,7 @@ raqm_index_to_position (raqm_t *rq,
 | 
				
			||||||
  if (rq == NULL)
 | 
					  if (rq == NULL)
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (rq->flags & RAQM_FLAG_UTF8)
 | 
					  if (rq->text_utf8)
 | 
				
			||||||
    *index = _raqm_u8_to_u32_index (rq, *index);
 | 
					    *index = _raqm_u8_to_u32_index (rq, *index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (*index >= rq->text_len)
 | 
					  if (*index >= rq->text_len)
 | 
				
			||||||
| 
						 | 
					@ -1974,7 +2075,7 @@ raqm_index_to_position (raqm_t *rq,
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
found:
 | 
					found:
 | 
				
			||||||
  if (rq->flags & RAQM_FLAG_UTF8)
 | 
					  if (rq->text_utf8)
 | 
				
			||||||
    *index = _raqm_u32_to_u8_index (rq, *index);
 | 
					    *index = _raqm_u32_to_u8_index (rq, *index);
 | 
				
			||||||
  RAQM_TEST ("The position is %d at index %zu\n",*x ,*index);
 | 
					  RAQM_TEST ("The position is %d at index %zu\n",*x ,*index);
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/thirdparty/raqm/raqm.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								src/thirdparty/raqm/raqm.h
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
 | 
					 * Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>
 | 
				
			||||||
 * Copyright © 2016-2021 Khaled Hosny <khaled@aliftype.com>
 | 
					 * Copyright © 2016-2022 Khaled Hosny <khaled@aliftype.com>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
				
			||||||
 * of this software and associated documentation files (the "Software"), to
 | 
					 * of this software and associated documentation files (the "Software"), to
 | 
				
			||||||
| 
						 | 
					@ -106,6 +106,9 @@ raqm_reference (raqm_t *rq);
 | 
				
			||||||
RAQM_API void
 | 
					RAQM_API void
 | 
				
			||||||
raqm_destroy (raqm_t *rq);
 | 
					raqm_destroy (raqm_t *rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RAQM_API void
 | 
				
			||||||
 | 
					raqm_clear_contents (raqm_t *rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RAQM_API bool
 | 
					RAQM_API bool
 | 
				
			||||||
raqm_set_text (raqm_t         *rq,
 | 
					raqm_set_text (raqm_t         *rq,
 | 
				
			||||||
               const uint32_t *text,
 | 
					               const uint32_t *text,
 | 
				
			||||||
| 
						 | 
					@ -145,6 +148,12 @@ RAQM_API bool
 | 
				
			||||||
raqm_set_freetype_load_flags (raqm_t *rq,
 | 
					raqm_set_freetype_load_flags (raqm_t *rq,
 | 
				
			||||||
                              int flags);
 | 
					                              int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RAQM_API bool
 | 
				
			||||||
 | 
					raqm_set_freetype_load_flags_range (raqm_t *rq,
 | 
				
			||||||
 | 
					                                    int     flags,
 | 
				
			||||||
 | 
					                                    size_t  start,
 | 
				
			||||||
 | 
					                                    size_t  len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RAQM_API bool
 | 
					RAQM_API bool
 | 
				
			||||||
raqm_set_invisible_glyph (raqm_t *rq,
 | 
					raqm_set_invisible_glyph (raqm_t *rq,
 | 
				
			||||||
                          int gid);
 | 
					                          int gid);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,7 +24,7 @@ Download and install:
 | 
				
			||||||
* `CMake 3.12 or newer <https://cmake.org/download/>`_
 | 
					* `CMake 3.12 or newer <https://cmake.org/download/>`_
 | 
				
			||||||
  (also available as Visual Studio component C++ CMake tools for Windows)
 | 
					  (also available as Visual Studio component C++ CMake tools for Windows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* `NASM <https://www.nasm.us/pub/nasm/releasebuilds/?C=M;O=D>`_
 | 
					* x86/x64: `NASM <https://www.nasm.us/pub/nasm/releasebuilds/?C=M;O=D>`_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Any version of Visual Studio 2017 or newer should be supported,
 | 
					Any version of Visual Studio 2017 or newer should be supported,
 | 
				
			||||||
including Visual Studio 2017 Community, or Build Tools for Visual Studio 2019.
 | 
					including Visual Studio 2017 Community, or Build Tools for Visual Studio 2019.
 | 
				
			||||||
| 
						 | 
					@ -42,8 +42,8 @@ behaviour of ``build_prepare.py``:
 | 
				
			||||||
  If ``PYTHON`` is unset, the version of Python used to run
 | 
					  If ``PYTHON`` is unset, the version of Python used to run
 | 
				
			||||||
  ``build_prepare.py`` will be used. If only ``PYTHON`` is set,
 | 
					  ``build_prepare.py`` will be used. If only ``PYTHON`` is set,
 | 
				
			||||||
  ``EXECUTABLE`` defaults to ``python.exe``.
 | 
					  ``EXECUTABLE`` defaults to ``python.exe``.
 | 
				
			||||||
* ``ARCHITECTURE`` is used to select a ``x86`` or ``x64`` build. By default,
 | 
					* ``ARCHITECTURE`` is used to select a ``x86``, ``x64`` or ``ARM64``build.
 | 
				
			||||||
  uses same architecture as the version of Python used to run ``build_prepare.py``.
 | 
					  By default, uses same architecture as the version of Python used to run ``build_prepare.py``.
 | 
				
			||||||
  is used.
 | 
					  is used.
 | 
				
			||||||
* ``PILLOW_BUILD`` can be used to override the ``winbuild\build`` directory
 | 
					* ``PILLOW_BUILD`` can be used to override the ``winbuild\build`` directory
 | 
				
			||||||
  path, used to store generated build scripts and compiled libraries.
 | 
					  path, used to store generated build scripts and compiled libraries.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import platform
 | 
				
			||||||
import shutil
 | 
					import shutil
 | 
				
			||||||
import struct
 | 
					import struct
 | 
				
			||||||
import subprocess
 | 
					import subprocess
 | 
				
			||||||
| 
						 | 
					@ -93,6 +94,7 @@ SF_MIRROR = "http://iweb.dl.sourceforge.net"
 | 
				
			||||||
architectures = {
 | 
					architectures = {
 | 
				
			||||||
    "x86": {"vcvars_arch": "x86", "msbuild_arch": "Win32"},
 | 
					    "x86": {"vcvars_arch": "x86", "msbuild_arch": "Win32"},
 | 
				
			||||||
    "x64": {"vcvars_arch": "x86_amd64", "msbuild_arch": "x64"},
 | 
					    "x64": {"vcvars_arch": "x86_amd64", "msbuild_arch": "x64"},
 | 
				
			||||||
 | 
					    "ARM64": {"vcvars_arch": "x86_arm64", "msbuild_arch": "ARM64"},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
header = [
 | 
					header = [
 | 
				
			||||||
| 
						 | 
					@ -219,25 +221,25 @@ deps = {
 | 
				
			||||||
        # "bins": [r"objs\{msbuild_arch}\Release\freetype.dll"],
 | 
					        # "bins": [r"objs\{msbuild_arch}\Release\freetype.dll"],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "lcms2": {
 | 
					    "lcms2": {
 | 
				
			||||||
        "url": SF_MIRROR + "/project/lcms/lcms/2.12/lcms2-2.12.tar.gz",
 | 
					        "url": SF_MIRROR + "/project/lcms/lcms/2.13/lcms2-2.13.tar.gz",
 | 
				
			||||||
        "filename": "lcms2-2.12.tar.gz",
 | 
					        "filename": "lcms2-2.13.tar.gz",
 | 
				
			||||||
        "dir": "lcms2-2.12",
 | 
					        "dir": "lcms2-2.13",
 | 
				
			||||||
        "patch": {
 | 
					        "patch": {
 | 
				
			||||||
            r"Projects\VC2017\lcms2_static\lcms2_static.vcxproj": {
 | 
					            r"Projects\VC2019\lcms2_static\lcms2_static.vcxproj": {
 | 
				
			||||||
                # default is /MD for x86 and /MT for x64, we need /MD always
 | 
					                # default is /MD for x86 and /MT for x64, we need /MD always
 | 
				
			||||||
                "<RuntimeLibrary>MultiThreaded</RuntimeLibrary>": "<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>",  # noqa: E501
 | 
					                "<RuntimeLibrary>MultiThreaded</RuntimeLibrary>": "<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>",  # noqa: E501
 | 
				
			||||||
                # retarget to default toolset (selected by vcvarsall.bat)
 | 
					                # retarget to default toolset (selected by vcvarsall.bat)
 | 
				
			||||||
                "<PlatformToolset>v141</PlatformToolset>": "<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>",  # noqa: E501
 | 
					                "<PlatformToolset>v142</PlatformToolset>": "<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>",  # noqa: E501
 | 
				
			||||||
                # retarget to latest (selected by vcvarsall.bat)
 | 
					                # retarget to latest (selected by vcvarsall.bat)
 | 
				
			||||||
                "<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>": "<WindowsTargetPlatformVersion>$(WindowsSDKVersion)</WindowsTargetPlatformVersion>",  # noqa: E501
 | 
					                "<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>": "<WindowsTargetPlatformVersion>$(WindowsSDKVersion)</WindowsTargetPlatformVersion>",  # noqa: E501
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "build": [
 | 
					        "build": [
 | 
				
			||||||
            cmd_rmdir("Lib"),
 | 
					            cmd_rmdir("Lib"),
 | 
				
			||||||
            cmd_rmdir(r"Projects\VC2017\Release"),
 | 
					            cmd_rmdir(r"Projects\VC2019\Release"),
 | 
				
			||||||
            cmd_msbuild(r"Projects\VC2017\lcms2.sln", "Release", "Clean"),
 | 
					            cmd_msbuild(r"Projects\VC2019\lcms2.sln", "Release", "Clean"),
 | 
				
			||||||
            cmd_msbuild(
 | 
					            cmd_msbuild(
 | 
				
			||||||
                r"Projects\VC2017\lcms2.sln", "Release", "lcms2_static:Rebuild"
 | 
					                r"Projects\VC2019\lcms2.sln", "Release", "lcms2_static:Rebuild"
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            cmd_xcopy("include", "{inc_dir}"),
 | 
					            cmd_xcopy("include", "{inc_dir}"),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
| 
						 | 
					@ -278,9 +280,9 @@ deps = {
 | 
				
			||||||
        "libs": [r"imagequant.lib"],
 | 
					        "libs": [r"imagequant.lib"],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "harfbuzz": {
 | 
					    "harfbuzz": {
 | 
				
			||||||
        "url": "https://github.com/harfbuzz/harfbuzz/archive/3.2.0.zip",
 | 
					        "url": "https://github.com/harfbuzz/harfbuzz/archive/3.3.1.zip",
 | 
				
			||||||
        "filename": "harfbuzz-3.2.0.zip",
 | 
					        "filename": "harfbuzz-3.3.1.zip",
 | 
				
			||||||
        "dir": "harfbuzz-3.2.0",
 | 
					        "dir": "harfbuzz-3.3.1",
 | 
				
			||||||
        "build": [
 | 
					        "build": [
 | 
				
			||||||
            cmd_cmake("-DHB_HAVE_FREETYPE:BOOL=TRUE"),
 | 
					            cmd_cmake("-DHB_HAVE_FREETYPE:BOOL=TRUE"),
 | 
				
			||||||
            cmd_nmake(target="clean"),
 | 
					            cmd_nmake(target="clean"),
 | 
				
			||||||
| 
						 | 
					@ -490,7 +492,10 @@ if __name__ == "__main__":
 | 
				
			||||||
    python_dir = os.environ.get("PYTHON")
 | 
					    python_dir = os.environ.get("PYTHON")
 | 
				
			||||||
    python_exe = os.environ.get("EXECUTABLE", "python.exe")
 | 
					    python_exe = os.environ.get("EXECUTABLE", "python.exe")
 | 
				
			||||||
    architecture = os.environ.get(
 | 
					    architecture = os.environ.get(
 | 
				
			||||||
        "ARCHITECTURE", "x86" if struct.calcsize("P") == 4 else "x64"
 | 
					        "ARCHITECTURE",
 | 
				
			||||||
 | 
					        "ARM64"
 | 
				
			||||||
 | 
					        if platform.machine() == "ARM64"
 | 
				
			||||||
 | 
					        else ("x86" if struct.calcsize("P") == 4 else "x64"),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    build_dir = os.environ.get("PILLOW_BUILD", os.path.join(winbuild_dir, "build"))
 | 
					    build_dir = os.environ.get("PILLOW_BUILD", os.path.join(winbuild_dir, "build"))
 | 
				
			||||||
    sources_dir = ""
 | 
					    sources_dir = ""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user