├── .github └── workflows │ └── wheels.yml ├── .gitignore ├── .gitmodules ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── bootstrap.min.css ├── build-wheels.sh ├── demo-pit11 ├── make-demo-html ├── pit11.py ├── pit11.xml ├── pit11.xsd ├── pit11.xsl └── styl.xsl ├── demo.html ├── litehtml-dumper.py ├── litehtml-pango-png.py ├── litehtml-t-web_color.py ├── litehtml-wx-browser.py ├── litehtml-wx-png-paged.py ├── litehtml-wx-png.py ├── litehtml-wx-print.py ├── litehtmld.py ├── litehtmlt.html ├── litehtmlt.py ├── logme.py ├── mingw-cross.cmake ├── pyproject.toml ├── set_inner_html.cpp ├── setup.py ├── src ├── background.h ├── borders.h ├── cairo │ ├── cairo_borders.cpp │ ├── cairo_borders.h │ ├── cairo_images_cache.h │ ├── container_cairo.cpp │ ├── container_cairo.h │ ├── container_cairo_pango.cpp │ └── container_cairo_pango.h ├── css_length.h ├── css_margins.h ├── css_offsets.h ├── css_position.h ├── css_properties.h ├── css_selector.h ├── document.h ├── document_container.h ├── element.h ├── flex_item.h ├── flex_line.h ├── font_description.h ├── formatting_context.h ├── html.h ├── html_tag.h ├── iterators.h ├── line_box.h ├── litehtml.h ├── litehtmlpy.cpp ├── litehtmlpy │ ├── __init__.py │ ├── litehtml.py │ ├── litehtmlpango.py │ └── litehtmlwx.py ├── master_css.h ├── media_query.h ├── num_cvt.h ├── os_types.h ├── render_block.h ├── render_block_context.h ├── render_flex.h ├── render_image.h ├── render_inline.h ├── render_inline_context.h ├── render_item.h ├── render_table.h ├── string_id.h ├── style.h ├── stylesheet.h ├── table.h ├── tstring_view.h ├── types.h └── web_color.h ├── test-01.html ├── test-02.html ├── weasy.py ├── x-build-cmake ├── x-build-cmake-mingw ├── x-build-docker ├── x-build-python ├── x-cleanup ├── x-debug-gdb ├── x-debug-valgrind ├── x-submodule ├── x-submodule-pull └── y-bug-height.html /.github/workflows/wheels.yml: -------------------------------------------------------------------------------- 1 | name: Wheels 2 | 3 | on: 4 | workflow_dispatch: 5 | # allow manual runs on branches without a PR 6 | 7 | jobs: 8 | build_ubuntu_wheels: 9 | name: Build wheels on Ubuntu 10 | runs-on: ubuntu-22.04 11 | 12 | timeout-minutes: 180 13 | 14 | steps: 15 | - name: Checkout sources 16 | uses: actions/checkout@v4 17 | with: 18 | submodules: true 19 | 20 | - name: Build wheels 21 | uses: pypa/cibuildwheel@v2.16 22 | env: 23 | CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 24 | CIBW_ARCHS_LINUX: x86_64 25 | CIBW_BUILD: "cp311*-manylinux_x86_64*" 26 | 27 | - name: Upload wheels 28 | uses: actions/upload-artifact@v4.3.0 29 | with: 30 | name: wheels_ubuntu__${{ github.sha }} 31 | path: wheelhouse/*.whl 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | todo/ 2 | 3 | _deps/ 4 | bin/ 5 | CMakeFiles/ 6 | lib/ 7 | 8 | cmake_install.cmake 9 | CMakeCache.txt 10 | Makefile 11 | litehtmlpy/litehtmlpy.*.so 12 | src/litehtmlpy/litehtmlpy.*.so 13 | src/litehtmlpy/litehtmlpy.pyd 14 | .ninja_deps 15 | .ninja_log 16 | build.ninja 17 | litehtmlpy.egg-info/ 18 | 19 | build/ 20 | dist/ 21 | wheelhouse/ 22 | __pycache__/ 23 | demo-pit11/xml/ 24 | 25 | demo.png 26 | demo-*.html 27 | demo-*.png 28 | 29 | litehtmlpy.cpp 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "pybind11"] 2 | path = pybind11 3 | url = https://github.com/pybind/pybind11 4 | branch = v2.13 5 | [submodule "litehtml"] 6 | path = litehtml 7 | url = https://github.com/m32/litehtml 8 | branch = master 9 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "${workspaceRoot}", 7 | "${workspaceRoot}/litehtml/include", 8 | "/usr/include", 9 | "." 10 | ], 11 | "defines": [ 12 | "_FILE_OFFSET_BITS=64", 13 | ], 14 | "browse": { 15 | "limitSymbolsToIncludedHeaders": true, 16 | "databaseFilename": "", 17 | "path": [ 18 | "/usr/include" 19 | ] 20 | }, 21 | "intelliSenseMode": "clang-x64", 22 | "compilerPath": "/usr/bin/clang", 23 | "cStandard": "c11", 24 | "cppStandard": "c++17", 25 | "configurationProvider": "ms-vscode.cmake-tools" 26 | } 27 | ], 28 | "version": 4 29 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "gdb", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "program": "/devel/bin/python3/bin/python", 9 | "stopAtEntry": true, 10 | "cwd": "${workspaceFolder}", 11 | "args": ["litehtml-pango-png.py"], 12 | "environment": [], 13 | "externalConsole": false, 14 | "MIMode": "gdb", 15 | "setupCommands": [ 16 | { 17 | "description": "Enable pretty-printing for gdb", 18 | "text": "-enable-pretty-printing", 19 | "ignoreFailures": true 20 | } 21 | ] 22 | }, 23 | { 24 | "name": "Python: Remote Attach", 25 | "type": "python", 26 | "request": "attach", 27 | "port": 10001, 28 | "host": "localhost", 29 | "pathMappings": [ 30 | { 31 | "localRoot": "${workspaceFolder}", 32 | "remoteRoot": "/app" 33 | } 34 | ] 35 | }, 36 | { 37 | "name": "Python: Current File", 38 | "type": "python", 39 | "request": "launch", 40 | "justMyCode": false, 41 | "cwd": "${workspaceFolder}", 42 | "program": "${file}" 43 | }, 44 | { 45 | "name": "Python C++ Debug", 46 | "type": "pythoncpp", 47 | "request": "launch", 48 | "pythonConfig": "default", 49 | "cppConfig": "default (gdb) Attach", 50 | } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": {} 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | "version": "2.0.0", 5 | "tasks": [ 6 | { 7 | "label": "cmake", 8 | "type": "shell", 9 | "command": "cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DLITEHTML_BUILD_TESTING=OFF -DLITEHTMLPY_BUILD_TESTING=ON -DLITEHTMLPY_INCLUDE_CAIRO_CONTAINERS=ON -Wno-dev ." 10 | }, 11 | { 12 | "label": "make", 13 | "type": "shell", 14 | "command": "make", 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | }, 19 | "problemMatcher": [ 20 | "$gcc" 21 | ] 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # cmake -DCMAKE_BUILD_TYPE=Debug . 3 | # cmake -DCMAKE_BUILD_TYPE=Release . 4 | # 5 | cmake_minimum_required(VERSION 3.4...3.18) 6 | project(litehtmlpy) 7 | 8 | # https://stackoverflow.com/questions/38296756/what-is-the-idiomatic-way-in-cmake-to-add-the-fpic-compiler-option 9 | set(CMAKE_POSITION_INDEPENDENT_CODE ON) 10 | 11 | option(LITEHTMLPY_BUILD_TESTING "enable testing for litehtmlpy" OFF) 12 | # option(LITEHTMLPY_INCLUDE_CAIRO_CONTAINERS "include cairo containers" OFF) 13 | 14 | #find_package(Git) 15 | # 16 | #if(NOT EXISTS ${CMAKE_SOURCE_DIR}/litehtml) 17 | # execute_process(COMMAND "${GIT_EXECUTABLE}" clone --depth 1 https://github.com/m32/litehtml -b master 18 | # WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") 19 | #endif() 20 | #if(NOT EXISTS ${CMAKE_SOURCE_DIR}/pybind11) 21 | # if(CMAKE_CROSSCOMPILING) 22 | # execute_process(COMMAND "${GIT_EXECUTABLE}" clone --depth 1 https://github.com/pybind/pybind11.git -b v2.9 23 | # WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") 24 | # else() 25 | # execute_process(COMMAND "${GIT_EXECUTABLE}" clone --depth 1 https://github.com/pybind/pybind11.git -b v2.11 26 | # WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") 27 | # endif() 28 | #endif() 29 | 30 | add_subdirectory(litehtml) 31 | 32 | if(CMAKE_CROSSCOMPILING) 33 | # Tell pybind11 where the target python installation is 34 | set(PYTHON_INCLUDE_DIR ${MY_TARGET_PYTHON_INCLUDE_DIRS} CACHE INTERNAL "Cross python include path") 35 | set(PYTHON_INCLUDE_DIRS ${MY_TARGET_PYTHON_INCLUDE_DIRS} CACHE INTERNAL "Cross python include path") 36 | set(PYTHON_MODULE_EXTENSION ".pyd" CACHE INTERNAL "Cross python lib extension") 37 | 38 | # Disable pybind11 python search mechanism 39 | set(PYTHONLIBS_FOUND TRUE CACHE INTERNAL "") 40 | 41 | target_compile_definitions(litehtml PRIVATE 42 | -DLITEHTML_NO_THREADS 43 | ) 44 | endif() 45 | 46 | add_subdirectory(pybind11) 47 | 48 | if(DEFINED LITEHTMLPY_INCLUDE_CAIRO_CONTAINERS AND LITEHTMLPY_INCLUDE_CAIRO_CONTAINERS) 49 | set(TEST_LITEHTMLPY_CONTAINERS 50 | src/cairo/cairo_borders.cpp 51 | src/cairo/container_cairo.cpp 52 | src/cairo/container_cairo_pango.cpp 53 | ) 54 | else() 55 | set(TEST_LITEHTMLPY_CONTAINERS 56 | ) 57 | endif() 58 | 59 | 60 | pybind11_add_module( 61 | litehtmlpy 62 | src/litehtmlpy.cpp 63 | ${TEST_LITEHTMLPY_CONTAINERS} 64 | ) 65 | 66 | set_target_properties(litehtmlpy PROPERTIES 67 | LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/src/litehtmlpy") 68 | 69 | #if(NOT CMAKE_CROSSCOMPILING) 70 | # find_package(PythonLibs 3.6) 71 | # #find_package(PythonLibs 3.8 REQUIRED) 72 | # #find_package(PythonLibs 3.11.2 EXACT REQUIRED) 73 | #endif() 74 | 75 | set_target_properties(litehtmlpy PROPERTIES 76 | CXX_STANDARD 17 77 | C_STANDARD 99 78 | ) 79 | 80 | target_compile_definitions(litehtmlpy PRIVATE 81 | #-DUNICODE 82 | ) 83 | 84 | target_include_directories(litehtmlpy PRIVATE 85 | # ${PYTHON_INCLUDE_DIRS} 86 | litehtml/include 87 | # ${PYBIND11_INCLUDE_DIR} 88 | ) 89 | 90 | target_link_libraries(litehtmlpy PRIVATE 91 | litehtml 92 | gumbo 93 | # ${PYTHON_LIBRARIES} 94 | ) 95 | 96 | if(DEFINED LITEHTMLPY_INCLUDE_CAIRO_CONTAINERS AND LITEHTMLPY_INCLUDE_CAIRO_CONTAINERS) 97 | find_package(PkgConfig REQUIRED) 98 | pkg_check_modules(CAIRO REQUIRED IMPORTED_TARGET "cairo") 99 | target_link_libraries(litehtmlpy PRIVATE PkgConfig::CAIRO) 100 | pkg_check_modules(PANGO REQUIRED IMPORTED_TARGET "pango") 101 | target_link_libraries(litehtmlpy PRIVATE PkgConfig::PANGO) 102 | pkg_check_modules(PANGOCAIRO REQUIRED IMPORTED_TARGET "pangocairo") 103 | target_link_libraries(litehtmlpy PRIVATE PkgConfig::PANGOCAIRO) 104 | target_compile_definitions(litehtmlpy PRIVATE 105 | -DUSE_CAIRO_CONTAINERS 106 | ) 107 | endif() 108 | 109 | if(CMAKE_CROSSCOMPILING) 110 | target_compile_definitions(litehtmlpy PRIVATE 111 | -DMS_WIN64 112 | ) 113 | target_compile_options(litehtmlpy PRIVATE 114 | -Wa,-mbig-obj 115 | ) 116 | target_link_options(litehtmlpy PRIVATE 117 | -static 118 | -static-libgcc 119 | -static-libstdc++ 120 | ) 121 | endif() 122 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Grzegorz Makarewicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python-litehtml 2 | LiteHtmlPy is a solution that helps python developers to create printouts and previews of html5/css3 pages without using a web browser. 3 | 4 | ## Links 5 | * [litehtml library](https://github.com/litehtml/litehtml) 6 | * [pybind11](https://github.com/pybind/pybind11) 7 | 8 | ## Cleanup repository 9 | ./x-cleanup 10 | 11 | ## Linux configure 12 | - ./x-build-cmake -DCMAKE_BUILD_TYPE=Debug 13 | - ./x-build-cmake -DCMAKE_BUILD_TYPE=Release 14 | 15 | ## Cross Mingw configure for python 2.7 16 | - ./x-build-cmake-mingw 17 | 18 | ## Build for manylinux inside docker 19 | - ./x-build-docker 20 | 21 | ## Just setup.py build 22 | - ./x-build-python 23 | -------------------------------------------------------------------------------- /build-wheels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -u -x 3 | cd /io 4 | 5 | #[ -n "$WHEELHOUSE" ] || 6 | WHEELHOUSE=wheelhouse 7 | #[ -z "$PYTHON_BUILD_VERSION" ] && 8 | PYTHON_BUILD_VERSION="cp311-cp311" 9 | 10 | function repair_wheel { 11 | wheel="$1" 12 | if ! auditwheel show "$wheel"; then 13 | echo "Skipping non-platform wheel $wheel" 14 | else 15 | auditwheel repair "$wheel" -w /io/wheelhouse/ 16 | fi 17 | } 18 | 19 | 20 | # Install a system package required by our library 21 | # yum install -y pybind11 22 | 23 | # Compile wheels 24 | for PYBIN in /opt/python/${PYTHON_BUILD_VERSION}/bin; do 25 | #"${PYBIN}/pip" install -r /io/dev-requirements.txt 26 | "${PYBIN}/pip" wheel /io/ --no-deps -w /io/${WHEELHOUSE} || exit 1 27 | done 28 | 29 | # Bundle external shared libraries into the wheels 30 | for whl in wheelhouse/*.whl; do 31 | repair_wheel "$whl" 32 | done 33 | 34 | # Install packages and test 35 | for PYBIN in /opt/python/${PYTHON_BUILD_VERSION}/bin; do 36 | "${PYBIN}/pip" install litehtmlpy --no-index -f /io/${WHEELHOUSE} 37 | "${PYBIN}/python" litehtmld.py 38 | done 39 | -------------------------------------------------------------------------------- /demo-pit11/make-demo-html: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ./pit11.py --xml=pit11.xml --xsl=pit11.xsl --html=../demo.html 3 | -------------------------------------------------------------------------------- /demo-pit11/pit11.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | # -*- coding: utf-8 -*- 3 | import os 4 | import sys 5 | import getopt 6 | import urllib.request 7 | import base64 8 | import zipfile 9 | import io 10 | from lxml import etree 11 | 12 | top = os.getcwd() 13 | 14 | def download(url): 15 | # http://crd.gov.pl/wzor/2014/12/22/1949/schemat.xsd 16 | if url[:7] == 'http://': 17 | fname = url.split('/') 18 | assert fname[2] in ('crd.gov.pl', 'jpk.mf.gov.pl') 19 | fname = '/'.join(fname[3:]) 20 | filepath = '/'.join((top, fname)) 21 | else: 22 | filepath = url 23 | # print('download', url, filepath) 24 | if not os.path.isfile(filepath): 25 | dirname = '/'.join(filepath.split('/')[:-1]) 26 | if not os.path.exists(dirname): 27 | os.makedirs(dirname) 28 | print("Resolving URL '%s'" % url) 29 | response = urllib.request.urlopen(url) 30 | data = response.read() 31 | open(filepath, 'wb').write(data) 32 | return filepath 33 | 34 | class DTDResolver(etree.Resolver): 35 | def resolve(self, url, id, context): 36 | filepath = download(url) 37 | return self.resolve_filename(filepath, context) 38 | 39 | class Parser: 40 | namespaces={ 41 | # 'dsig' :"http://www.w3.org/2000/09/xmldsig#", 42 | # 'xsd' :"http://www.w3.org/2001/XMLSchema", 43 | # 'soap' :"http://www.w3.org/2003/05/soap-envelope", 44 | } 45 | 46 | def __init__(self, xml): 47 | self.xml = xml 48 | self.tree = etree.parse(io.BytesIO(xml)) 49 | self.namespaces.update(self.tree.getroot().nsmap) 50 | 51 | class Deklaracja: 52 | def __init__(self, xml): 53 | self.xml = xml 54 | self.xsd = None 55 | self.xsl = None 56 | self.url = None 57 | 58 | self.xsdformularz = None 59 | self.xsdwariant = None 60 | self.xsdwersja = None 61 | self.firmanip = None 62 | self.firmanazwa = None 63 | 64 | self.prepare() 65 | 66 | def prepare(self): 67 | self.tree = etree.parse(io.BytesIO(self.xml)) 68 | self.root = self.tree.getroot() 69 | self.nsmap = self.root.nsmap.copy() 70 | try: 71 | self.url = self.root.nsmap[None] 72 | self.nsmap['doc'] = self.nsmap[None] 73 | del self.nsmap[None] 74 | except: 75 | pass 76 | 77 | def getxsd(self): 78 | if self.xsd: 79 | return self.xsd 80 | return download(self.url+'schemat.xsd') 81 | 82 | def getxsl(self): 83 | if self.xsl: 84 | return self.xsl 85 | return download(self.url+'styl.xsl') 86 | 87 | def validate(self): 88 | fxsd = self.getxsd() 89 | print('fxsd=', fxsd) 90 | xsdparser = etree.XMLParser(load_dtd=True) 91 | xsdparser.resolvers.add( DTDResolver() ) 92 | 93 | schema_root = etree.XML(open(fxsd, 'rb').read(), xsdparser) 94 | schema = etree.XMLSchema(schema_root) 95 | 96 | xmlparser = etree.XMLParser(schema = schema) 97 | etree.clear_error_log() 98 | try: 99 | oot = etree.parse(io.BytesIO(self.xml), xmlparser) 100 | except etree.XMLSyntaxError as e: 101 | return e 102 | return None 103 | 104 | def showerror(self, e): 105 | for ee in e.error_log: 106 | print(ee.line, ee.column, ee.message) 107 | 108 | def html(self): 109 | fxsl = self.getxsl() 110 | 111 | xsdparser = etree.XMLParser(load_dtd=True) 112 | xsdparser.resolvers.add( DTDResolver() ) 113 | 114 | xslt_root = etree.XML(open(fxsl, 'rb').read(), xsdparser) 115 | transform = etree.XSLT(xslt_root) 116 | 117 | result = transform(self.tree) 118 | result = etree.tostring(result) 119 | return result 120 | 121 | def info(self): 122 | self.info_naglowek() 123 | self.info_osoba() 124 | 125 | def info_naglowek(self): 126 | naglowek = '/doc:Deklaracja/doc:Naglowek' 127 | formularz = self.tree.xpath( naglowek+'/doc:KodFormularza', namespaces=self.nsmap )[0] 128 | wariant = self.tree.xpath( naglowek+'/doc:WariantFormularza', namespaces=self.nsmap )[0].text 129 | 130 | self.xsdformularz = formularz.text 131 | self.xsdwariant = wariant 132 | self.xsdwersja = formularz.get('wersjaSchemy') 133 | 134 | def info_osoba(self): 135 | path = '/doc:Deklaracja/doc:Podmiot1/etd:OsobaFizyczna' 136 | podmiot = self.tree.xpath( path, namespaces=self.nsmap ) 137 | if podmiot: 138 | self.firmanip = self.tree.xpath( path+'/etd:NIP', namespaces=self.nsmap )[0].text 139 | imie = self.tree.xpath( path+'/etd:ImiePierwsze', namespaces=self.nsmap )[0].text 140 | nazwisko = self.tree.xpath( path+'/etd:Nazwisko', namespaces=self.nsmap )[0].text 141 | self.firmanazwa = imie+' '+nazwisko 142 | else: 143 | path = '/doc:Deklaracja/doc:Podmiot1/etd:OsobaNiefizyczna' 144 | podmiot = self.tree.xpath( path, namespaces=self.nsmap ) 145 | self.firmanip = self.tree.xpath( path+'/etd:NIP', namespaces=self.nsmap )[0].text 146 | self.firmanazwa = self.tree.xpath( path+'/etd:PelnaNazwa', namespaces=self.nsmap )[0].text 147 | 148 | class XADESParser(Parser): 149 | def __init__(self, xml): 150 | Parser.__init__(self, xml) 151 | self.dokument = None 152 | 153 | ns = [ 154 | '/ds:Signature', 155 | '/ds:SignedInfo', 156 | '/ds:Reference', 157 | ] 158 | path = ''.join(ns) 159 | odpowiedz = self.tree.xpath( path, namespaces=self.namespaces ) 160 | odpowiedz = odpowiedz[0] 161 | ref = odpowiedz.get('URI')[1:] 162 | ns = [ 163 | '/ds:Signature', 164 | '/ds:Object', 165 | ] 166 | path = ''.join(ns) 167 | print(ref) 168 | for odpowiedz in self.tree.xpath( path, namespaces=self.namespaces ): 169 | print(odpowiedz.get('Id')) 170 | if ref == odpowiedz.get('Id'): 171 | print(dir(odpowiedz)) 172 | dokument = odpowiedz.text 173 | print('dokument', dokument) 174 | dokument = base64.decodestring(dokument) 175 | fp = io.BytesIO(dokument) 176 | zfp = zipfile.ZipFile(fp, 'r', zipfile.ZIP_DEFLATED) 177 | self.dokument = zfp.read(zfp.namelist()[0]) 178 | return 179 | 180 | def main(): 181 | opts, args = getopt.getopt(sys.argv[1:], '?', [ 182 | 'help', 183 | 'validate', 184 | 'xml=', 185 | 'xsd=', 186 | 'html=', 187 | 'xsl=', 188 | 'xades=', 189 | ]) 190 | if args or '-?' in opts or '--help' in opts: 191 | print('''\ 192 | usage: %s opcje 193 | 194 | opcje: 195 | --help = pokaz ten tekst 196 | -? = pokaz ten tekst 197 | --validate = sprawdz poprawnosc pliku (--xml|--xades) 198 | --xsd= = nazwa pliku xsd 199 | --html=plik = gdzie zapisac plik html 200 | --xsl= = nazwa pliku xsl 201 | --xades=plik = wczytaj plik xml z podpisanego pliku (xades) 202 | --xml=plik = wczytaj plik xml 203 | ''' % sys.argv[0]) 204 | return 205 | dek = None 206 | for o, a in opts: 207 | if o == '--xml': 208 | xml=open(a, 'rb').read() 209 | dekok = Deklaracja(xml) 210 | elif o == '--xsd': 211 | dekok.xsd = a 212 | elif o == '--xsl': 213 | dekok.xsl = a 214 | elif o == '--xades': 215 | xml = open(a, 'rb').read() 216 | p = XADESParser(xml) 217 | dekok = Deklaracja(p.dokument) 218 | elif o == '--validate': 219 | print('*'*20, 'validate') 220 | e = dekok.validate() 221 | if e: 222 | dekok.showerror(e) 223 | else: 224 | print('OK') 225 | elif o == '--html': 226 | print('*'*20, 'html') 227 | lines = io.BytesIO(dekok.html()).readlines() 228 | html = [] 229 | for line in lines: 230 | line = line.strip() 231 | if len(line) > 0: 232 | html.append(line) 233 | html = b'\n'.join(html) 234 | open(a, 'wb').write(html) 235 | print('OK') 236 | 237 | main() 238 | -------------------------------------------------------------------------------- /demo-pit11/pit11.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | PIT-11 9 | 29 10 | 1 11 | 2023 12 | 2205 13 | 14 | 15 | 16 | 1234567890 17 | Firma Sp. z o.o. 18 | 19 | 20 | 21 | 22 | 12345678901 23 | Imię 24 | Nazwisko 25 | 1234-56-78 26 | 27 | 28 | PL 29 | Województwo 30 | Powiat 31 | Gmina 32 | Ulica 33 | 1 34 | Miejscowość 35 | 12-345 36 | 37 | 38 | 39 | 1 40 | 1 41 | 249525.40 42 | 3000.00 43 | 246525.40 44 | 0.00 45 | 41878 46 | 0.00 47 | 0.00 48 | 0.00 49 | 0.00 50 | 0.00 51 | 0.00 52 | 0 53 | 0.00 54 | 0.00 55 | 0.00 56 | 0.00 57 | 0.00 58 | 0.00 59 | 0 60 | 0.00 61 | 0.00 62 | 0.00 63 | 0.00 64 | 0.00 65 | 0 66 | 0.00 67 | 0.00 68 | 0.00 69 | 0 70 | 0.00 71 | 0.00 72 | 0.00 73 | 0 74 | 0.00 75 | 0.00 76 | 0.00 77 | 0 78 | 0.00 79 | 0.00 80 | 0.00 81 | 0 82 | 0.00 83 | 0.00 84 | 0 85 | 0.00 86 | 0.00 87 | 0.00 88 | 0.00 89 | 0 90 | 0.00 91 | 0.00 92 | 0 93 | 0.00 94 | 0.00 95 | 0 96 | 0.00 97 | 0.00 98 | 0 99 | 0.00 100 | 0.00 101 | 0 102 | 0.00 103 | 0.00 104 | 0.00 105 | 0.00 106 | 0 107 | 29403.26 108 | 0.00 109 | 0.00 110 | 0.00 111 | 0.00 112 | 0.00 113 | 0.00 114 | 0.00 115 | 0.00 116 | 0.00 117 | 0.00 118 | 0.00 119 | 0.00 120 | 0.00 121 | 0.00 122 | 2 123 | 19309.38 124 | 0.00 125 | 126 | 1 127 | 128 | -------------------------------------------------------------------------------- /litehtml-dumper.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import sys 3 | import logging 4 | 5 | import logme 6 | from litehtmlpy import litehtml, litehtmlpy 7 | 8 | litehtmlpy.debuglog(0) 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | class document_container(litehtml.document_container): 13 | pass 14 | 15 | class dumper(litehtmlpy.dumper): 16 | def __init__(self): 17 | super().__init__() 18 | self.indent = 0 19 | 20 | def printi(self, *args): 21 | s = ' '*self.indent if self.indent else '' 22 | print(s, *args) 23 | 24 | def begin_node(self, descr): 25 | self.printi('begin_node', descr) 26 | self.indent += 1 27 | 28 | def end_node(self): 29 | self.indent -= 1 30 | self.printi('end_node') 31 | 32 | def begin_attrs_group(self, descr): 33 | self.printi('begin_attrs_group', descr) 34 | self.indent += 1 35 | 36 | def end_attrs_group(self): 37 | self.indent -= 1 38 | self.printi('end_attrs_group') 39 | 40 | def add_attr(self, name, value): 41 | self.printi('add_attr', name, value) 42 | 43 | class Main: 44 | def demo(self): 45 | if len(sys.argv) > 1: 46 | fname = sys.argv[1] 47 | else: 48 | fname = 'demo.html' 49 | fname = 'litehtmlt.html' 50 | html = open(fname, 'rt').read() 51 | 52 | cntr = document_container() 53 | print('max size=', cntr.size) 54 | 55 | doc = litehtmlpy.fromString(cntr, html, None, None) 56 | doc.render(cntr.size[0], litehtmlpy.render_all) 57 | print('doc: width:', doc.width(), 'height:', doc.height()) 58 | 59 | dump = dumper() 60 | doc.dump(dump) 61 | 62 | del doc 63 | del cntr 64 | 65 | def main(): 66 | app = Main() 67 | app.demo() 68 | 69 | main() 70 | -------------------------------------------------------------------------------- /litehtml-pango-png.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import gc 3 | import sys 4 | import os 5 | import io 6 | import logging 7 | import requests 8 | import urllib.parse 9 | from PIL import Image 10 | import logme 11 | from litehtmlpy import litehtmlpango, litehtmlpy 12 | 13 | litehtmlpy.debuglog(1) 14 | 15 | logger = logging.getLogger(__name__) 16 | 17 | class document_container(litehtmlpango.document_container): 18 | def import_css(self, text, url, base_url): 19 | url = urllib.parse.urljoin(base_url, url) 20 | if os.path.exists(url): 21 | with open(url, 'rt') as fp: 22 | data = fp.read() 23 | elif url.split(':')[0] in ('http', 'https'): 24 | r = requests.get(url) 25 | if r.headers['Content-Type'] == 'text/css': 26 | data = r.text 27 | if data is None: 28 | print('unknown import_css', url) 29 | return 30 | return data 31 | 32 | class App: 33 | images = {} 34 | url = '' 35 | def GetUrlData(self, url, html=True): 36 | data = None 37 | if os.path.exists(url): 38 | with open(url, 'rb') as fp: 39 | data = fp.read() 40 | elif url.split(':')[0] in ('http', 'https'): 41 | r = requests.get(url) 42 | print(r.headers) 43 | if html: 44 | if r.headers['Content-Type'] == 'text/html': 45 | data = r.text 46 | else: 47 | if r.headers['Content-Type'] == 'image/png': 48 | data = r.content 49 | if data is None: 50 | return None 51 | return data 52 | 53 | def HtmlLoadImage(self, cntr, src, baseurl, redraw_on_ready): 54 | if baseurl is not None: 55 | url = urllib.parse.urljoin(baseurl, src) 56 | else: 57 | url = urllib.parse.urljoin(self.url, src) 58 | data = self.GetUrlData(url, False) 59 | print('HtmlLoadImage({}, {})'.format(url, data is not None)) 60 | if data is None: 61 | return 62 | try: 63 | im = Image.open(io.BytesIO(data)) 64 | except: 65 | print('bang') 66 | return 67 | if 'A' not in im.getbands(): 68 | alpha = 1.0 69 | im.putalpha(int(alpha * 256.)) 70 | try: 71 | arr = bytearray(im.tobytes('raw', 'BGRa')) 72 | except ValueError: 73 | return 74 | cntr.put_image(url, arr, im.width, im.height) 75 | 76 | 77 | class Main: 78 | def demo(self): 79 | app = App() 80 | if len(sys.argv) > 1: 81 | fname = sys.argv[1] 82 | else: 83 | fname = 'demo.html' 84 | fname = 'litehtmlt.html' 85 | html = open(fname, 'rt').read() 86 | 87 | cntr = document_container(app) 88 | print('max size=', cntr.size) 89 | 90 | doc = cntr.fromString(html, None, None) 91 | doc.render(cntr.size[0], litehtmlpy.render_all) 92 | print('doc: width:', doc.width(), 'height:', doc.height()) 93 | 94 | cntr.size[1] = doc.height() 95 | hdc = cntr.surface(doc.width(), doc.height()) 96 | 97 | print('*'*10, 'draw') 98 | clip = litehtmlpy.position(0, 0, doc.width(), doc.height()) 99 | doc.draw(hdc, 0, 0, clip) 100 | 101 | print('x-save') 102 | cntr.save('demo.png') 103 | 104 | print('x-save-stream') 105 | with open('demo-1.png', 'wb') as fpo: 106 | rc = cntr.savestream(fpo.write) 107 | print('save result:', rc) 108 | 109 | del doc 110 | cntr.clear_images() 111 | del cntr 112 | 113 | def main(): 114 | app = Main() 115 | app.demo() 116 | 117 | main() 118 | gc.collect() 119 | -------------------------------------------------------------------------------- /litehtml-t-web_color.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import sys 3 | import logme 4 | from litehtmlpy import litehtml, litehtmlpy 5 | 6 | #litehtmlpy.debuglog(1) 7 | 8 | class document_container(litehtml.document_container): 9 | pass 10 | 11 | class Main: 12 | def main(self): 13 | if len(sys.argv) > 1: 14 | fname = sys.argv[1] 15 | else: 16 | fname = 'demo.html' 17 | fname = 'litehtmlt.html' 18 | html = open(fname, 'rt').read() 19 | 20 | cntr = document_container() 21 | try: 22 | self.demo(cntr) 23 | finally: 24 | del cntr 25 | 26 | def demo(self, cntr): 27 | wc00 = litehtmlpy.web_color() 28 | print(wc00) 29 | wcff = litehtmlpy.web_color(0xff, 0xff, 0xff) 30 | print(wcff) 31 | print(wc00==wcff) 32 | print(wc00!=wcff) 33 | print('black', litehtmlpy.web_color.black) 34 | print('white', litehtmlpy.web_color.white) 35 | print('transparent', litehtmlpy.web_color.transparent) 36 | print('current', litehtmlpy.web_color.current_color) 37 | wcffd = wcff.darken(0.5) 38 | print(wcffd) 39 | 40 | def main(): 41 | app = Main() 42 | app.main() 43 | 44 | main() 45 | -------------------------------------------------------------------------------- /litehtml-wx-png-paged.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import logme 3 | import wx 4 | from litehtmlpy import litehtmlwx, litehtmlpy 5 | 6 | class document_container(litehtmlwx.document_container): 7 | pass 8 | 9 | class Main: 10 | def __init__(self): 11 | self.wxapp = wx.App(False) 12 | 13 | def save(self, i, htmlstart, htmldata, htmlend): 14 | html = htmlstart+htmldata+htmlend 15 | if 0: 16 | fp = open('demo-{i:04d}.html'.format(i=i), 'wt') 17 | fp.write(html) 18 | fp.close() 19 | 20 | cntr = document_container() 21 | cntr.reset() 22 | 23 | doc = litehtmlpy.fromString(cntr, html, None, None) 24 | doc.render(cntr.size[0], litehtmlpy.render_all) 25 | 26 | cntr.size[1] = doc.height() 27 | cntr.reset() 28 | clip = litehtmlpy.position(0, 0, doc.width(), doc.height()) 29 | doc.draw(0, 0, 0, clip) 30 | 31 | cntr.bmp.SaveFile('demo-{i:04d}.png'.format(i=i), wx.BITMAP_TYPE_PNG) 32 | 33 | del doc 34 | del cntr 35 | 36 | def main(self): 37 | if len(sys.argv) > 1: 38 | fname = sys.argv[1] 39 | else: 40 | fname = 'demo.html' 41 | html = open(fname, 'rt').read() 42 | split='' 43 | start = html.find(split) + len(split) 44 | start = html.find('>', start) + 1 45 | i = end = start 46 | while True: 47 | i = html.find('', i+1) 48 | if i == -1: 49 | break 50 | end = i 51 | htmlstart = html[0:start] 52 | htmldata = html[start:end] 53 | htmlend = html[end:] 54 | i = 0 55 | split = '
' 56 | while True: 57 | istop = htmldata.find(split) 58 | if istop == -1: 59 | self.save(i, htmlstart, htmldata, htmlend) 60 | break 61 | self.save(i, htmlstart, htmldata[:istop], htmlend) 62 | htmldata = htmldata[istop+len(split):] 63 | i += 1 64 | 65 | def main(): 66 | cls = Main() 67 | cls.main() 68 | main() 69 | -------------------------------------------------------------------------------- /litehtml-wx-png.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import sys 3 | import wx 4 | 5 | import logme 6 | from litehtmlpy import litehtmlwx, litehtmlpy 7 | 8 | class document_container(litehtmlwx.document_container): 9 | def pt_to_px(self, pt): 10 | return pt 11 | 12 | class Main: 13 | def __init__(self): 14 | self.wxapp = wx.App(False) 15 | 16 | def save(self, i, htmlstart, htmlend, htmldata): 17 | html = htmlstart+htmldata+htmlend 18 | 19 | dc = wx.MemoryDC() 20 | 21 | cntr = document_container() 22 | cntr.SetDC(dc) 23 | doc = litehtmlpy.fromString(cntr, html, None, None) 24 | doc.render(cntr.size[0], litehtmlpy.render_all) 25 | 26 | cntr.size[1] = doc.height() 27 | 28 | bmp = wx.Bitmap(cntr.size[0], cntr.size[1], 32) 29 | dc.SelectObject(bmp) 30 | dc.SetBackground(wx.Brush(wx.WHITE)) 31 | dc.Clear() 32 | 33 | clip = litehtmlpy.position(0, 0, doc.width(), doc.height()) 34 | doc.draw(0, 0, 0, clip) 35 | 36 | bmp.SaveFile('demo-{i:04d}.png'.format(i=i), wx.BITMAP_TYPE_PNG) 37 | 38 | cntr.SetDC(None) 39 | del doc 40 | del cntr 41 | 42 | def main(self): 43 | if len(sys.argv) > 1: 44 | fname = sys.argv[1] 45 | else: 46 | fname = 'demo.html' 47 | html = open(fname, 'rt').read() 48 | split='' 49 | start = html.find(split) + len(split) 50 | end = html.find('') 51 | htmlstart = html[0:start] 52 | htmlend = html[end:] 53 | html = html[start:end] 54 | htmlpages = [] 55 | split = '
' 56 | start = 0 57 | while True: 58 | stop = html.find(split, start) 59 | if stop == -1: 60 | htmlpages.append((start, len(html))) 61 | break 62 | htmlpages.append((start, stop)) 63 | start = stop+len(split) 64 | for i in range(len(htmlpages)): 65 | print(i, htmlpages[i][0], htmlpages[i][1]) 66 | self.save(i, htmlstart, htmlend, html[htmlpages[i][0]:htmlpages[i][1]]) 67 | def main(): 68 | cls = Main() 69 | cls.main() 70 | main() 71 | -------------------------------------------------------------------------------- /litehtml-wx-print.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import sys 3 | import wx 4 | 5 | import logme 6 | from litehtmlpy import litehtmlwx, litehtmlpy 7 | 8 | class document_container(litehtmlwx.document_container): 9 | def pt_to_px(self, pt): 10 | return pt 11 | 12 | class HTMLPrinterPrintout(wx.Printout): 13 | def __init__(self, htmlstart, htmlend, html, htmlpages): 14 | wx.Printout.__init__(self) 15 | self.npages = len(htmlpages) 16 | self.htmlstart = htmlstart 17 | self.htmlend = htmlend 18 | self.html = html 19 | self.htmlpages = htmlpages 20 | self.pageinfo = (1, self.npages, 1, self.npages) 21 | 22 | def OnBeginDocument(self, start, end): 23 | return self.GetDC().StartDoc('DEMO') 24 | 25 | def HasPage(self, page): 26 | return page <= self.npages 27 | 28 | def GetPageInfo(self): 29 | return self.pageinfo 30 | 31 | def OnPreparePrinting(self): 32 | pass 33 | 34 | def OnPrintPage(self, page): 35 | dc = self.GetDC() 36 | self.MakePage(dc, page) 37 | return True 38 | 39 | def MakePage(self, dc, page): 40 | page -= 1 41 | print('page:', page, self.htmlpages[page]) 42 | dc.Clear() 43 | dc.SetMapMode(wx.MM_TEXT) 44 | dc.SetBackground(wx.Brush(wx.WHITE)) 45 | 46 | (w, h) = dc.GetSize() 47 | print('DC:', 'w=', w, 'h=', h, 'ppi=', dc.GetPPI()) 48 | 49 | html = self.html[self.htmlpages[page][0]:self.htmlpages[page][1]] 50 | html = self.htmlstart + html + self.htmlend 51 | 52 | cntr = document_container() 53 | cntr.SetDC(dc) 54 | doc = litehtmlpy.fromString(cntr, html, None, None) 55 | try: 56 | doc.render(cntr.size[0], litehtmlpy.render_all) 57 | cntr.size[1] = doc.height() 58 | 59 | if 1: 60 | print('DOC:', 'w=', doc.width(), 'h=', doc.height()) 61 | maxX = doc.width() + (2*50) # marginesy 50 device units 62 | maxY = doc.height() + (2*50) # marginesy 50 device units 63 | (w, h) = dc.GetSize() 64 | scaleX = float(w) / maxX 65 | scaleY = float(h) / maxY 66 | actualScale = min(scaleX, scaleY) 67 | print('SCALE:', 'x=', scaleX, 'y=', scaleY, 'act=', actualScale) 68 | dc.SetUserScale(actualScale, actualScale) 69 | #dc.SetDeviceOrigin(int(posX), int(posY)) 70 | 71 | #bmp = wx.Bitmap(cntr.size[0], cntr.size[1], 32) 72 | clip = litehtmlpy.position(0, 0, doc.width(), doc.height()) 73 | doc.draw(0, 0, 0, clip) 74 | finally: 75 | cntr.SetDC(None) 76 | del doc 77 | del cntr 78 | 79 | class HTMLPrintDokument: 80 | def __init__(self, fname): 81 | self.fname = fname 82 | 83 | def Run(self): 84 | html = open(self.fname, 'rt').read() 85 | split='' 86 | start = html.find(split) + len(split) 87 | end = html.find('') 88 | htmlstart = html[0:start] 89 | htmlend = html[end:] 90 | html = html[start:end] 91 | htmlpages = [] 92 | split = '
' 93 | start = 0 94 | while True: 95 | stop = html.find(split, start) 96 | if stop == -1: 97 | htmlpages.append((start, len(html))) 98 | break 99 | htmlpages.append((start, stop)) 100 | start = stop+len(split) 101 | npages = len(htmlpages) 102 | 103 | pdd = wx.PrintDialogData() 104 | pdd.SetMaxPage(npages) 105 | pdd.SetToPage(npages) 106 | printer = wx.Printer(pdd) 107 | printout = HTMLPrinterPrintout(htmlstart, htmlend, html, htmlpages) 108 | if not printer.Print(None, printout, 1): 109 | rc = wx.Printer_GetLastError() 110 | else: 111 | rc = wx.PRINTER_NO_ERROR 112 | printout.Destroy() 113 | print('rc=', rc) 114 | 115 | class Main: 116 | def demo(self): 117 | wxapp = wx.App(False) 118 | 119 | if len(sys.argv) > 1: 120 | fname = sys.argv[1] 121 | else: 122 | fname = 'demo.html' 123 | cls = HTMLPrintDokument(fname) 124 | cls.Run() 125 | 126 | def main(): 127 | app = Main() 128 | app.demo() 129 | 130 | main() 131 | -------------------------------------------------------------------------------- /litehtmld.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import sys 3 | import gc 4 | gc.enable() 5 | 6 | import logme 7 | 8 | from litehtmlpy import litehtml, litehtmlpy 9 | 10 | class document_container(litehtml.document_container): 11 | pass 12 | 13 | def main(): 14 | #litehtml.litehtml.liblitehtmlpy.debuglog(1) 15 | if len(sys.argv) > 1: 16 | fname = sys.argv[1] 17 | else: 18 | fname = 'demo.html' 19 | html = open(fname, 'rt').read() 20 | cntr = document_container() 21 | try: 22 | doc = litehtmlpy.fromString(cntr, html, None, None) 23 | try: 24 | doc.render(cntr.size[0], litehtmlpy.render_all) 25 | clip = litehtmlpy.position(0, 0, doc.width(), doc.height()) 26 | doc.draw(0, 0, 0, clip) 27 | del clip 28 | print('done') 29 | finally: 30 | print('del doc') 31 | del doc 32 | finally: 33 | print('del cntr') 34 | del cntr 35 | 36 | showobjs = False 37 | print('gc.collect', gc.collect()) 38 | print('gc.get_count=', gc.get_count()) 39 | print('gc.get_stats=', gc.get_stats()) 40 | if showobjs: 41 | print('gc.get_objects=', gc.get_objects()) 42 | main() 43 | print('gc.collect', gc.collect()) 44 | print('gc.get_count=', gc.get_count()) 45 | print('gc.get_stats=', gc.get_stats()) 46 | if showobjs: 47 | print('gc.get_objects=', gc.get_objects()) 48 | -------------------------------------------------------------------------------- /litehtmlt.html: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 |
14 | 15 | 16 |
17 |
zażółcić gęślą jaźń
18 | web-platform-tests.org
19 | W3C tests
20 | W3C test flex-direction
21 | 22 |
23 |
24 | 27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /litehtmlt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import logme 3 | 4 | from litehtmlpy import litehtml, litehtmlpy 5 | 6 | class Button(litehtml.litehtmlpy.html_tag): 7 | def __init__(self, attributes, doc): 8 | super().__init__(doc) 9 | print('i`m the button', attributes, 'tagName=', self.get_tagName()) 10 | def draw(self, hdc, x, y, clip, ri): 11 | super().draw(hdc, x, y, clip, ri) 12 | print('Button.draw', hdc, x, y, clip, ri.pos()) 13 | 14 | class document_container(litehtml.document_container): 15 | def __init__(self): 16 | super().__init__() 17 | self.handlers = [] 18 | 19 | def import_css(self, text, url, base_url): 20 | url = urllib.parse.urljoin(base_url, url) 21 | if os.path.exists(url): 22 | with open(url, 'rt') as fp: 23 | data = fp.read() 24 | elif url.split(':')[0] in ('http', 'https'): 25 | r = requests.get(url) 26 | if r.headers['Content-Type'] == 'text/css': 27 | data = r.text 28 | if data is None: 29 | print('unknown import_css', url) 30 | return 31 | return data 32 | 33 | def create_element(self, tag_name, attributes=None, doc=None): 34 | if tag_name == 'button': 35 | if doc is not None: 36 | tagh = Button(attributes, doc) 37 | self.handlers.append(tagh) 38 | return tagh 39 | return True 40 | 41 | def main(): 42 | #litehtml.litehtml.liblitehtmlpy.debuglog(1) 43 | html = open('litehtmlt.html', 'rt').read() 44 | cntr = document_container() 45 | 46 | doc = litehtmlpy.fromString(cntr, html, None, None) 47 | doc.render(cntr.size[0], litehtmlpy.render_all) 48 | clip = litehtmlpy.position(0, 0, doc.width(), doc.height()) 49 | doc.draw(0, 0, 0, clip) 50 | del doc, cntr 51 | 52 | main() 53 | -------------------------------------------------------------------------------- /logme.py: -------------------------------------------------------------------------------- 1 | import logging 2 | logger = logging.getLogger() 3 | handler = logging.StreamHandler() 4 | formatter = logging.Formatter('%(asctime)s %(name)-12s %(levelname)-8s %(message)s') 5 | handler.setFormatter(formatter) 6 | logger.addHandler(handler) 7 | logger.setLevel(logging.DEBUG) 8 | 9 | if 1: 10 | import sys 11 | sys.path.insert(1, 'src') 12 | 13 | from litehtmlpy import litehtmlpy 14 | #litehtmlpy.debuglog(1) 15 | -------------------------------------------------------------------------------- /mingw-cross.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # https://cmake.org/cmake/help/book/mastering-cmake/chapter/Cross%20Compiling%20With%20CMake.html 3 | # 4 | # the name of the target operating system 5 | set(CMAKE_SYSTEM_NAME Windows) 6 | 7 | # which compilers to use for C and C++ 8 | set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) 9 | set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) 10 | 11 | # where is the target environment located 12 | set(CMAKE_FIND_ROOT_PATH /usr/bin 13 | /devel/bin/mingw-install) 14 | 15 | # adjust the default behavior of the FIND_XXX() commands: 16 | # search programs in the host environment 17 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 18 | 19 | # search headers and libraries in the target environment 20 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 21 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 22 | 23 | #set(CMAKE_BUILD_TYPE DEBUG) 24 | #set(CMAKE_C_FLAGS "-O0 -ggdb") 25 | #set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb") 26 | #set(CMAKE_C_FLAGS_RELEASE "-O0 -ggdb") 27 | #set(CMAKE_CXX_FLAGS "-O0 -ggdb") 28 | #set(CMAKE_CXX_FLAGS_DEBUG "-O0 -ggdb") 29 | #set(CMAKE_CXX_FLAGS_RELEASE "-O0 -ggdb") 30 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -static-libgcc -march=x86-64 -mtune=generic") 31 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -static-libgcc -static-libstdc++ -march=x86-64 -mtune=generic") 32 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib -static -static-libgcc -static-libstdc++ -march=x86-64 -mtune=generic") 33 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel", 5 | "ninja", 6 | "cmake>=3.12", 7 | "pybind11", 8 | ] 9 | build-backend = "setuptools.build_meta" 10 | 11 | [project] 12 | name = "litehtmlpy" 13 | version = "0.1.0" 14 | authors = [ 15 | { name="Grzegorz Makarewicz", email="mak@trisoft.com.pl" }, 16 | ] 17 | description = "LiteHtmlPy is a solution that helps python developers to create printouts and previews of html5/css3 pages without using a web browser." 18 | readme = "README.md" 19 | requires-python = ">=3.7" 20 | classifiers=[ 21 | 'Development Status :: 4 - Beta', 22 | 'Development Status :: 5 - Production/Stable', 23 | 'Operating System :: OS Independent', 24 | 'Intended Audience :: Developers', 25 | 'License :: OSI Approved :: MIT License', 26 | 'Programming Language :: Python :: 3', 27 | 'Topic :: Software Development :: Libraries :: Python Modules', 28 | 'Topic :: Office/Business', 29 | 'Topic :: Text Processing', 30 | 'Topic :: Multimedia :: Graphics', 31 | ] 32 | 33 | [project.urls] 34 | "Homepage" = "https://github.com/m32/litehtmlpy" 35 | "Bug Tracker" = "https://github.com/m32/litehtmlpy/issues" 36 | -------------------------------------------------------------------------------- /set_inner_html.cpp: -------------------------------------------------------------------------------- 1 | void litehtml::element::set_inner_html(const litehtml::tchar_t* str, litehtml::css* user_styles) 2 | { 3 | // parse document into GumboOutput 4 | GumboOptions options = kGumboDefaultOptions; 5 | 6 | options.fragment_context = gumbo_tag_enum(get_tagName()); 7 | 8 | GumboOutput* output = gumbo_parse_with_options(&options, str, strlen(str)); 9 | document::ptr doc = m_doc.lock(); 10 | 11 | m_children.clear(); 12 | 13 | document::create_node(output->root->v.element.children.data[0], m_children, true, doc); 14 | gumbo_destroy_output(&kGumboDefaultOptions, output); 15 | 16 | for (auto& child : m_children) 17 | { 18 | child->parent(shared_from_this()); 19 | } 20 | 21 | if( doc->is_initialised() ) 22 | { 23 | for (auto& child : m_children) 24 | { 25 | // Let's process created elements tree 26 | // apply master CSS 27 | child->apply_stylesheet(doc->get_context()->master_css()); 28 | 29 | // parse elements attributes 30 | child->parse_attributes(); 31 | 32 | // Apply parsed styles. 33 | child->apply_stylesheet(doc->get_styles()); 34 | 35 | // Apply user styles if any 36 | if (user_styles) 37 | { 38 | child->apply_stylesheet(*user_styles); 39 | } 40 | 41 | // Parse applied styles in the elements 42 | child->parse_styles(); 43 | 44 | // Finally initialize elements 45 | child->init(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import subprocess 4 | import sys 5 | from pathlib import Path 6 | 7 | from setuptools import Extension, setup, find_packages 8 | from setuptools.command.build_ext import build_ext 9 | 10 | from pybind11 import get_include 11 | 12 | # Convert distutils Windows platform specifiers to CMake -A arguments 13 | PLAT_TO_CMAKE = { 14 | "win32": "Win32", 15 | "win-amd64": "x64", 16 | "win-arm32": "ARM", 17 | "win-arm64": "ARM64", 18 | } 19 | 20 | 21 | # A CMakeExtension needs a sourcedir instead of a file list. 22 | # The name must be the _single_ output extension from the CMake build. 23 | # If you need multiple extensions, see scikit-build. 24 | class CMakeExtension(Extension): 25 | def __init__(self, name: str, sourcedir: str = "") -> None: 26 | super().__init__(name, sources=[]) 27 | self.sourcedir = os.fspath(Path(sourcedir).resolve()) 28 | 29 | 30 | class CMakeBuild(build_ext): 31 | def build_extension(self, ext: CMakeExtension) -> None: 32 | # Must be in this form due to bug in .resolve() only fixed in Python 3.10+ 33 | ext_fullpath = Path.cwd() / self.get_ext_fullpath(ext.name) # type: ignore[no-untyped-call] 34 | extdir = ext_fullpath.parent.resolve() 35 | 36 | # Using this requires trailing slash for auto-detection & inclusion of 37 | # auxiliary "native" libs 38 | 39 | debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug 40 | cfg = "Debug" if debug else "Release" 41 | 42 | # CMake lets you override the generator - we need to check this. 43 | # Can be set with Conda-Build, for example. 44 | cmake_generator = os.environ.get("CMAKE_GENERATOR", "") 45 | 46 | # Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON 47 | # EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code 48 | # from Python. 49 | cname = ext.name 50 | cmake_args = [ 51 | f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}{os.sep}{cname}{os.sep}", 52 | f"-DPYTHON_EXECUTABLE={sys.executable}", 53 | f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm 54 | "-DPYBIND11_INCLUDE_DIR={}".format(get_include()), 55 | "-DLITEHTML_BUILD_TESTING=OFF", 56 | "-DLITEHTMLPY_BUILD_TESTING=OFF", 57 | "-Wno-dev", 58 | ] 59 | build_args = [] 60 | # Adding CMake arguments set as environment variable 61 | # (needed e.g. to build for ARM OSx on conda-forge) 62 | if "CMAKE_ARGS" in os.environ: 63 | cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item] 64 | 65 | if self.compiler.compiler_type != "msvc": 66 | # Using Ninja-build since it a) is available as a wheel and b) 67 | # multithreads automatically. MSVC would require all variables be 68 | # exported for Ninja to pick it up, which is a little tricky to do. 69 | # Users can override the generator with CMAKE_GENERATOR in CMake 70 | # 3.15+. 71 | if not cmake_generator or cmake_generator == "Ninja": 72 | try: 73 | import ninja # noqa: F401 74 | 75 | ninja_executable_path = Path(ninja.BIN_DIR) / "ninja" 76 | cmake_args += [ 77 | "-GNinja", 78 | f"-DCMAKE_MAKE_PROGRAM:FILEPATH={ninja_executable_path}", 79 | ] 80 | except ImportError: 81 | pass 82 | 83 | else: 84 | 85 | # Single config generators are handled "normally" 86 | single_config = any(x in cmake_generator for x in {"NMake", "Ninja"}) 87 | 88 | # CMake allows an arch-in-generator style for backward compatibility 89 | contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"}) 90 | 91 | # Specify the arch if using MSVC generator, but only if it doesn't 92 | # contain a backward-compatibility arch spec already in the 93 | # generator name. 94 | if not single_config and not contains_arch: 95 | cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]] 96 | 97 | # Multi-config generators have a different way to specify configs 98 | if not single_config: 99 | cmake_args += [ 100 | f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}" 101 | ] 102 | build_args += ["--config", cfg] 103 | 104 | if sys.platform.startswith("darwin"): 105 | # Cross-compile support for macOS - respect ARCHFLAGS if set 106 | archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", "")) 107 | if archs: 108 | cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))] 109 | 110 | # Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level 111 | # across all generators. 112 | if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ: 113 | # self.parallel is a Python 3 only way to set parallel jobs by hand 114 | # using -j in the build_ext call, not supported by pip or PyPA-build. 115 | if hasattr(self, "parallel") and self.parallel: 116 | # CMake 3.12+ only. 117 | build_args += [f"-j{self.parallel}"] 118 | 119 | subprocess.run( 120 | ["cmake", ext.sourcedir, *cmake_args], check=True 121 | ) 122 | subprocess.run( 123 | ["cmake", "--build", ".", *build_args], check=True 124 | ) 125 | 126 | 127 | # The information here can also be placed in setup.cfg - better separation of 128 | # logic and declaration, and simpler if you include description/version in a file. 129 | setup( 130 | name="litehtmlpy", 131 | version="0.1.0", 132 | author="Grzegorz Makarewicz", 133 | author_email="mak@trisoft.com.pl", 134 | description="LiteHtmlPy is a solution that helps python developers to create printouts and previews of html5/css3 pages without using a web browser.", 135 | long_description="", 136 | ext_modules=[ 137 | CMakeExtension("litehtmlpy.litehtmlpy") 138 | ], 139 | cmdclass={"build_ext": CMakeBuild}, 140 | zip_safe=False, 141 | # extras_require={"test": ["pytest>=6.0"]}, 142 | python_requires=">=3.7", 143 | packages=find_packages(where="src"), 144 | package_dir={"": "src"}, 145 | ) 146 | -------------------------------------------------------------------------------- /src/background.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "background_layer") 2 | .def_readwrite("border_box", &lh::background_layer::border_box) 3 | .def_readwrite("border_radius", &lh::background_layer::border_radius) 4 | .def_readwrite("clip_box", &lh::background_layer::clip_box) 5 | .def_readwrite("origin_box", &lh::background_layer::origin_box) 6 | .def_readwrite("attachment", &lh::background_layer::attachment) 7 | .def_readwrite("repeat", &lh::background_layer::repeat) 8 | .def_readwrite("is_root", &lh::background_layer::is_root) 9 | // 10 | .def(py::init<>()) 11 | ; 12 | py::class_(m, "background_layer_image") 13 | .def_readwrite("url", &lh::background_layer::image::url) 14 | .def_readwrite("base_url", &lh::background_layer::image::base_url) 15 | ; 16 | py::class_(m, "background_layer_color_point") 17 | .def_readwrite("offset", &lh::background_layer::color_point::offset) 18 | .def_readwrite("color", &lh::background_layer::color_point::color) 19 | .def_readwrite("hint", &lh::background_layer::color_point::hint) 20 | // 21 | .def(py::init<>()) 22 | .def(py::init(), "offset"_a, "color"_a) 23 | ; 24 | py::class_(m, "background_layer_color") 25 | .def_readwrite("color", &lh::background_layer::color::color) 26 | ; 27 | /* 28 | class gradient_base 29 | { 30 | public: 31 | vector color_points; 32 | color_space_t color_space = color_space_none; 33 | hue_interpolation_t hue_interpolation = hue_interpolation_none; 34 | 35 | void color_points_transparent_fix(); 36 | bool prepare_color_points(float len, string_id grad_type, const vector& colors); 37 | }; 38 | 39 | class linear_gradient : public gradient_base 40 | { 41 | public: 42 | pointF start; 43 | pointF end; 44 | }; 45 | 46 | class radial_gradient : public gradient_base 47 | { 48 | public: 49 | pointF position; 50 | pointF radius; 51 | }; 52 | 53 | class conic_gradient : public gradient_base 54 | { 55 | public: 56 | pointF position; 57 | float angle = 0; 58 | }; 59 | */ 60 | py::enum_(m, "layer_type") 61 | .value("type_none", lh::background::layer_type::type_none) 62 | .value("type_color", lh::background::layer_type::type_color) 63 | .value("type_image", lh::background::layer_type::type_image) 64 | .value("type_linear_gradient", lh::background::layer_type::type_linear_gradient) 65 | .value("type_radial_gradient", lh::background::layer_type::type_radial_gradient) 66 | .value("type_conic_gradient", lh::background::layer_type::type_conic_gradient) 67 | ; 68 | 69 | py::class_(m, "background") 70 | .def_readwrite("m_image", &lh::background::m_image) 71 | .def_readwrite("m_baseurl", &lh::background::m_baseurl) 72 | .def_readwrite("m_color", &lh::background::m_color) 73 | .def_readwrite("m_attachment", &lh::background::m_attachment) 74 | .def_readwrite("m_position_x", &lh::background::m_position_x) 75 | .def_readwrite("m_position_y", &lh::background::m_position_y) 76 | .def_readwrite("m_size", &lh::background::m_size) 77 | .def_readwrite("m_repeat", &lh::background::m_repeat) 78 | .def_readwrite("m_clip", &lh::background::m_clip) 79 | .def_readwrite("m_origin", &lh::background::m_origin) 80 | // 81 | .def("is_empty", &lh::background::is_empty) 82 | .def("get_layers_number", &lh::background::get_layers_number) 83 | .def("get_layer", &lh::background::get_layer, "idx"_a, "pos"_a, "el"_a, "ri"_a, "layer"_a) 84 | .def("get_layer_type", &lh::background::get_layer_type, "idx"_a) 85 | .def("get_image_layer", &lh::background::get_image_layer, "idx"_a) 86 | .def("get_color_layer", &lh::background::get_color_layer, "idx"_a) 87 | .def("get_linear_gradient_layer", &lh::background::get_linear_gradient_layer, "idx"_a, "layer"_a) 88 | .def("get_radial_gradient_layer", &lh::background::get_radial_gradient_layer, "idx"_a, "layer"_a) 89 | .def("get_conic_gradient_layer", &lh::background::get_conic_gradient_layer, "idx"_a, "layer"_a) 90 | .def("draw_layer", &lh::background::draw_layer, "hdc"_a, "idx"_a, "layer"_a, "container"_a) 91 | ; 92 | -------------------------------------------------------------------------------- /src/borders.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_border") 2 | .def_readwrite("width", &lh::css_border::width) 3 | .def_readwrite("style", &lh::css_border::style) 4 | .def_readwrite("style", &lh::css_border::color) 5 | // 6 | .def(py::init<>()) 7 | .def(py::init()) 8 | //css_border& operator=(const css_border& val) 9 | .def("to_string", &lh::css_border::to_string) 10 | ; 11 | 12 | py::class_(m, "border") 13 | .def_readwrite("width", &lh::border::width) 14 | .def_readwrite("style", &lh::border::style) 15 | .def_readwrite("color", &lh::border::color) 16 | // 17 | .def(py::init<>()) 18 | .def(py::init()) 19 | .def(py::init()) 20 | //border& operator=(const border& val) 21 | //border& operator=(const css_border& val) 22 | ; 23 | 24 | py::class_(m, "border_radiuses") 25 | .def_readwrite("top_left_x", &lh::border_radiuses::top_left_x) 26 | .def_readwrite("top_left_y", &lh::border_radiuses::top_left_y) 27 | .def_readwrite("top_right_x", &lh::border_radiuses::top_right_x) 28 | .def_readwrite("top_right_y", &lh::border_radiuses::top_right_y) 29 | .def_readwrite("bottom_right_x", &lh::border_radiuses::bottom_right_x) 30 | .def_readwrite("bottom_right_y", &lh::border_radiuses::bottom_right_y) 31 | .def_readwrite("bottom_left_x", &lh::border_radiuses::bottom_left_x) 32 | .def_readwrite("bottom_left_y", &lh::border_radiuses::bottom_left_y) 33 | // 34 | .def(py::init<>()) 35 | .def(py::init()) 36 | //border_radiuses& operator = (const border_radiuses& val) 37 | //void operator += (const margins& mg) 38 | //void operator -= (const margins& mg) 39 | //.def("fix_values", &lh::border_radiuses::fix_values) 40 | //void fix_values(int width, int height) 41 | ; 42 | 43 | py::class_(m, "css_border_radius") 44 | .def_readwrite("top_left_x", &lh::css_border_radius::top_left_x) 45 | .def_readwrite("top_left_y", &lh::css_border_radius::top_left_y) 46 | .def_readwrite("top_right_x", &lh::css_border_radius::top_right_x) 47 | .def_readwrite("top_right_y", &lh::css_border_radius::top_right_y) 48 | .def_readwrite("bottom_right_x", &lh::css_border_radius::bottom_right_x) 49 | .def_readwrite("bottom_right_y", &lh::css_border_radius::bottom_right_y) 50 | .def_readwrite("bottom_left_x", &lh::css_border_radius::bottom_left_x) 51 | .def_readwrite("bottom_left_y", &lh::css_border_radius::bottom_left_y) 52 | // 53 | .def(py::init<>()) 54 | .def(py::init()) 55 | //css_border_radius& operator=(const css_border_radius& val) 56 | //border_radiuses calc_percents(int width, int height) const 57 | ; 58 | 59 | py::class_(m, "css_borders") 60 | .def_readwrite("left", &lh::css_borders::left) 61 | .def_readwrite("top", &lh::css_borders::top) 62 | .def_readwrite("right", &lh::css_borders::right) 63 | .def_readwrite("bottom", &lh::css_borders::bottom) 64 | .def_readwrite("radius", &lh::css_borders::radius) 65 | // 66 | //?css_borders() = default; 67 | .def(py::init<>()) 68 | //.def(py::init()) 69 | .def("is_visible", &lh::css_borders::is_visible) 70 | //css_borders& operator=(const css_borders& val) 71 | .def("to_string", &lh::css_borders::to_string) 72 | ; 73 | 74 | py::class_(m, "borders") 75 | .def_readwrite("left", &lh::borders::left) 76 | .def_readwrite("top", &lh::borders::top) 77 | .def_readwrite("right", &lh::borders::right) 78 | .def_readwrite("bottom", &lh::borders::bottom) 79 | .def_readwrite("radius", &lh::borders::radius) 80 | 81 | //?borders() = default; 82 | .def(py::init<>()) 83 | //.def(py::init()) 84 | //.def(py::init()) 85 | .def("is_visible", &lh::borders::is_visible) 86 | //borders& operator=(const borders& val) 87 | //borders& operator=(const css_borders& val) 88 | ; 89 | -------------------------------------------------------------------------------- /src/cairo/cairo_borders.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "cairo_borders.h" 3 | #include 4 | 5 | #ifndef M_PI 6 | # define M_PI 3.14159265358979323846 7 | #endif 8 | 9 | void cairo::add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg) 10 | { 11 | if(rx > 0 && ry > 0) 12 | { 13 | cairo_save(cr); 14 | 15 | cairo_translate(cr, x, y); 16 | cairo_scale(cr, 1, ry / rx); 17 | cairo_translate(cr, -x, -y); 18 | 19 | if(neg) 20 | { 21 | cairo_arc_negative(cr, x, y, rx, a1, a2); 22 | } else 23 | { 24 | cairo_arc(cr, x, y, rx, a1, a2); 25 | } 26 | 27 | cairo_restore(cr); 28 | } else 29 | { 30 | cairo_move_to(cr, x, y); 31 | } 32 | } 33 | 34 | /** 35 | * Draw border at the left side. Use the only function to draw all border by using rotation transfer 36 | * @param cr cairo context 37 | * @param left left position of the border 38 | * @param top top position of the border 39 | * @param bottom bottom position of the border 40 | * @param data border data 41 | */ 42 | void cairo::border::draw_border() 43 | { 44 | cairo_save(cr); 45 | 46 | if(radius_top_x && radius_top_y) 47 | { 48 | double start_angle = M_PI; 49 | double end_angle = start_angle + M_PI / 2.0 / ((double) top_border_width / (double) border_width + 1); 50 | 51 | add_path_arc(cr, 52 | left + radius_top_x, 53 | top + radius_top_y, 54 | radius_top_x - border_width, 55 | radius_top_y - border_width + (border_width - top_border_width), 56 | start_angle, 57 | end_angle, false); 58 | 59 | add_path_arc(cr, 60 | left + radius_top_x, 61 | top + radius_top_y, 62 | radius_top_x, 63 | radius_top_y, 64 | end_angle, 65 | start_angle, true); 66 | } else 67 | { 68 | cairo_move_to(cr, left + border_width, top + top_border_width); 69 | cairo_line_to(cr, left, top); 70 | } 71 | 72 | if(radius_bottom_x && radius_bottom_y) 73 | { 74 | cairo_line_to(cr, left, bottom - radius_bottom_y); 75 | 76 | double end_angle = M_PI; 77 | double start_angle = end_angle - M_PI / 2.0 / ((double) bottom_border_width / (double) border_width + 1); 78 | 79 | add_path_arc(cr, 80 | left + radius_bottom_x, 81 | bottom - radius_bottom_y, 82 | radius_bottom_x, 83 | radius_bottom_y, 84 | end_angle, 85 | start_angle, true); 86 | 87 | add_path_arc(cr, 88 | left + radius_bottom_x, 89 | bottom - radius_bottom_y, 90 | radius_bottom_x - border_width, 91 | radius_bottom_y - border_width + (border_width - bottom_border_width), 92 | start_angle, 93 | end_angle, false); 94 | } else 95 | { 96 | cairo_line_to(cr, left, bottom); 97 | cairo_line_to(cr, left + border_width, bottom - bottom_border_width); 98 | } 99 | cairo_clip(cr); 100 | 101 | switch (style) 102 | { 103 | case litehtml::border_style_dotted: 104 | draw_dotted(); 105 | break; 106 | case litehtml::border_style_dashed: 107 | draw_dashed(); 108 | break; 109 | case litehtml::border_style_double: 110 | draw_double(); 111 | break; 112 | case litehtml::border_style_inset: 113 | draw_inset_outset(true); 114 | break; 115 | case litehtml::border_style_outset: 116 | draw_inset_outset(false); 117 | break; 118 | case litehtml::border_style_groove: 119 | draw_groove_ridge(true); 120 | break; 121 | case litehtml::border_style_ridge: 122 | draw_groove_ridge(false); 123 | break; 124 | default: 125 | draw_solid(); 126 | break; 127 | } 128 | 129 | cairo_restore(cr); 130 | } 131 | 132 | void cairo::border::draw_line(double line_offset, double top_line_offset, double bottom_line_offset) 133 | { 134 | if(radius_top_x && radius_top_y) 135 | { 136 | double end_angle = M_PI; 137 | double start_angle = end_angle + M_PI / 2.0 / ((double) top_border_width / (double) border_width + 1); 138 | 139 | add_path_arc(cr, 140 | left + radius_top_x, 141 | top + radius_top_y, 142 | radius_top_x - line_offset, 143 | radius_top_y - line_offset + (line_offset - top_line_offset), 144 | start_angle, 145 | end_angle, true); 146 | } else 147 | { 148 | cairo_move_to(cr, left + line_offset, top); 149 | } 150 | 151 | if(radius_bottom_x && radius_bottom_y) 152 | { 153 | cairo_line_to(cr, left + line_offset, bottom - radius_bottom_y); 154 | 155 | double start_angle = M_PI; 156 | double end_angle = start_angle - M_PI / 2.0 / ((double) bottom_border_width / (double) border_width + 1); 157 | 158 | add_path_arc(cr, 159 | left + radius_bottom_x, 160 | bottom - radius_bottom_y, 161 | radius_bottom_x - line_offset, 162 | radius_bottom_y - line_offset + (line_offset - bottom_line_offset), 163 | start_angle, 164 | end_angle, true); 165 | } else 166 | { 167 | cairo_line_to(cr, left + line_offset, bottom); 168 | } 169 | } 170 | 171 | void cairo::border::draw_inset_outset(bool is_inset) 172 | { 173 | litehtml::web_color line_color; 174 | litehtml::web_color light_color = color; 175 | litehtml::web_color dark_color = color.darken(0.33); 176 | if(color.red == 0 && color.green == 0 && color.blue == 0) 177 | { 178 | dark_color.red = dark_color.green = dark_color.blue = 0x4C; 179 | light_color.red = light_color.green = light_color.blue = 0xB2; 180 | } 181 | 182 | if (real_side == left_side || real_side == top_side) 183 | { 184 | line_color = is_inset ? dark_color : light_color; 185 | } else 186 | { 187 | line_color = is_inset ? light_color : dark_color; 188 | } 189 | draw_line(border_width / 2.0, 190 | top_border_width / 2.0, 191 | bottom_border_width / 2.0); 192 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); 193 | cairo_set_dash(cr, nullptr, 0, 0); 194 | set_color(cr, line_color); 195 | cairo_set_line_width(cr, border_width); 196 | cairo_stroke(cr); 197 | } 198 | 199 | void cairo::border::draw_double() 200 | { 201 | if (border_width < 3) 202 | { 203 | draw_solid(); 204 | } else 205 | { 206 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); 207 | cairo_set_dash(cr, nullptr, 0, 0); 208 | set_color(cr, color); 209 | 210 | double line_width = border_width / 3.0; 211 | cairo_set_line_width(cr, line_width); 212 | // draw external line 213 | draw_line(line_width / 2.0, 214 | top_border_width / 6.0, 215 | bottom_border_width / 6.0); 216 | cairo_stroke(cr); 217 | // draw internal line 218 | draw_line(border_width - line_width / 2.0, 219 | top_border_width - top_border_width / 6.0, 220 | bottom_border_width - bottom_border_width / 6.0); 221 | cairo_stroke(cr); 222 | } 223 | } 224 | 225 | void cairo::border::draw_dashed() 226 | { 227 | int line_length = std::abs(bottom - top); 228 | if(!line_length) return; 229 | 230 | draw_line(border_width / 2.0, 231 | top_border_width / 2.0, 232 | bottom_border_width / 2.0); 233 | 234 | int segment_length = border_width * 3; 235 | int seg_nums = line_length / segment_length; 236 | if(seg_nums < 2) 237 | { 238 | seg_nums = 2; 239 | } if(seg_nums % 2 != 0) 240 | { 241 | seg_nums = seg_nums + 1; 242 | } 243 | seg_nums++; 244 | double seg_len = (double) line_length / (double) seg_nums; 245 | 246 | double dashes[2]; 247 | dashes[0] = seg_len; 248 | dashes[1] = seg_len; 249 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); 250 | cairo_set_dash(cr, dashes, 2, 0); 251 | set_color(cr, color); 252 | cairo_set_line_width(cr, border_width); 253 | cairo_stroke(cr); 254 | } 255 | 256 | void cairo::border::draw_solid() 257 | { 258 | draw_line(border_width / 2.0, 259 | top_border_width / 2.0, 260 | bottom_border_width / 2.0); 261 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); 262 | cairo_set_dash(cr, nullptr, 0, 0); 263 | set_color(cr, color); 264 | cairo_set_line_width(cr, border_width); 265 | cairo_stroke(cr); 266 | } 267 | 268 | void cairo::border::draw_dotted() 269 | { 270 | // Zero length line 271 | if(bottom == top) return; 272 | 273 | draw_line(border_width / 2.0, 274 | top_border_width / 2.0, 275 | bottom_border_width / 2.0); 276 | 277 | double line_length = std::abs(bottom - top); 278 | 279 | double dot_size = border_width; 280 | int num_dots = (int) std::nearbyint(line_length / (dot_size * 2.0)); 281 | if(num_dots < 2) 282 | { 283 | num_dots = 2; 284 | } if(num_dots % 2 != 0) 285 | { 286 | num_dots = num_dots + 1; 287 | } 288 | num_dots++; 289 | double space_len = ((double) line_length - (double) border_width) / (num_dots - 1.0); 290 | 291 | double dashes[2]; 292 | dashes[0] = 0; 293 | dashes[1] = space_len; 294 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); 295 | cairo_set_dash(cr, dashes, 2, -dot_size / 2.0); 296 | 297 | set_color(cr, color); 298 | cairo_set_line_width(cr, border_width); 299 | cairo_stroke(cr); 300 | } 301 | 302 | void cairo::border::draw_groove_ridge(bool is_groove) 303 | { 304 | if(border_width == 1) 305 | { 306 | draw_solid(); 307 | } else 308 | { 309 | litehtml::web_color inner_line_color; 310 | litehtml::web_color outer_line_color; 311 | litehtml::web_color light_color = color; 312 | litehtml::web_color dark_color = color.darken(0.33); 313 | if (color.red == 0 && color.green == 0 && color.blue == 0) 314 | { 315 | dark_color.red = dark_color.green = dark_color.blue = 0x4C; 316 | light_color.red = light_color.green = light_color.blue = 0xB2; 317 | } 318 | 319 | if (real_side == left_side || real_side == top_side) 320 | { 321 | outer_line_color = is_groove ? dark_color : light_color; 322 | inner_line_color = is_groove ? light_color : dark_color; 323 | } else 324 | { 325 | outer_line_color = is_groove ? light_color : dark_color; 326 | inner_line_color = is_groove ? dark_color : light_color; 327 | } 328 | 329 | cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT); 330 | cairo_set_dash(cr, nullptr, 0, 0); 331 | 332 | double line_width = border_width / 2.0; 333 | cairo_set_line_width(cr, line_width); 334 | // draw external line 335 | draw_line(line_width / 2.0, 336 | top_border_width / 4.0, 337 | bottom_border_width / 4.0); 338 | set_color(cr, outer_line_color); 339 | cairo_stroke(cr); 340 | // draw internal line 341 | set_color(cr, inner_line_color); 342 | draw_line(border_width - line_width / 2.0, 343 | top_border_width - top_border_width / 4.0, 344 | bottom_border_width - bottom_border_width / 4.0); 345 | cairo_stroke(cr); 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /src/cairo/cairo_borders.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_CAIRO_BORDERS_H 2 | #define LITEHTML_CAIRO_BORDERS_H 3 | 4 | #include 5 | 6 | namespace cairo 7 | { 8 | extern void add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg); 9 | inline void set_color(cairo_t* cr, const litehtml::web_color& color) 10 | { 11 | cairo_set_source_rgba(cr, color.red / 255.0, color.green / 255.0, color.blue / 255.0, color.alpha / 255.0); 12 | } 13 | 14 | class border 15 | { 16 | public: 17 | enum real_side_t 18 | { 19 | left_side, 20 | top_side, 21 | right_side, 22 | bottom_side 23 | }; 24 | 25 | real_side_t real_side; /// real side of the border 26 | litehtml::web_color color; 27 | litehtml::border_style style; 28 | 29 | int border_width; 30 | int top_border_width; 31 | int bottom_border_width; 32 | 33 | int radius_top_x; 34 | int radius_top_y; 35 | int radius_bottom_x; 36 | int radius_bottom_y; 37 | 38 | border(cairo_t* _cr, int _left, int _top, int _bottom) : 39 | real_side(left_side), 40 | color(), 41 | style(litehtml::border_style_none), 42 | border_width(0), 43 | top_border_width(0), 44 | bottom_border_width(0), 45 | radius_top_x(0), 46 | radius_top_y(0), 47 | radius_bottom_x(0), 48 | radius_bottom_y(0), 49 | cr(_cr), left(_left), top(_top), bottom(_bottom) 50 | {} 51 | 52 | void draw_border(); 53 | 54 | private: 55 | cairo_t* cr; 56 | int left; 57 | int top; 58 | int bottom; 59 | void draw_line(double line_offset, double top_line_offset, double bottom_line_offset); 60 | void draw_solid(); 61 | void draw_dotted(); 62 | void draw_dashed(); 63 | void draw_double(); 64 | void draw_inset_outset(bool is_inset); 65 | void draw_groove_ridge(bool is_groove); 66 | }; 67 | } 68 | 69 | #endif //LITEHTML_CAIRO_BORDERS_H 70 | -------------------------------------------------------------------------------- /src/cairo/cairo_images_cache.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_CAIRO_IMAGES_CACHE_H 2 | #define LITEHTML_CAIRO_IMAGES_CACHE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class cairo_surface_wrapper 10 | { 11 | cairo_surface_t* surface; 12 | public: 13 | cairo_surface_wrapper() : surface(nullptr) {} 14 | cairo_surface_wrapper(const cairo_surface_wrapper& v) : surface(v.surface) 15 | { 16 | if(v.surface) 17 | { 18 | surface = cairo_surface_reference(v.surface); 19 | } 20 | } 21 | explicit cairo_surface_wrapper(cairo_surface_t* v) : surface(v) {} 22 | cairo_surface_wrapper(cairo_surface_wrapper&& v) noexcept 23 | { 24 | surface = v.surface; 25 | v.surface = nullptr; 26 | } 27 | cairo_surface_wrapper& operator=(const cairo_surface_wrapper& v) 28 | { 29 | if(surface != v.surface) 30 | { 31 | if(surface) 32 | { 33 | cairo_surface_destroy(surface); 34 | } 35 | surface = cairo_surface_reference(v.surface); 36 | } 37 | return *this; 38 | } 39 | ~cairo_surface_wrapper() 40 | { 41 | if(surface) 42 | { 43 | cairo_surface_destroy(surface); 44 | } 45 | } 46 | cairo_surface_t* get() { return cairo_surface_reference(surface); } 47 | }; 48 | 49 | class cairo_images_cache 50 | { 51 | std::mutex m_mutex; 52 | std::map m_images; 53 | public: 54 | void add_image(const std::string& url, cairo_surface_t* image) 55 | { 56 | std::unique_lock lock(m_mutex); 57 | m_images[url] = cairo_surface_wrapper(image); 58 | } 59 | 60 | cairo_surface_t* get_image(const std::string& url) 61 | { 62 | std::unique_lock lock(m_mutex); 63 | auto iter = m_images.find(url); 64 | if(iter != m_images.end()) 65 | { 66 | return iter->second.get(); 67 | } 68 | return nullptr; 69 | } 70 | 71 | bool reserve(const std::string& url) 72 | { 73 | std::unique_lock lock(m_mutex); 74 | auto iter = m_images.find(url); 75 | if (iter == m_images.end()) 76 | { 77 | m_images[url] = cairo_surface_wrapper(); 78 | return true; 79 | } 80 | return false; 81 | } 82 | 83 | bool exists(const std::string& url) 84 | { 85 | std::unique_lock lock(m_mutex); 86 | auto iter = m_images.find(url); 87 | return iter != m_images.end(); 88 | } 89 | 90 | void clear() 91 | { 92 | std::unique_lock lock(m_mutex); 93 | m_images.clear(); 94 | } 95 | }; 96 | 97 | #endif //LITEHTML_CAIRO_IMAGES_CACHE_H 98 | -------------------------------------------------------------------------------- /src/cairo/container_cairo.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_CONTAINER_LINUX_H 2 | #define LH_CONTAINER_LINUX_H 3 | 4 | #include 5 | #include 6 | 7 | struct cairo_clip_box 8 | { 9 | typedef std::vector vector; 10 | litehtml::position box; 11 | litehtml::border_radiuses radius; 12 | 13 | cairo_clip_box(const litehtml::position& vBox, const litehtml::border_radiuses& vRad) 14 | { 15 | box = vBox; 16 | radius = vRad; 17 | } 18 | 19 | cairo_clip_box(const cairo_clip_box& val) 20 | { 21 | box = val.box; 22 | radius = val.radius; 23 | } 24 | cairo_clip_box& operator=(const cairo_clip_box& val) 25 | { 26 | box = val.box; 27 | radius = val.radius; 28 | return *this; 29 | } 30 | }; 31 | 32 | class container_cairo : public litehtml::document_container 33 | { 34 | protected: 35 | cairo_clip_box::vector m_clips; 36 | public: 37 | container_cairo() = default; 38 | virtual ~container_cairo() = default; 39 | 40 | int pt_to_px(int pt) const override; 41 | int get_default_font_size() const override; 42 | const char* get_default_font_name() const override; 43 | void get_image_size(const char* src, const char* baseurl, litehtml::size& sz) override; 44 | void draw_image(litehtml::uint_ptr hdc, const litehtml::background_layer& layer, const std::string& url, const std::string& base_url) override; 45 | void draw_solid_fill(litehtml::uint_ptr hdc, const litehtml::background_layer& layer, const litehtml::web_color& color) override; 46 | void draw_linear_gradient(litehtml::uint_ptr hdc, const litehtml::background_layer& layer, const litehtml::background_layer::linear_gradient& gradient) override; 47 | void draw_radial_gradient(litehtml::uint_ptr hdc, const litehtml::background_layer& layer, const litehtml::background_layer::radial_gradient& gradient) override; 48 | void draw_conic_gradient(litehtml::uint_ptr hdc, const litehtml::background_layer& layer, const litehtml::background_layer::conic_gradient& gradient) override; 49 | void draw_borders(litehtml::uint_ptr hdc, const litehtml::borders& borders, const litehtml::position& draw_pos, bool root) override; 50 | void draw_list_marker(litehtml::uint_ptr hdc, const litehtml::list_marker& marker) override; 51 | std::shared_ptr create_element(const char *tag_name, 52 | const litehtml::string_map &attributes, 53 | const std::shared_ptr &doc) override; 54 | void get_media_features(litehtml::media_features& media) const override; 55 | void get_language(litehtml::string& language, litehtml::string & culture) const override; 56 | void link(const std::shared_ptr &ptr, const litehtml::element::ptr& el) override; 57 | 58 | 59 | void transform_text(litehtml::string& text, litehtml::text_transform tt) override; 60 | void set_clip(const litehtml::position& pos, const litehtml::border_radiuses& bdr_radius) override; 61 | void del_clip() override; 62 | 63 | virtual void make_url( const char* url, const char* basepath, litehtml::string& out ); 64 | virtual cairo_surface_t* get_image(const std::string& url) = 0; 65 | virtual double get_screen_dpi() const = 0; 66 | virtual int get_screen_width() const = 0; 67 | virtual int get_screen_height() const = 0; 68 | 69 | void clear_images(); 70 | 71 | protected: 72 | virtual void draw_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color, int line_width); 73 | virtual void fill_ellipse(cairo_t* cr, int x, int y, int width, int height, const litehtml::web_color& color); 74 | virtual void rounded_rectangle( cairo_t* cr, const litehtml::position &pos, const litehtml::border_radiuses &radius ); 75 | 76 | void clip_background_layer(cairo_t* cr, const litehtml::background_layer& layer); 77 | void apply_clip(cairo_t* cr); 78 | static void set_color(cairo_t* cr, const litehtml::web_color& color) 79 | { 80 | cairo_set_source_rgba(cr, 81 | color.red / 255.0, 82 | color.green / 255.0, 83 | color.blue / 255.0, 84 | color.alpha / 255.0); 85 | } 86 | private: 87 | 88 | static void add_path_arc(cairo_t* cr, double x, double y, double rx, double ry, double a1, double a2, bool neg); 89 | static void draw_pixbuf(cairo_t* cr, cairo_surface_t* bmp, int x, int y, int cx, int cy); 90 | static cairo_surface_t* scale_surface(cairo_surface_t* surface, int width, int height); 91 | }; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/cairo/container_cairo_pango.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEBROWSER_CONTAINER_CAIRO_PANGO_H 2 | #define LITEBROWSER_CONTAINER_CAIRO_PANGO_H 3 | 4 | #include 5 | #include "container_cairo.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct cairo_font 12 | { 13 | PangoFontDescription* font; 14 | int size; 15 | bool underline; 16 | bool strikeout; 17 | bool overline; 18 | int ascent; 19 | int descent; 20 | int underline_thickness; 21 | int underline_position; 22 | int strikethrough_thickness; 23 | int strikethrough_position; 24 | int overline_thickness; 25 | int overline_position; 26 | int decoration_style; 27 | litehtml::web_color decoration_color; 28 | }; 29 | 30 | class container_cairo_pango : public container_cairo 31 | { 32 | cairo_surface_t* m_temp_surface; 33 | cairo_t* m_temp_cr; 34 | std::set m_all_fonts; 35 | public: 36 | container_cairo_pango(); 37 | ~container_cairo_pango() override; 38 | litehtml::uint_ptr create_font(const litehtml::font_description& descr, const litehtml::document* doc, litehtml::font_metrics* fm) override; 39 | void delete_font(litehtml::uint_ptr hFont) override; 40 | int text_width(const char* text, litehtml::uint_ptr hFont) override; 41 | void draw_text(litehtml::uint_ptr hdc, const char* text, litehtml::uint_ptr hFont, litehtml::web_color color, const litehtml::position& pos) override; 42 | 43 | virtual cairo_font_options_t* get_font_options() { return nullptr; } 44 | 45 | litehtml::uint_ptr surface(int width, int height); 46 | void save(const char *fname); 47 | cairo_surface_t* getsurface() { 48 | return m_temp_surface; 49 | } 50 | }; 51 | 52 | #endif //LITEBROWSER_CONTAINER_CAIRO_PANGO_H 53 | -------------------------------------------------------------------------------- /src/css_length.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_length") 2 | .def(py::init<>()) 3 | .def(py::init()) 4 | //css_length& operator=(float val) 5 | .def("is_predefined", &lh::css_length::is_predefined) 6 | //.def("predef", &lh::css_length::predef) 7 | .def("predef_value", &lh::css_length::predef_value) 8 | .def("set_value", &lh::css_length::set_value) 9 | .def("val", &lh::css_length::val) 10 | .def("units", &lh::css_length::units) 11 | .def("calc_percent", &lh::css_length::calc_percent) 12 | .def("to_string", &lh::css_length::to_string) 13 | ; 14 | -------------------------------------------------------------------------------- /src/css_margins.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_margins") 2 | .def_readwrite("left", &lh::css_margins::left) 3 | .def_readwrite("right", &lh::css_margins::right) 4 | .def_readwrite("top", &lh::css_margins::top) 5 | .def_readwrite("bottom", &lh::css_margins::bottom) 6 | // 7 | .def(py::init<>()) 8 | .def(py::init()) 9 | //css_margins& operator=(const css_margins& val) 10 | .def("to_string", &lh::css_margins::to_string) 11 | ; 12 | -------------------------------------------------------------------------------- /src/css_offsets.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_offsets") 2 | .def_readwrite("left", &lh::css_offsets::left) 3 | .def_readwrite("right", &lh::css_offsets::right) 4 | .def_readwrite("top", &lh::css_offsets::top) 5 | .def_readwrite("bottom", &lh::css_offsets::bottom) 6 | // 7 | .def(py::init<>()) 8 | .def(py::init()) 9 | //css_offsets& operator=(const css_offsets& val) 10 | .def("to_string", &lh::css_offsets::to_string) 11 | ; 12 | -------------------------------------------------------------------------------- /src/css_position.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_position") 2 | .def_readwrite("x", &lh::css_position::x) 3 | .def_readwrite("y", &lh::css_position::y) 4 | .def_readwrite("width", &lh::css_position::width) 5 | .def_readwrite("height", &lh::css_position::height) 6 | ; 7 | py::class_(m, "css_size") 8 | .def_readwrite("width", &lh::css_size::width) 9 | .def_readwrite("height", &lh::css_size::height) 10 | // 11 | .def(py::init()) 12 | ; 13 | -------------------------------------------------------------------------------- /src/css_properties.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_properties") 2 | // 3 | .def(py::init<>()) 4 | //void compute(const element* el, const std::shared_ptr& doc); 5 | //std::vector> dump_get_attrs(); 6 | .def("get_position", &lh::css_properties::get_position) 7 | .def("set_position", &lh::css_properties::set_position) 8 | .def("get_text_align", &lh::css_properties::get_text_align) 9 | .def("set_text_align", &lh::css_properties::set_text_align) 10 | .def("get_overflow", &lh::css_properties::get_overflow) 11 | .def("set_overflow", &lh::css_properties::set_overflow) 12 | .def("get_white_space", &lh::css_properties::get_white_space) 13 | .def("set_white_space", &lh::css_properties::set_white_space) 14 | .def("get_display", &lh::css_properties::get_display) 15 | .def("set_display", &lh::css_properties::set_display) 16 | .def("get_visibility", &lh::css_properties::get_visibility) 17 | .def("set_visibility", &lh::css_properties::set_visibility) 18 | .def("get_appearance", &lh::css_properties::get_appearance) 19 | .def("set_appearance", &lh::css_properties::set_appearance) 20 | .def("get_box_sizing", &lh::css_properties::get_box_sizing) 21 | .def("set_box_sizing", &lh::css_properties::set_box_sizing) 22 | .def("get_z_index", &lh::css_properties::get_z_index) 23 | .def("set_z_index", &lh::css_properties::set_z_index) 24 | .def("get_vertical_align", &lh::css_properties::get_vertical_align) 25 | .def("set_vertical_align", &lh::css_properties::set_vertical_align) 26 | .def("get_float", &lh::css_properties::get_float) 27 | .def("set_float", &lh::css_properties::set_float) 28 | .def("get_clear", &lh::css_properties::get_clear) 29 | .def("set_clear", &lh::css_properties::get_clear) 30 | .def("get_margins", &lh::css_properties::get_margins) 31 | .def("set_margins", &lh::css_properties::set_margins) 32 | .def("get_padding", &lh::css_properties::get_padding) 33 | .def("set_padding", &lh::css_properties::set_padding) 34 | .def("get_borders", &lh::css_properties::get_borders) 35 | .def("set_borders", &lh::css_properties::set_borders) 36 | .def("get_width", &lh::css_properties::get_width) 37 | .def("set_width", &lh::css_properties::set_width) 38 | .def("get_height", &lh::css_properties::get_height) 39 | .def("set_height", &lh::css_properties::set_height) 40 | .def("get_min_width", &lh::css_properties::get_min_width) 41 | .def("set_min_width", &lh::css_properties::set_min_width) 42 | .def("get_min_height", &lh::css_properties::get_min_height) 43 | .def("set_min_height", &lh::css_properties::set_min_height) 44 | .def("get_max_width", &lh::css_properties::get_max_width) 45 | .def("set_max_width", &lh::css_properties::set_max_width) 46 | .def("get_max_height", &lh::css_properties::get_max_height) 47 | .def("set_max_height", &lh::css_properties::set_max_height) 48 | .def("get_offsets", &lh::css_properties::get_offsets) 49 | .def("set_offsets", &lh::css_properties::set_offsets) 50 | .def("get_text_indent", &lh::css_properties::get_text_indent) 51 | .def("set_text_indent", &lh::css_properties::set_text_indent) 52 | .def("line_height", &lh::css_properties::line_height) 53 | .def("line_height_w", &lh::css_properties::line_height_w) 54 | .def("get_list_style_type", &lh::css_properties::get_list_style_type) 55 | .def("set_list_style_type", &lh::css_properties::set_list_style_type) 56 | .def("get_list_style_position", &lh::css_properties::get_list_style_position) 57 | .def("set_list_style_position", &lh::css_properties::set_list_style_position) 58 | .def("get_list_style_image", &lh::css_properties::get_list_style_image) 59 | .def("set_list_style_image", &lh::css_properties::set_list_style_image) 60 | .def("get_list_style_image_baseurl", &lh::css_properties::get_list_style_image_baseurl) 61 | .def("set_list_style_image_baseurl", &lh::css_properties::set_list_style_image_baseurl) 62 | .def("get_bg", &lh::css_properties::get_bg) 63 | .def("set_bg", &lh::css_properties::set_bg) 64 | .def("get_font_size", &lh::css_properties::get_font_size) 65 | .def("set_font_size", &lh::css_properties::set_font_size) 66 | .def("get_font", &lh::css_properties::get_font) 67 | .def("set_font", &lh::css_properties::set_font) 68 | .def("get_font_metrics", &lh::css_properties::get_font_metrics) 69 | .def("set_font_metrics", &lh::css_properties::set_font_metrics) 70 | .def("get_text_transform", &lh::css_properties::get_text_transform) 71 | .def("set_text_transform", &lh::css_properties::set_text_transform) 72 | .def("get_color", &lh::css_properties::get_color) 73 | .def("set_color", &lh::css_properties::set_color) 74 | .def("get_cursor", &lh::css_properties::get_cursor) 75 | .def("set_cursor", &lh::css_properties::set_cursor) 76 | .def("get_content", &lh::css_properties::get_content) 77 | .def("set_content", &lh::css_properties::set_content) 78 | .def("get_border_collapse", &lh::css_properties::get_border_collapse) 79 | .def("set_border_collapse", &lh::css_properties::get_border_collapse) 80 | .def("get_border_spacing_x", &lh::css_properties::get_border_spacing_x) 81 | .def("set_border_spacing_x", &lh::css_properties::set_border_spacing_x) 82 | .def("get_border_spacing_y", &lh::css_properties::get_border_spacing_y) 83 | .def("set_border_spacing_y", &lh::css_properties::set_border_spacing_y) 84 | .def("get_caption_side", &lh::css_properties::get_caption_side) 85 | .def("set_caption_side", &lh::css_properties::set_caption_side) 86 | .def("get_flex_grow", &lh::css_properties::get_flex_grow) 87 | .def("get_flex_shrink", &lh::css_properties::get_flex_shrink) 88 | .def("get_flex_basis", &lh::css_properties::get_flex_basis) 89 | .def("get_flex_direction", &lh::css_properties::get_flex_direction) 90 | .def("get_flex_wrap", &lh::css_properties::get_flex_wrap) 91 | .def("get_flex_justify_content", &lh::css_properties::get_flex_justify_content) 92 | .def("get_flex_align_items", &lh::css_properties::get_flex_align_items) 93 | .def("get_flex_align_self", &lh::css_properties::get_flex_align_self) 94 | .def("get_flex_align_content", &lh::css_properties::get_flex_align_content) 95 | .def("get_order", &lh::css_properties::get_order) 96 | .def("set_order", &lh::css_properties::set_order) 97 | .def("get_text_decoration_line", &lh::css_properties::get_text_decoration_line) 98 | .def("get_text_decoration_style", &lh::css_properties::get_text_decoration_style) 99 | .def("get_text_decoration_thickness", &lh::css_properties::get_text_decoration_thickness) 100 | .def("get_text_decoration_color", &lh::css_properties::get_text_decoration_color) 101 | ; 102 | -------------------------------------------------------------------------------- /src/css_selector.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_CSS_SELECTOR_H 2 | #define LH_CSS_SELECTOR_H 3 | 4 | #include "style.h" 5 | #include "media_query.h" 6 | 7 | namespace litehtml 8 | { 9 | ////////////////////////////////////////////////////////////////////////// 10 | 11 | struct selector_specificity 12 | { 13 | int a; 14 | int b; 15 | int c; 16 | int d; 17 | 18 | explicit selector_specificity(int va = 0, int vb = 0, int vc = 0, int vd = 0) 19 | { 20 | a = va; 21 | b = vb; 22 | c = vc; 23 | d = vd; 24 | } 25 | 26 | void operator += (const selector_specificity& val) 27 | { 28 | a += val.a; 29 | b += val.b; 30 | c += val.c; 31 | d += val.d; 32 | } 33 | 34 | bool operator==(const selector_specificity& val) const 35 | { 36 | if(a == val.a && b == val.b && c == val.c && d == val.d) 37 | { 38 | return true; 39 | } 40 | return false; 41 | } 42 | 43 | bool operator!=(const selector_specificity& val) const 44 | { 45 | if(a != val.a || b != val.b || c != val.c || d != val.d) 46 | { 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | bool operator > (const selector_specificity& val) const 53 | { 54 | if(a > val.a) 55 | { 56 | return true; 57 | } else if(a < val.a) 58 | { 59 | return false; 60 | } else 61 | { 62 | if(b > val.b) 63 | { 64 | return true; 65 | } else if(b < val.b) 66 | { 67 | return false; 68 | } else 69 | { 70 | if(c > val.c) 71 | { 72 | return true; 73 | } else if(c < val.c) 74 | { 75 | return false; 76 | } else 77 | { 78 | if(d > val.d) 79 | { 80 | return true; 81 | } else if(d < val.d) 82 | { 83 | return false; 84 | } 85 | } 86 | } 87 | } 88 | return false; 89 | } 90 | 91 | bool operator >= (const selector_specificity& val) const 92 | { 93 | if((*this) == val) return true; 94 | if((*this) > val) return true; 95 | return false; 96 | } 97 | 98 | bool operator <= (const selector_specificity& val) const 99 | { 100 | if((*this) > val) 101 | { 102 | return false; 103 | } 104 | return true; 105 | } 106 | 107 | bool operator < (const selector_specificity& val) const 108 | { 109 | if((*this) <= val && (*this) != val) 110 | { 111 | return true; 112 | } 113 | return false; 114 | } 115 | 116 | }; 117 | 118 | ////////////////////////////////////////////////////////////////////////// 119 | 120 | enum attr_select_type 121 | { 122 | select_class, 123 | select_id, 124 | 125 | select_exists, 126 | select_equal, 127 | select_contain_str, 128 | select_start_str, 129 | select_end_str, 130 | 131 | select_pseudo_class, 132 | select_pseudo_element, 133 | }; 134 | 135 | ////////////////////////////////////////////////////////////////////////// 136 | 137 | class css_element_selector; 138 | 139 | struct css_attribute_selector 140 | { 141 | typedef std::vector vector; 142 | 143 | attr_select_type type; 144 | string_id name; // .name, #name, [name], :name 145 | string val; // [name=val], :lang(val) 146 | 147 | std::shared_ptr sel; // :not(sel) 148 | int a, b; // :nth-child(an+b) 149 | 150 | css_attribute_selector() 151 | { 152 | type = select_class; 153 | name = empty_id; 154 | a = b = 0; 155 | } 156 | }; 157 | 158 | ////////////////////////////////////////////////////////////////////////// 159 | 160 | class css_element_selector 161 | { 162 | public: 163 | string_id m_tag; 164 | css_attribute_selector::vector m_attrs; 165 | public: 166 | 167 | void parse(const string& txt); 168 | static void parse_nth_child_params(const string& param, int& num, int& off); 169 | }; 170 | 171 | ////////////////////////////////////////////////////////////////////////// 172 | 173 | enum css_combinator 174 | { 175 | combinator_descendant, 176 | combinator_child, 177 | combinator_adjacent_sibling, 178 | combinator_general_sibling 179 | }; 180 | 181 | ////////////////////////////////////////////////////////////////////////// 182 | 183 | class css_selector 184 | { 185 | public: 186 | typedef std::shared_ptr ptr; 187 | typedef std::vector vector; 188 | public: 189 | selector_specificity m_specificity; 190 | css_element_selector m_right; 191 | css_selector::ptr m_left; 192 | css_combinator m_combinator; 193 | style::ptr m_style; 194 | int m_order; 195 | media_query_list::ptr m_media_query; 196 | public: 197 | explicit css_selector(const media_query_list::ptr& media = nullptr) 198 | { 199 | m_media_query = media; 200 | m_combinator = combinator_descendant; 201 | m_order = 0; 202 | } 203 | 204 | ~css_selector() = default; 205 | 206 | css_selector(const css_selector& val) 207 | { 208 | m_right = val.m_right; 209 | if(val.m_left) 210 | { 211 | m_left = std::make_shared(*val.m_left); 212 | } else 213 | { 214 | m_left = nullptr; 215 | } 216 | m_combinator = val.m_combinator; 217 | m_specificity = val.m_specificity; 218 | m_order = val.m_order; 219 | m_media_query = val.m_media_query; 220 | } 221 | 222 | bool parse(const string& text); 223 | void calc_specificity(); 224 | bool is_media_valid() const; 225 | void add_media_to_doc(document* doc) const; 226 | }; 227 | 228 | inline bool css_selector::is_media_valid() const 229 | { 230 | if(!m_media_query) 231 | { 232 | return true; 233 | } 234 | return m_media_query->is_used(); 235 | } 236 | 237 | 238 | ////////////////////////////////////////////////////////////////////////// 239 | 240 | inline bool operator > (const css_selector& v1, const css_selector& v2) 241 | { 242 | if(v1.m_specificity == v2.m_specificity) 243 | { 244 | return (v1.m_order > v2.m_order); 245 | } 246 | return (v1.m_specificity > v2.m_specificity); 247 | } 248 | 249 | inline bool operator < (const css_selector& v1, const css_selector& v2) 250 | { 251 | if(v1.m_specificity == v2.m_specificity) 252 | { 253 | return (v1.m_order < v2.m_order); 254 | } 255 | return (v1.m_specificity < v2.m_specificity); 256 | } 257 | 258 | inline bool operator > (const css_selector::ptr& v1, const css_selector::ptr& v2) 259 | { 260 | return (*v1 > *v2); 261 | } 262 | 263 | inline bool operator < (const css_selector::ptr& v1, const css_selector::ptr& v2) 264 | { 265 | return (*v1 < *v2); 266 | } 267 | 268 | ////////////////////////////////////////////////////////////////////////// 269 | 270 | class used_selector 271 | { 272 | public: 273 | typedef std::unique_ptr ptr; 274 | typedef std::vector vector; 275 | 276 | css_selector::ptr m_selector; 277 | bool m_used; 278 | 279 | used_selector(const css_selector::ptr& selector, bool used) 280 | { 281 | m_used = used; 282 | m_selector = selector; 283 | } 284 | 285 | used_selector(const used_selector& val) 286 | { 287 | m_used = val.m_used; 288 | m_selector = val.m_selector; 289 | } 290 | 291 | used_selector& operator=(const used_selector& val) 292 | { 293 | m_used = val.m_used; 294 | m_selector = val.m_selector; 295 | return *this; 296 | } 297 | }; 298 | } 299 | 300 | #endif // LH_CSS_SELECTOR_H 301 | -------------------------------------------------------------------------------- /src/document.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "css_text") 2 | .def_readwrite("text", &lh::css_text::text) 3 | .def_readwrite("baseurl", &lh::css_text::baseurl) 4 | .def_readwrite("media", &lh::css_text::media) 5 | // 6 | .def(py::init<>()) 7 | .def(py::init()) 8 | ; 9 | 10 | py::class_>(m, "dumper") 11 | .def(py::init<>()) 12 | ; 13 | 14 | py::class_>(m, "document") 15 | //document(document_container* objContainer); 16 | //virtual ~document(); 17 | //document_container* container() { return m_container; } 18 | //uint_ptr get_font(const char* name, int size, const char* weight, const char* style, const char* decoration, font_metrics* fm); 19 | .def("render", &lh::document::render) 20 | .def("draw", &lh::document::draw) 21 | //web_color get_def_color() { return m_def_color; } 22 | //int to_pixels(const char* str, int fontSize, bool* is_percent = nullptr) const; 23 | //void cvt_units(css_length& val, int fontSize, int size = 0) const; 24 | //int to_pixels(const css_length& val, int fontSize, int size = 0) const; 25 | .def("width", &lh::document::width) 26 | .def("height", &lh::document::height) 27 | .def("content_width", &lh::document::content_width) 28 | .def("content_height", &lh::document::content_height) 29 | /* 30 | void add_stylesheet(const char* str, const char* baseurl, const char* media); 31 | */ 32 | .def("on_mouse_over", &lh::document::on_mouse_over) 33 | .def("on_lbutton_down", &lh::document::on_lbutton_down) 34 | .def("on_lbutton_up", &lh::document::on_lbutton_up) 35 | /* 36 | .def("on_lbutton_up", [](py_document &self, int x, int y, int cx, int cy, lh::position::vector& redraw_boxes){ 37 | DebugBreak(); 38 | py::gil_scoped_release release; 39 | bool rc = self.on_lbutton_up(x, y, cx, cy, redraw_boxes); 40 | return rc; 41 | }) 42 | */ 43 | .def("on_mouse_leave", &lh::document::on_mouse_leave) 44 | /* 45 | element::ptr create_element(const char* tag_name, const string_map& attributes); 46 | element::ptr root(); 47 | void get_fixed_boxes(position::vector& fixed_boxes); 48 | void add_fixed_box(const position& pos); 49 | void add_media_list(const media_query_list::ptr& list); 50 | bool media_changed(); 51 | bool lang_changed(); 52 | bool match_lang(const string& lang); 53 | void add_tabular(const std::shared_ptr& el); 54 | element::const_ptr get_over_element() const { return m_over_element; } 55 | 56 | void append_children_from_string(element& parent, const char* str); 57 | void dump(dumper& cout); 58 | */ 59 | .def("dump", &lh::document::dump) 60 | ; 61 | 62 | m.def("fromString", [](py_document_container *container, char *html, const char *master_css = lh::master_css, const char *user_styles = "") { 63 | py::gil_scoped_release release; 64 | if( master_css == nullptr ) 65 | master_css = lh::master_css; 66 | if( user_styles == nullptr ) 67 | user_styles = ""; 68 | #if 1 69 | lh::document::ptr doc = lh::document::createFromString(html, container, master_css, user_styles); 70 | return doc; 71 | #else 72 | auto doc = lh::document::createFromString(html, container, master_css, user_styles); 73 | py::object o = py::cast(doc, py::return_value_policy::reference); 74 | return o; 75 | #endif 76 | }) 77 | ; 78 | -------------------------------------------------------------------------------- /src/document_container.h: -------------------------------------------------------------------------------- 1 | /* 2 | typedef struct 3 | { 4 | unsigned char *current_position; 5 | unsigned char *end_of_array; 6 | } png_stream_to_byte_array_closure_t; 7 | 8 | static cairo_status_t write_png_stream_to_byte_array (void *in_closure, const unsigned char *data, unsigned int length) 9 | { 10 | png_stream_to_byte_array_closure_t *closure = (png_stream_to_byte_array_closure_t *) in_closure; 11 | if ((closure->current_position + length) > (closure->end_of_array)) 12 | return CAIRO_STATUS_WRITE_ERROR; 13 | memcpy (closure->current_position, data, length); 14 | closure->current_position += length; 15 | return CAIRO_STATUS_SUCCESS; 16 | } 17 | 18 | closure.current_position = byte_array; 19 | closure.end_of_array = byte_array + sizeof (byte_array); 20 | cairo_surface_write_to_png_stream (surface, write_png_stream_to_byte_array, &closure); 21 | 22 | */ 23 | py::enum_(m, "mouse_event") 24 | .value("mouse_event_enter", lh::mouse_event::mouse_event_enter) 25 | .value("mouse_event_leave", lh::mouse_event::mouse_event_leave) 26 | ; 27 | 28 | py::class_>(m, "document_container") 29 | .def(py::init<>()) 30 | ; 31 | 32 | #ifdef USE_CAIRO_CONTAINERS 33 | #if 0 34 | py::class_>(m, "container_cairo") 35 | .def(py::init<>()) 36 | ; 37 | #endif 38 | py::class_>(m, "container_cairo_pango") 39 | .def(py::init<>()) 40 | .def("surface", &container_cairo_pango::surface, "width"_a, "height"_a) 41 | .def("save", &container_cairo_pango::save, "fname"_a) 42 | .def("savestream", []( 43 | py_document_container_cairo_pango &self, 44 | const py::function &pyfunc 45 | ) { 46 | cairo_surface_t *surface = self.getsurface(); 47 | cairosavestream_t st; st.pyfunc = pyfunc; 48 | cairo_status_t status = cairo_surface_write_to_png_stream(surface, &cairosavestream, &st); 49 | return (int)status; 50 | }) 51 | .def("clear_images", []( 52 | py_document_container_cairo_pango &self 53 | ) { 54 | return self.clear_images(); 55 | }) 56 | .def("put_image", []( 57 | py_document_container_cairo_pango &self, 58 | const std::string& url, 59 | py::bytearray data, 60 | int width, 61 | int height 62 | ) { 63 | return self.put_image(url, data, width, height); 64 | }) 65 | .def("set_dpi", []( 66 | py_document_container_cairo_pango &self, 67 | int dpi 68 | ) { 69 | self.set_dpi(dpi); 70 | }) 71 | .def("fromString", []( 72 | py_document_container_cairo_pango &self, 73 | char *html, 74 | const char *master_css = lh::master_css, 75 | const char *user_styles = "" 76 | ) { 77 | py::gil_scoped_release release; 78 | if( master_css == nullptr ) 79 | master_css = lh::master_css; 80 | if( user_styles == nullptr ) 81 | user_styles = ""; 82 | lh::document::ptr doc = lh::document::createFromString(html, &self, master_css, user_styles); 83 | return doc; 84 | }) 85 | ; 86 | ; 87 | #endif 88 | -------------------------------------------------------------------------------- /src/element.h: -------------------------------------------------------------------------------- 1 | py::class_>(m, "element") 2 | .def(py::init&>()) 3 | .def("css", &lh::element::css) 4 | .def("in_normal_flow", &lh::element::in_normal_flow) 5 | .def("is_inline", &lh::element::is_inline) 6 | .def("is_inline_box", &lh::element::is_inline_box) 7 | .def("is_block_box", &lh::element::is_block_box) 8 | .def("get_placement", &lh::element::get_placement) 9 | .def("is_positioned", &lh::element::is_positioned) 10 | .def("is_float", &lh::element::is_float) 11 | .def("is_block_formatting_context", &lh::element::is_block_formatting_context) 12 | .def("is_root", &lh::element::is_root) 13 | // .def("parent", &lh::element::parent) 14 | // void parent(const element::ptr& par) 15 | .def("is_table_skip", &lh::element::is_table_skip) 16 | 17 | // std::shared_ptr .def("get_document", &lh::element::get_document) 18 | // const std::list>& .def("children", &lh::element::children) 19 | 20 | // virtual elements_list select_all(const string& selector) 21 | // virtual elements_list select_all(const css_selector& selector) 22 | 23 | // virtual element::ptr select_one(const string& selector) 24 | // virtual element::ptr select_one(const css_selector& selector) 25 | 26 | // virtual bool appendChild(const ptr &el) 27 | // virtual bool removeChild(const ptr &el) 28 | // virtual void .def("clearRecursive", &lh::element::clearRecursive) 29 | 30 | .def("id", &lh::element::id) 31 | .def("tag", &lh::element::tag) 32 | .def("get_tagName", &lh::element::get_tagName) 33 | // virtual void set_tagName(const char* tag); 34 | // virtual void set_data(const char* data); 35 | 36 | // virtual void set_attr(const char* name, const char* val); 37 | // virtual const char* get_attr(const char* name, const char* def = nullptr) const; 38 | // virtual void apply_stylesheet(const litehtml::css& stylesheet); 39 | .def("refresh_styles", &lh::element::refresh_styles) 40 | .def("is_white_space", &lh::element::is_white_space) 41 | .def("is_space", &lh::element::is_space) 42 | .def("is_comment", &lh::element::is_comment) 43 | .def("is_body", &lh::element::is_body) 44 | .def("is_break", &lh::element::is_break) 45 | .def("is_text", &lh::element::is_text) 46 | 47 | .def("on_mouse_over", &lh::element::on_mouse_over) 48 | .def("on_mouse_leave", &lh::element::on_mouse_leave) 49 | .def("on_lbutton_down", &lh::element::on_lbutton_down) 50 | .def("on_lbutton_up", &lh::element::on_lbutton_up) 51 | .def("on_click", &lh::element::on_click) 52 | // virtual bool set_pseudo_class(string_id cls, bool add); 53 | // virtual bool set_class(const char* pclass, bool add); 54 | .def("is_replaced", &lh::element::is_replaced) 55 | // virtual void compute_styles(bool recursive = true); 56 | // virtual void draw(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr& ri); 57 | // virtual void draw_background(uint_ptr hdc, int x, int y, const position *clip, const std::shared_ptr &ri); 58 | // virtual int get_enum_property (string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const; 59 | // virtual int get_int_property (string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const; 60 | // virtual css_length get_length_property(string_id name, bool inherited, css_length default_value, uint_ptr css_properties_member_offset) const; 61 | // virtual web_color get_color_property (string_id name, bool inherited, web_color default_value, uint_ptr css_properties_member_offset) const; 62 | // virtual string get_string_property(string_id name, bool inherited, const string& default_value, uint_ptr css_properties_member_offset) const; 63 | // virtual float get_number_property(string_id name, bool inherited, float default_value, uint_ptr css_properties_member_offset) const; 64 | // virtual string_vector get_string_vector_property(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const; 65 | // virtual int_vector get_int_vector_property (string_id name, bool inherited, const int_vector& default_value, uint_ptr css_properties_member_offset) const; 66 | // virtual length_vector get_length_vector_property(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const; 67 | // virtual size_vector get_size_vector_property (string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const; 68 | // virtual string get_custom_property(string_id name, const string& default_value) const; 69 | 70 | // virtual void get_text(string& text); 71 | // virtual void parse_attributes(); 72 | // virtual int select(const string& selector); 73 | // virtual int select(const css_selector& selector, bool apply_pseudo = true); 74 | // virtual int select(const css_element_selector& selector, bool apply_pseudo = true); 75 | // virtual element::ptr find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr); 76 | // virtual bool is_ancestor(const ptr &el) const; 77 | // virtual element::ptr find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr); 78 | // virtual element::ptr find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr); 79 | // virtual void get_content_size(size& sz, int max_width); 80 | // virtual bool is_nth_child(const element::ptr& el, int num, int off, bool of_type) const; 81 | // virtual bool is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const; 82 | // virtual bool is_only_child(const element::ptr& el, bool of_type) const; 83 | // virtual void add_style(const style& style); 84 | // virtual const background* get_background(bool own_only = false); 85 | 86 | // virtual string dump_get_name(); 87 | // virtual std::vector> dump_get_attrs(); 88 | // void dump(litehtml::dumper& cout); 89 | 90 | // std::tuple split_inlines(); 91 | // virtual std::shared_ptr create_render_item(const std::shared_ptr& parent_ri); 92 | // bool requires_styles_update(); 93 | // void add_render(const std::shared_ptr& ri); 94 | // bool find_styles_changes( position::vector& redraw_boxes); 95 | // element::ptr add_pseudo_before(const style& style) 96 | // element::ptr add_pseudo_after(const style& style) 97 | // string get_counter_value(const string& counter_name); 98 | // string get_counters_value(const string_vector& parameters); 99 | // void increment_counter(const string_id& counter_name_id, const int increment = 1); 100 | // void reset_counter(const string_id& counter_name_id, const int value = 0); 101 | ; 102 | -------------------------------------------------------------------------------- /src/flex_item.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_FLEX_ITEM_H 2 | #define LITEHTML_FLEX_ITEM_H 3 | 4 | #include 5 | #include "formatting_context.h" 6 | 7 | namespace litehtml 8 | { 9 | class flex_line; 10 | 11 | /** 12 | * Base class for flex item 13 | */ 14 | class flex_item 15 | { 16 | public: 17 | std::shared_ptr el; 18 | int base_size; 19 | int min_size; 20 | def_value max_size; 21 | int main_size; 22 | int grow; 23 | int shrink; 24 | int scaled_flex_shrink_factor; 25 | bool frozen; 26 | int order; 27 | int src_order; 28 | def_value auto_margin_main_start; 29 | def_value auto_margin_main_end; 30 | bool auto_margin_cross_start; 31 | bool auto_margin_cross_end; 32 | flex_align_items align; 33 | 34 | explicit flex_item(std::shared_ptr &_el) : 35 | el(_el), 36 | base_size(0), 37 | min_size(0), 38 | max_size(0), 39 | main_size(0), 40 | grow(0), 41 | shrink(0), 42 | scaled_flex_shrink_factor(0), 43 | frozen(false), 44 | order(0), 45 | src_order(0), 46 | auto_margin_main_start(0), 47 | auto_margin_main_end(0), 48 | auto_margin_cross_start(false), 49 | auto_margin_cross_end(false), 50 | align(flex_align_items_auto) 51 | {} 52 | 53 | virtual ~flex_item() = default; 54 | 55 | bool operator<(const flex_item& b) const 56 | { 57 | if(order < b.order) return true; 58 | if(order == b.order) return src_order < b.src_order; 59 | return false; 60 | } 61 | void init(const litehtml::containing_block_context &self_size, 62 | litehtml::formatting_context *fmt_ctx, flex_align_items align_items); 63 | virtual void apply_main_auto_margins() = 0; 64 | virtual bool apply_cross_auto_margins(int cross_size) = 0; 65 | virtual void set_main_position(int pos) = 0; 66 | virtual void set_cross_position(int pos) = 0; 67 | virtual int get_el_main_size() = 0; 68 | virtual int get_el_cross_size() = 0; 69 | 70 | void place(flex_line &ln, int main_pos, 71 | const containing_block_context &self_size, 72 | formatting_context *fmt_ctx); 73 | int get_last_baseline(baseline::_baseline_type type) const; 74 | int get_first_baseline(baseline::_baseline_type type) const; 75 | 76 | protected: 77 | virtual void direction_specific_init(const litehtml::containing_block_context &self_size, 78 | litehtml::formatting_context *fmt_ctx) = 0; 79 | virtual void align_stretch(flex_line &ln, const containing_block_context &self_size, 80 | formatting_context *fmt_ctx) = 0; 81 | virtual void align_baseline(flex_line &ln, 82 | const containing_block_context &self_size, 83 | formatting_context *fmt_ctx) = 0; 84 | }; 85 | 86 | /** 87 | * Flex item with "flex-direction: row" or " flex-direction: row-reverse" 88 | */ 89 | class flex_item_row_direction : public flex_item 90 | { 91 | public: 92 | explicit flex_item_row_direction(std::shared_ptr &_el) : flex_item(_el) {} 93 | 94 | void apply_main_auto_margins() override; 95 | bool apply_cross_auto_margins(int cross_size) override; 96 | void set_main_position(int pos) override; 97 | void set_cross_position(int pos) override; 98 | int get_el_main_size() override; 99 | int get_el_cross_size() override; 100 | 101 | protected: 102 | void direction_specific_init(const litehtml::containing_block_context &self_size, 103 | litehtml::formatting_context *fmt_ctx) override; 104 | void align_stretch(flex_line &ln, const containing_block_context &self_size, 105 | formatting_context *fmt_ctx) override; 106 | void align_baseline(flex_line &ln, 107 | const containing_block_context &self_size, 108 | formatting_context *fmt_ctx) override; 109 | }; 110 | 111 | /** 112 | * Flex item with "flex-direction: column" or " flex-direction: column-reverse" 113 | */ 114 | class flex_item_column_direction : public flex_item 115 | { 116 | public: 117 | explicit flex_item_column_direction(std::shared_ptr &_el) : flex_item(_el) {} 118 | 119 | void apply_main_auto_margins() override; 120 | bool apply_cross_auto_margins(int cross_size) override; 121 | void set_main_position(int pos) override; 122 | void set_cross_position(int pos) override; 123 | int get_el_main_size() override; 124 | int get_el_cross_size() override; 125 | 126 | protected: 127 | void direction_specific_init(const litehtml::containing_block_context &self_size, 128 | litehtml::formatting_context *fmt_ctx) override; 129 | void align_stretch(flex_line &ln, const containing_block_context &self_size, 130 | formatting_context *fmt_ctx) override; 131 | void align_baseline(flex_line &ln, 132 | const containing_block_context &self_size, 133 | formatting_context *fmt_ctx) override; 134 | }; 135 | } 136 | 137 | #endif //LITEHTML_FLEX_ITEM_H 138 | -------------------------------------------------------------------------------- /src/flex_line.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_FLEX_LINE_H 2 | #define LITEHTML_FLEX_LINE_H 3 | 4 | #include "formatting_context.h" 5 | 6 | namespace litehtml 7 | { 8 | class flex_item; 9 | 10 | class flex_line 11 | { 12 | public: 13 | std::list> items; 14 | int cross_start; // for row direction: top. for column direction: left 15 | int main_size; // sum of all items main size 16 | int cross_size; // sum of all items cross size 17 | int base_size; 18 | int total_grow; 19 | int total_shrink; 20 | int num_auto_margin_main_start; // number of items with auto margin left/top 21 | int num_auto_margin_main_end; // number of items with auto margin right/bottom 22 | baseline first_baseline; 23 | baseline last_baseline; 24 | bool reverse_main; 25 | bool reverse_cross; 26 | 27 | flex_line(bool _reverse_main, bool _reverse_cross) : 28 | cross_start(0), 29 | main_size(0), 30 | cross_size(0), 31 | base_size(0), 32 | total_grow(0), 33 | total_shrink(0), 34 | num_auto_margin_main_start(0), 35 | num_auto_margin_main_end(0), 36 | first_baseline(), 37 | last_baseline(), 38 | reverse_main(_reverse_main), 39 | reverse_cross(_reverse_cross) 40 | {} 41 | 42 | void init(int container_main_size, bool fit_container, bool is_row_direction, 43 | const litehtml::containing_block_context &self_size, 44 | litehtml::formatting_context *fmt_ctx); 45 | bool distribute_main_auto_margins(int free_main_size); 46 | int calculate_items_position(int container_main_size, 47 | flex_justify_content justify_content, 48 | bool is_row_direction, 49 | const containing_block_context &self_size, 50 | formatting_context *fmt_ctx); 51 | protected: 52 | void distribute_free_space(int container_main_size); 53 | }; 54 | } 55 | 56 | #endif //LITEHTML_FLEX_LINE_H 57 | -------------------------------------------------------------------------------- /src/font_description.h: -------------------------------------------------------------------------------- 1 | py::class_(m, "font_description") 2 | .def_readwrite("family", &lh::font_description::family) 3 | .def_readwrite("size", &lh::font_description::size) 4 | .def_readwrite("style", &lh::font_description::style) 5 | .def_readwrite("weight", &lh::font_description::weight) 6 | .def_readwrite("decoration_line", &lh::font_description::decoration_line) 7 | .def_readwrite("decoration_thickness", &lh::font_description::decoration_thickness) 8 | .def_readwrite("decoration_style", &lh::font_description::decoration_style) 9 | .def_readwrite("decoration_color", &lh::font_description::decoration_color) 10 | // 11 | .def(py::init<>()) 12 | ; 13 | 14 | -------------------------------------------------------------------------------- /src/formatting_context.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_FLOATS_HOLDER_H 2 | #define LITEHTML_FLOATS_HOLDER_H 3 | 4 | #include 5 | #include "types.h" 6 | 7 | namespace litehtml 8 | { 9 | class formatting_context 10 | { 11 | private: 12 | std::list m_floats_left; 13 | std::list m_floats_right; 14 | int_int_cache m_cache_line_left; 15 | int_int_cache m_cache_line_right; 16 | int m_current_top; 17 | int m_current_left; 18 | 19 | public: 20 | formatting_context() : m_current_top(0), m_current_left(0) {} 21 | 22 | void push_position(int x, int y) 23 | { 24 | m_current_left += x; 25 | m_current_top += y; 26 | } 27 | void pop_position(int x, int y) 28 | { 29 | m_current_left -= x; 30 | m_current_top -= y; 31 | } 32 | 33 | void add_float(const std::shared_ptr &el, int min_width, int context); 34 | void clear_floats(int context); 35 | int find_next_line_top( int top, int width, int def_right ); 36 | int get_floats_height(element_float el_float = float_none) const; 37 | int get_left_floats_height() const; 38 | int get_right_floats_height() const; 39 | int get_line_left( int y ); 40 | void get_line_left_right( int y, int def_right, int& ln_left, int& ln_right ) 41 | { 42 | ln_left = get_line_left(y); 43 | ln_right = get_line_right(y, def_right); 44 | } 45 | int get_line_right( int y, int def_right ); 46 | int get_cleared_top(const std::shared_ptr &el, int line_top) const; 47 | void update_floats(int dy, const std::shared_ptr &parent); 48 | void apply_relative_shift(const containing_block_context &containing_block_size); 49 | int find_min_left(int y, int context_idx); 50 | int find_min_right(int y, int right, int context_idx); 51 | }; 52 | } 53 | 54 | #endif //LITEHTML_FLOATS_HOLDER_H 55 | -------------------------------------------------------------------------------- /src/html.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_HTML_H 2 | #define LH_HTML_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "os_types.h" 13 | #include "string_id.h" 14 | #include "types.h" 15 | #include "utf8_strings.h" 16 | #include "background.h" 17 | #include "borders.h" 18 | #include "web_color.h" 19 | #include "media_query.h" 20 | #include "html_tag.h" 21 | #include "document_container.h" 22 | #include "document.h" 23 | 24 | namespace litehtml 25 | { 26 | void trim(string &s, const string& chars_to_trim = " \n\r\t"); 27 | void lcase(string &s); 28 | int value_index(const string& val, const string& strings, int defValue = -1, char delim = ';'); 29 | string index_value(int index, const string& strings, char delim = ';'); 30 | bool value_in_list(const string& val, const string& strings, char delim = ';'); 31 | string::size_type find_close_bracket(const string &s, string::size_type off, char open_b = '(', char close_b = ')'); 32 | void split_string(const string& str, string_vector& tokens, const string& delims, const string& delims_preserve = "", const string& quote = "\""); 33 | void join_string(string& str, const string_vector& tokens, const string& delims); 34 | double t_strtod(const char* string, char** endPtr = nullptr); 35 | string get_escaped_string(const string& in_str); 36 | 37 | int t_strcasecmp(const char *s1, const char *s2); 38 | int t_strncasecmp(const char *s1, const char *s2, size_t n); 39 | 40 | bool is_number(const string& string, const bool allow_dot = 1); 41 | 42 | inline int t_isdigit(int c) 43 | { 44 | return (c >= '0' && c <= '9'); 45 | } 46 | 47 | inline int t_isalpha(int c) 48 | { 49 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); 50 | } 51 | 52 | inline int t_tolower(int c) 53 | { 54 | return (c >= 'A' && c <= 'Z' ? c + 'a' - 'A' : c); 55 | } 56 | 57 | inline int round_f(float val) 58 | { 59 | int int_val = (int) val; 60 | if(val - int_val >= 0.5) 61 | { 62 | int_val++; 63 | } 64 | return int_val; 65 | } 66 | 67 | inline int round_d(double val) 68 | { 69 | int int_val = (int) val; 70 | if(val - int_val >= 0.5) 71 | { 72 | int_val++; 73 | } 74 | return int_val; 75 | } 76 | 77 | inline float t_strtof(const string& str, char** endPtr = nullptr) 78 | { 79 | return (float)t_strtod(str.c_str(), endPtr); 80 | } 81 | 82 | inline int baseline_align(int line_height, int line_base_line, int height, int baseline) 83 | { 84 | return (line_height - line_base_line) - (height - baseline); 85 | } 86 | } 87 | 88 | #endif // LH_HTML_H 89 | -------------------------------------------------------------------------------- /src/html_tag.h: -------------------------------------------------------------------------------- 1 | py::class_>(m, "html_tag") 2 | /* 3 | protected: 4 | string_id m_tag; 5 | string_id m_id; 6 | string_vector m_str_classes; 7 | std::vector m_classes; 8 | litehtml::style m_style; 9 | string_map m_attrs; 10 | std::vector m_pseudo_classes; 11 | 12 | void select_all(const css_selector& selector, elements_list& res) override; 13 | public 14 | */ 15 | .def(py::init&>()) 16 | //.def(py::init<(const lh::element::ptr& parent, const lh::string& style = "display: block")>()) 17 | /* 18 | bool appendChild(const element::ptr &el) override; 19 | bool removeChild(const element::ptr &el) override; 20 | void clearRecursive() override; 21 | string_id tag() const override; 22 | string_id id() const override; 23 | */ 24 | .def("get_tagName",&lh::html_tag::get_tagName) 25 | /* 26 | void set_tagName(const char* tag) override; 27 | void set_data(const char* data) override; 28 | void set_attr(const char* name, const char* val) override; 29 | const char* get_attr(const char* name, const char* def = nullptr) const override; 30 | void apply_stylesheet(const litehtml::css& stylesheet) override; 31 | void refresh_styles() override; 32 | 33 | bool is_white_space() const override; 34 | bool is_body() const override; 35 | bool is_break() const override; 36 | 37 | bool on_mouse_over() override; 38 | bool on_mouse_leave() override; 39 | bool on_lbutton_down() override; 40 | bool on_lbutton_up() override; 41 | void on_click() override; 42 | bool set_pseudo_class(string_id cls, bool add) override; 43 | bool set_class(const char* pclass, bool add) override; 44 | bool is_replaced() const override; 45 | void compute_styles(bool recursive = true) override; 46 | */ 47 | .def("draw", &lh::html_tag::draw) 48 | .def("draw_background", &lh::html_tag::draw_background) 49 | /* 50 | template 51 | const Type& get_property_impl (string_id name, bool inherited, const Type& default_value, uint_ptr css_properties_member_offset) const; 52 | int get_enum_property (string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const override; 53 | int get_int_property (string_id name, bool inherited, int default_value, uint_ptr css_properties_member_offset) const override; 54 | css_length get_length_property(string_id name, bool inherited, css_length default_value, uint_ptr css_properties_member_offset) const override; 55 | web_color get_color_property (string_id name, bool inherited, web_color default_value, uint_ptr css_properties_member_offset) const override; 56 | string get_string_property(string_id name, bool inherited, const string& default_value, uint_ptr css_properties_member_offset) const override; 57 | float get_number_property(string_id name, bool inherited, float default_value, uint_ptr css_properties_member_offset) const override; 58 | string_vector get_string_vector_property(string_id name, bool inherited, const string_vector& default_value, uint_ptr css_properties_member_offset) const override; 59 | int_vector get_int_vector_property (string_id name, bool inherited, const int_vector& default_value, uint_ptr css_properties_member_offset) const override; 60 | length_vector get_length_vector_property(string_id name, bool inherited, const length_vector& default_value, uint_ptr css_properties_member_offset) const override; 61 | size_vector get_size_vector_property (string_id name, bool inherited, const size_vector& default_value, uint_ptr css_properties_member_offset) const override; 62 | string get_custom_property(string_id name, const string& default_value) const override; 63 | 64 | elements_list& children(); 65 | 66 | int select(const string& selector) override; 67 | int select(const css_selector& selector, bool apply_pseudo = true) override; 68 | int select(const css_element_selector& selector, bool apply_pseudo = true) override; 69 | int select_pseudoclass(const css_attribute_selector& sel); 70 | int select_attribute(const css_attribute_selector& sel); 71 | 72 | elements_list select_all(const string& selector) override; 73 | elements_list select_all(const css_selector& selector) override; 74 | 75 | element::ptr select_one(const string& selector) override; 76 | element::ptr select_one(const css_selector& selector) override; 77 | 78 | element::ptr find_ancestor(const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr) override; 79 | element::ptr find_adjacent_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr) override; 80 | element::ptr find_sibling(const element::ptr& el, const css_selector& selector, bool apply_pseudo = true, bool* is_pseudo = nullptr) override; 81 | void get_text(string& text) override; 82 | void parse_attributes() override; 83 | 84 | void get_content_size(size& sz, int max_width) override; 85 | void add_style(const style& style) override; 86 | 87 | bool is_nth_child(const element::ptr& el, int num, int off, bool of_type) const override; 88 | bool is_nth_last_child(const element::ptr& el, int num, int off, bool of_type) const override; 89 | bool is_only_child(const element::ptr& el, bool of_type) const override; 90 | const background* get_background(bool own_only = false) override; 91 | 92 | string dump_get_name() override; 93 | 94 | protected: 95 | void init_background_paint(position pos, std::vector& bg_paint, const background* bg, const std::shared_ptr& ri); 96 | void init_one_background_paint(int i, position pos, background_paint& bg_paint, const background* bg, const std::shared_ptr& ri); 97 | void draw_list_marker( uint_ptr hdc, const position &pos ); 98 | string get_list_marker_text(int index); 99 | element::ptr get_element_before(const style& style, bool create); 100 | element::ptr get_element_after(const style& style, bool create); 101 | 102 | private: 103 | void handle_counter_properties(); 104 | public: 105 | */ 106 | // .def("get_placement", &lh::element::get_placement) 107 | .def("get_placement", &lh::html_tag::get_placement) 108 | ; 109 | -------------------------------------------------------------------------------- /src/iterators.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_ITERATORS_H 2 | #define LH_ITERATORS_H 3 | 4 | #include "types.h" 5 | #include 6 | #include 7 | 8 | namespace litehtml 9 | { 10 | class render_item; 11 | 12 | class iterator_selector 13 | { 14 | public: 15 | virtual bool select(const std::shared_ptr& el) = 0; 16 | 17 | protected: 18 | ~iterator_selector() = default; 19 | }; 20 | 21 | enum iterator_item_type 22 | { 23 | iterator_item_type_child, 24 | iterator_item_type_start_parent, 25 | iterator_item_type_end_parent 26 | }; 27 | 28 | class elements_iterator 29 | { 30 | private: 31 | iterator_selector* m_go_inside; 32 | iterator_selector* m_select; 33 | bool m_return_parent; 34 | 35 | /** 36 | * Checks if iterator should go inside the element 37 | * 38 | * @param el element to check 39 | * @return true to go inside 40 | */ 41 | bool go_inside(const std::shared_ptr& el); 42 | 43 | public: 44 | elements_iterator(bool return_parents, iterator_selector* go_inside, iterator_selector* select); 45 | ~elements_iterator() = default; 46 | 47 | void process(const std::shared_ptr& container, const std::function&, iterator_item_type)>& func); 48 | 49 | private: 50 | void next_idx(); 51 | }; 52 | 53 | class go_inside_inline final : public iterator_selector 54 | { 55 | public: 56 | bool select(const std::shared_ptr& el) override; 57 | }; 58 | 59 | class inline_selector final : public iterator_selector 60 | { 61 | public: 62 | bool select(const std::shared_ptr& el) override; 63 | }; 64 | 65 | class go_inside_table final : public iterator_selector 66 | { 67 | public: 68 | bool select(const std::shared_ptr& el) override; 69 | }; 70 | 71 | class table_rows_selector final : public iterator_selector 72 | { 73 | public: 74 | bool select(const std::shared_ptr& el) override; 75 | }; 76 | 77 | class table_cells_selector final : public iterator_selector 78 | { 79 | public: 80 | bool select(const std::shared_ptr& el) override; 81 | }; 82 | } 83 | 84 | #endif // LH_ITERATORS_H 85 | -------------------------------------------------------------------------------- /src/line_box.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_LINE_BOX_H 2 | #define LH_LINE_BOX_H 3 | 4 | #include 5 | #include 6 | #include "os_types.h" 7 | #include "types.h" 8 | 9 | namespace litehtml 10 | { 11 | class render_item; 12 | 13 | struct line_context 14 | { 15 | int calculatedTop; 16 | int top; 17 | int left; 18 | int right; 19 | 20 | int width() const 21 | { 22 | return right - left; 23 | } 24 | void fix_top() 25 | { 26 | calculatedTop = top; 27 | } 28 | line_context() : calculatedTop(0), top(0), left(0), right(0) {} 29 | }; 30 | 31 | class line_box_item 32 | { 33 | public: 34 | enum element_type 35 | { 36 | type_text_part, 37 | type_inline_start, 38 | type_inline_continue, 39 | type_inline_end 40 | }; 41 | protected: 42 | std::shared_ptr m_element; 43 | int m_rendered_min_width; 44 | public: 45 | explicit line_box_item(const std::shared_ptr& element) : m_element(element), m_rendered_min_width(0) {} 46 | line_box_item() : m_element(), m_rendered_min_width(0) {}; 47 | line_box_item(const line_box_item& el) = default; 48 | line_box_item(line_box_item&&) = default; 49 | 50 | int height() const { return right() - left(); } 51 | const std::shared_ptr& get_el() const { return m_element; } 52 | virtual position& pos(); 53 | virtual void place_to(int x, int y); 54 | virtual int width() const; 55 | virtual int top() const; 56 | virtual int bottom() const; 57 | virtual int right() const; 58 | virtual int left() const; 59 | virtual element_type get_type() const { return type_text_part; } 60 | virtual int get_rendered_min_width() const { return m_rendered_min_width; } 61 | virtual void set_rendered_min_width(int min_width) { m_rendered_min_width = min_width; } 62 | }; 63 | 64 | class lbi_start : public line_box_item 65 | { 66 | protected: 67 | position m_pos; 68 | public: 69 | explicit lbi_start(const std::shared_ptr& element); 70 | 71 | void place_to(int x, int y) override; 72 | int width() const override; 73 | position& pos() override { return m_pos; } 74 | int top() const override; 75 | int bottom() const override; 76 | int right() const override; 77 | int left() const override; 78 | element_type get_type() const override { return type_inline_start; } 79 | int get_rendered_min_width() const override { return width(); } 80 | }; 81 | 82 | class lbi_end : public lbi_start 83 | { 84 | public: 85 | explicit lbi_end(const std::shared_ptr& element); 86 | 87 | void place_to(int x, int y) override; 88 | int right() const override; 89 | int left() const override; 90 | element_type get_type() const override { return type_inline_end; } 91 | }; 92 | 93 | class lbi_continue : public lbi_start 94 | { 95 | public: 96 | explicit lbi_continue(const std::shared_ptr& element); 97 | 98 | void place_to(int x, int y) override; 99 | int right() const override; 100 | int left() const override; 101 | int width() const override; 102 | element_type get_type() const override { return type_inline_continue; } 103 | }; 104 | 105 | class line_box 106 | { 107 | struct va_context 108 | { 109 | int baseline; 110 | font_metrics fm; 111 | 112 | va_context() : baseline(0) {} 113 | }; 114 | 115 | int m_top; 116 | int m_left; 117 | int m_right; 118 | int m_height; 119 | int m_width; 120 | int m_line_height; 121 | int m_default_line_height; 122 | font_metrics m_font_metrics; 123 | int m_baseline; 124 | text_align m_text_align; 125 | int m_min_width; 126 | std::list< std::unique_ptr > m_items; 127 | public: 128 | line_box(int top, int left, int right, int line_height, const font_metrics& fm, text_align align) : 129 | m_top(top), 130 | m_left(left), 131 | m_right(right), 132 | m_height(0), 133 | m_width(0), 134 | m_line_height(0), 135 | m_default_line_height(line_height), 136 | m_font_metrics(fm), 137 | m_baseline(0), 138 | m_text_align(align), 139 | m_min_width(0) 140 | { 141 | } 142 | 143 | int bottom() const { return m_top + height(); } 144 | int top() const { return m_top; } 145 | int right() const { return m_left + width(); } 146 | int left() const { return m_left; } 147 | int height() const { return m_height; } 148 | int width() const { return m_width; } 149 | int line_right() const { return m_right; } 150 | int min_width() const { return m_min_width; } 151 | 152 | void add_item(std::unique_ptr item); 153 | bool can_hold(const std::unique_ptr& item, white_space ws) const; 154 | bool is_empty() const; 155 | int baseline() const; 156 | int top_margin() const; 157 | int bottom_margin() const; 158 | void y_shift(int shift); 159 | std::list< std::unique_ptr > finish(bool last_box, const containing_block_context &containing_block_size); 160 | std::list< std::unique_ptr > new_width(int left, int right); 161 | std::shared_ptr get_last_text_part() const; 162 | std::shared_ptr get_first_text_part() const; 163 | std::list< std::unique_ptr >& items() { return m_items; } 164 | private: 165 | bool have_last_space() const; 166 | bool is_break_only() const; 167 | static int calc_va_baseline(const va_context& current, vertical_align va, const font_metrics& new_font, int top, int bottom); 168 | }; 169 | } 170 | 171 | #endif //LH_LINE_BOX_H 172 | -------------------------------------------------------------------------------- /src/litehtml.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_H 2 | #define LITEHTML_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #endif // LITEHTML_H 12 | -------------------------------------------------------------------------------- /src/litehtmlpy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m32/litehtmlpy/a2140803b8752e6e8b38a784b4a5bc267bc469f6/src/litehtmlpy/__init__.py -------------------------------------------------------------------------------- /src/litehtmlpy/litehtml.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from . import litehtmlpy 3 | 4 | logger = logging.getLogger(__name__) 5 | 6 | class document_container(litehtmlpy.document_container): 7 | def __init__(self): 8 | #super().__init__() 9 | litehtmlpy.document_container.__init__(self) 10 | self.hfont = 0 11 | self.fonts = {} 12 | v = 3.96 * 96 / 72 13 | self.size = [int(210 * v), int(297 * v)] 14 | self.ppi = (96, 96) 15 | self.clips = [] 16 | 17 | def create_font(self, descr): 18 | logger.debug('create_font(%s)', descr) 19 | self.hfont += 1 20 | self.fonts[self.hfont] = None 21 | return [self.hfont, 15, 4, 19, 19] 22 | 23 | def delete_font(self, hFont): 24 | logger.debug('delete_font(%d)', hFont) 25 | del self.fonts[hFont] 26 | 27 | def text_width(self, text, hFont): 28 | logger.debug('text_width(%s, %s)', text, hFont) 29 | return len(text)*12 30 | 31 | def draw_text(self, hdc, text, hFont, color, pos): 32 | logger.debug('draw_text(%d, %s, %d, %s, %s)', hdc, text, hFont, color, pos) 33 | 34 | def pt_to_px(self, pt): 35 | logger.debug('pt_to_px(%d)', pt) 36 | pt = int(pt * self.ppi[1] / 72) 37 | return pt 38 | 39 | def get_default_font_size(self): 40 | return 12 41 | 42 | def get_default_font_name(self): 43 | return 'Times New Roman' 44 | 45 | def draw_list_marker(self, hdc, marker): 46 | logger.debug('draw_list_marker(%d, %s)', hdc, marker) 47 | 48 | def load_image(self, src, baseurl, redraw_on_ready): 49 | logger.debug('load_image(%s, %s, %s)', src, baseurl, redraw_on_ready) 50 | 51 | def get_image_size(self, src, baseurl, size): 52 | logger.debug('get_image_size(%s, %s)', src, baseurl) 53 | size.width = 0 54 | size.height = 0 55 | 56 | def draw_image(self, hdc, layer, url, base_url): 57 | logger.debug('draw_image(%d, %s, %s, %s)', hdc, layer, url, base_url) 58 | 59 | def draw_solid_fill(self, hdc, layer, color): 60 | logger.debug('draw_solid_fill(%d, %s, %s)', hdc, layer, color) 61 | 62 | def draw_linear_gradient(self, hdc, layer, gradient): 63 | logger.debug('draw_linear_gradient(%d, %s, %s)', hdc, layer, gradient) 64 | 65 | def draw_radial_gradient(self, hdc, layer, gradient): 66 | logger.debug('draw_radial_gradient(%d, %s, %s)', hdc, layer, gradient) 67 | 68 | def draw_conic_gradient(self, hdc, layer, gradient): 69 | logger.debug('draw_conic_gradient(%d, %s, %s)', hdc, layer, gradient) 70 | 71 | def draw_borders(self, hdc, borders, draw_pos, root): 72 | logger.debug('draw_borders(%d, %s, %s, %s)', hdc, borders, draw_pos, root) 73 | 74 | def set_caption(self, caption): 75 | logger.debug('set_caption(%s)', caption) 76 | 77 | def set_base_url(self, url): 78 | logger.debug('set_base_url(%s)', url) 79 | 80 | #void link(const std::shared_ptr& doc, const element::ptr& el) override 81 | 82 | #void on_anchor_click(const char* url, const element::ptr& el) override 83 | def on_mouse_event(self, el, event): 84 | logger.debug('on_mouse_event(%s, %s)', el, event) 85 | 86 | def set_cursor(self, cursor): 87 | logger.debug('set_cursor(%s)', cursor) 88 | 89 | def transform_text(self, text, tt): 90 | logger.debug('transform_text(%s, %d)', text, tt) 91 | 92 | def import_css(self, text, url, base_url): 93 | logger.debug('import_css(%s, %s, %s)', text, url, base_url) 94 | 95 | def set_clip(self, pos, radius): 96 | logger.debug('set_clip(%s, %s)', pos, radius) 97 | self.clips.push((pos, radius)) 98 | 99 | def del_clip(self): 100 | logger.debug('del_clip()') 101 | if self.clips: 102 | self.clips.pop() 103 | 104 | def get_client_rect(self, client): 105 | logger.debug('get_client_rect(%s, %s, %s, %s)', client.x, client.y, client.width, client.height) 106 | client.clear() 107 | client.width = self.size[0] 108 | client.height = self.size[1] 109 | 110 | #element::ptr create_element( const char* tag_name, const string_map& attributes, const std::shared_ptr& doc) override 111 | 112 | def get_media_features(self): 113 | logger.debug('get_media_features()') 114 | return ( 115 | 2, # media_type_screen 116 | self.size[0], 117 | self.size[1], 118 | 1024, # device width (screen width) 119 | 800, # device height (screen height) 120 | 8, # color 121 | 0, # monochrome 122 | 0, # color index 123 | 96, # resolution 124 | ) 125 | 126 | def get_language(self): 127 | logger.debug('get_language()') 128 | return ('en', '') 129 | -------------------------------------------------------------------------------- /src/litehtmlpy/litehtmlpango.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import logging 3 | from . import litehtmlpy 4 | 5 | logger = logging.getLogger(__name__) 6 | 7 | class document_container(litehtmlpy.container_cairo_pango): 8 | def __init__(self, parent=None): 9 | super().__init__() 10 | self.parent = parent 11 | v = 3.96 * 96 / 72 12 | self.set_dpi(96) 13 | self.size = [int(210 * v), int(297 * v)] 14 | 15 | def get_screen_width(self): 16 | return self.size[0] 17 | 18 | def get_screen_height(self): 19 | return self.size[1] 20 | 21 | def load_image(self, src, baseurl, redraw_on_ready): 22 | logger.debug('load_image(%s, %s, %s)', src, baseurl, redraw_on_ready) 23 | if self.parent is not None: 24 | self.parent.HtmlLoadImage(self, src, baseurl, redraw_on_ready) 25 | 26 | def set_caption(self, caption): 27 | logger.debug('set_caption(%s)', caption) 28 | 29 | def set_base_url(self, url): 30 | logger.debug('set_base_url(%s)', url) 31 | 32 | ##void link(const std::shared_ptr& doc, const element::ptr& el) override 33 | 34 | #void on_anchor_click(const char* url, const element::ptr& el) override 35 | def on_mouse_event(self, el, event): 36 | logger.debug('on_mouse_event(%s, %s)', el, event) 37 | 38 | def set_cursor(self, cursor): 39 | logger.debug('set_cursor(%s)', cursor) 40 | 41 | def import_css(self, text, url, base_url): 42 | logger.debug('import_css(%s, %s, %s)', text, url, base_url) 43 | 44 | def get_client_rect(self, client): 45 | #logger.debug('get_client_rect(%s)'%client) 46 | client.clear() 47 | client.width = self.size[0] 48 | client.height = self.size[1] 49 | -------------------------------------------------------------------------------- /src/litehtmlpy/litehtmlwx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env vpython3 2 | import logging 3 | import wx 4 | from . import litehtmlpy 5 | 6 | logger = logging.getLogger(__name__) 7 | 8 | class document_container(litehtmlpy.document_container): 9 | def __init__(self, parent=None): 10 | #super().__init__() 11 | litehtmlpy.document_container.__init__(self) 12 | self.parent = parent 13 | self.hfont = 0 14 | self.fonts = {} 15 | v = 3.96 * 96 / 72 16 | self.size = [int(210 * v), int(297 * v)] 17 | self.clips = [] 18 | self.dc = None 19 | 20 | def SetDC(self, dc): 21 | self.dc = dc 22 | 23 | def reset(self): 24 | self.bmp = wx.Bitmap(self.size[0], self.size[1], 32) 25 | self.dc = wx.MemoryDC() 26 | self.dc.SelectObject(self.bmp) 27 | self.dc.SetBackground(wx.Brush(wx.WHITE)) 28 | self.dc.Clear() 29 | self.ppi = self.dc.GetPPI() 30 | 31 | def create_font(self, descr): 32 | face = descr.family 33 | size = descr.size 34 | weight = descr.weight 35 | italic = descr.style == litehtmlpy.font_style_italic 36 | #decoration = descr.decoration_style 37 | decoration = 0 38 | #logger.debug('create_font(%s)', face, size, weight, italic, decoration) 39 | if not face: 40 | face = 'Times New Roman' 41 | else: 42 | face = face.split(',')[0].strip() 43 | if face[0] == '"': 44 | face = face.split('"')[1] 45 | elif face[0] == "'": 46 | face = face.split("'")[1] 47 | if italic: 48 | style = wx.FONTSTYLE_ITALIC 49 | else: 50 | style = wx.FONTSTYLE_NORMAL 51 | try: 52 | wx.FONTWEIGHT_THIN 53 | weigths = { 54 | 100:wx.FONTWEIGHT_THIN, 55 | 200:wx.FONTWEIGHT_EXTRALIGHT, 56 | 300:wx.FONTWEIGHT_LIGHT, 57 | 400:wx.FONTWEIGHT_NORMAL, 58 | 500:wx.FONTWEIGHT_MEDIUM, 59 | 600:wx.FONTWEIGHT_SEMIBOLD, 60 | 700:wx.FONTWEIGHT_BOLD, 61 | 800:wx.FONTWEIGHT_EXTRABOLD, 62 | 900:wx.FONTWEIGHT_HEAVY, 63 | 1000:wx.FONTWEIGHT_EXTRAHEAVY, 64 | } 65 | weight = weigths.get(weight, wx.FONTWEIGHT_NORMAL) 66 | except AttributeError: 67 | if weight < 400: 68 | wight = wx.FONTWEIGHT_LIGHT 69 | elif weight > 500: 70 | weight = wx.FONTWEIGHT_BOLD 71 | else: 72 | weight = wx.FONTWEIGHT_NORMAL 73 | 74 | underline = decoration != 0 75 | font = wx.Font(size, wx.FONTFAMILY_DEFAULT, style, weight, underline, face) 76 | self.hfont += 1 77 | self.fonts[self.hfont] = font 78 | self.dc.SetFont(font) 79 | fm = self.dc.GetFontMetrics() 80 | return [ 81 | self.hfont, 82 | fm.ascent, 83 | fm.descent, 84 | fm.height, 85 | fm.height, 86 | ] 87 | 88 | def delete_font(self, hFont): 89 | #logger.debug('delete_font(%d)', hFont) 90 | del self.fonts[hFont] 91 | 92 | def text_width(self, text, hFont): 93 | #logger.debug('text_width(%s, %s)', text, hFont) 94 | font = self.fonts[hFont] 95 | width = self.dc.GetFullTextExtent(text, font)[0] 96 | return width 97 | 98 | def draw_text(self, hdc, text, hFont, color, pos): 99 | #logger.debug('draw_text(%d, %s, %d, %s, %s)', hdc, text, hFont, color, (pos.x, pos.y, pos.width, pos.height)) 100 | font = self.fonts[hFont] 101 | color = wx.Colour(color.red, color.green, color.blue, color.alpha) 102 | #self.dc.SetTextForeground(color) 103 | self.dc.SetTextBackground(color) 104 | self.dc.SetFont(font) 105 | self.dc.DrawText(text, pos.x, pos.y) 106 | 107 | def pt_to_px(self, pt): 108 | #logger.debug('pt_to_px(%d)', pt) 109 | pt = int(pt * self.ppi[1] / 72) 110 | return pt 111 | 112 | def get_default_font_size(self): 113 | #logger.debug('get_default_font_size()') 114 | return 12 115 | 116 | def get_default_font_name(self): 117 | #logger.debug('get_default_font_name()') 118 | return 'Times New Roman' 119 | 120 | def draw_list_marker(self, hdc, marker): 121 | #logger.debug('draw_list_marker(%d, %s)', hdc, marker) 122 | pass 123 | 124 | def load_image(self, src, baseurl, redraw_on_ready): 125 | #logger.debug('load_image(%s, %s, %s)', src, baseurl, redraw_on_ready) 126 | if self.parent is not None: 127 | self.parent.HtmlLoadImage(src, baseurl, redraw_on_ready) 128 | 129 | def get_image_size(self, src, baseurl, size): 130 | #logger.debug('get_image_size(%s, %s)', src, baseurl) 131 | if self.parent is None: 132 | size.width = 0 133 | size.height = 0 134 | else: 135 | img = self.parent.HtmlGetImage(src, baseurl) 136 | if img is None: 137 | size.width = 0 138 | size.height = 0 139 | else: 140 | sz = img.GetSize() 141 | size.width = sz[0] 142 | size.height = sz[1] 143 | 144 | def draw_image(self, hdc, layer, url, base_url): 145 | #logger.debug('draw_image(%d, %s, %s, %s)', hdc, layer, url, base_url) 146 | pass 147 | 148 | def draw_solid_fill(self, hdc, layer, color): 149 | #logger.debug('draw_solid_fill(%d, %s, %s)', hdc, layer, color) 150 | pass 151 | 152 | def draw_linear_gradient(self, hdc, layer, gradient): 153 | #logger.debug('draw_linear_gradient(%d, %s, %s)', hdc, layer, gradient) 154 | pass 155 | 156 | def draw_radial_gradient(self, hdc, layer, gradient): 157 | #logger.debug('draw_radial_gradient(%d, %s, %s)', hdc, layer, gradient) 158 | pass 159 | 160 | def draw_conic_gradient(self, hdc, layer, gradient): 161 | #logger.debug('draw_conic_gradient(%d, %s, %s)', hdc, layer, gradient) 162 | pass 163 | 164 | def draw_borders(self, hdc, borders, draw_pos, root): 165 | #logger.debug('draw_borders(%d, %s, %s, %s)', hdc, borders, draw_pos, root) 166 | left = draw_pos.x 167 | top = draw_pos.y 168 | right = left + draw_pos.width 169 | bottom = top + draw_pos.height 170 | 171 | b = borders.left 172 | colorLeft = wx.Colour(b.color.red, b.color.green, b.color.blue, b.color.alpha) 173 | widthLeft = b.width 174 | 175 | b = borders.top 176 | colorTop = wx.Colour(b.color.red, b.color.green, b.color.blue, b.color.alpha) 177 | widthTop = b.width 178 | 179 | b = borders.right 180 | colorRight = wx.Colour(b.color.red, b.color.green, b.color.blue, b.color.alpha) 181 | widthRight = b.width 182 | 183 | b = borders.bottom 184 | colorBottom = wx.Colour(b.color.red, b.color.green, b.color.blue, b.color.alpha) 185 | widthBottom = b.width 186 | 187 | self.dc.SetPen(wx.Pen(colorLeft, widthLeft)) 188 | self.dc.DrawLine(left, top, left, bottom) 189 | self.dc.SetPen(wx.Pen(colorTop, widthTop)) 190 | self.dc.DrawLine(left, top, right, top) 191 | self.dc.SetPen(wx.Pen(colorRight, widthRight)) 192 | self.dc.DrawLine(right, top, right, bottom) 193 | self.dc.SetPen(wx.Pen(colorBottom, widthBottom)) 194 | self.dc.DrawLine(left, bottom, right, bottom) 195 | 196 | def set_caption(self, caption): 197 | #logger.debug('set_caption(%s)', caption) 198 | pass 199 | 200 | def set_base_url(self, url): 201 | #logger.debug('set_base_url(%s)', url) 202 | pass 203 | 204 | #void link(const std::shared_ptr& doc, const element::ptr& el) override 205 | 206 | #void on_anchor_click(const char* url, const element::ptr& el) override 207 | def on_mouse_event(self, el, event): 208 | #logger.debug('on_mouse_event(%s, %s)', el, event) 209 | pass 210 | 211 | def set_cursor(self, cursor): 212 | #logger.debug('set_cursor(%s)', cursor) 213 | pass 214 | 215 | def transform_text(self, text, tt): 216 | #logger.debug('transform_text(%s, %d)', text, tt) 217 | pass 218 | 219 | def import_css(self, text, url, base_url): 220 | #logger.debug('import_css(%s, %s, %s)', text, url, base_url) 221 | pass 222 | 223 | def set_clip(self, pos, radius): 224 | #logger.debug('set_clip(%s, %s)', pos, radius) 225 | self.clips.append((pos, radius)) 226 | 227 | def del_clip(self): 228 | #logger.debug('del_clip()') 229 | if self.clips: 230 | self.clips.pop() 231 | 232 | def get_client_rect(self, client): 233 | #logger.debug('get_client_rect(%s)'%client) 234 | client.clear() 235 | client.width = self.size[0] 236 | client.height = self.size[1] 237 | 238 | #element::ptr create_element( const char* tag_name, const string_map& attributes, const std::shared_ptr& doc) override 239 | 240 | def get_media_features(self): 241 | #logger.debug('get_media_features()') 242 | return ( 243 | 2, # media_type_screen 244 | self.size[0], 245 | self.size[1], 246 | 1024, # device width (screen width) 247 | 800, # device height (screen height) 248 | 8, # color 249 | 0, # monochrome 250 | 256, # color index 251 | 96, # resolution 252 | ) 253 | 254 | def get_language(self): 255 | #logger.debug('get_language()') 256 | return ('en', '') 257 | -------------------------------------------------------------------------------- /src/master_css.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_MASTER_CSS_H 2 | #define LH_MASTER_CSS_H 3 | namespace litehtml{ const char* const master_css = R"##( 4 | 5 | 6 | html { 7 | display: block; 8 | position: relative; 9 | } 10 | 11 | head { 12 | display: none 13 | } 14 | 15 | meta { 16 | display: none 17 | } 18 | 19 | title { 20 | display: none 21 | } 22 | 23 | link { 24 | display: none 25 | } 26 | 27 | style { 28 | display: none 29 | } 30 | 31 | script { 32 | display: none 33 | } 34 | 35 | body { 36 | display:block; 37 | margin:8px; 38 | } 39 | 40 | p { 41 | display:block; 42 | margin-top:1em; 43 | margin-bottom:1em; 44 | } 45 | 46 | b, strong { 47 | display:inline; 48 | font-weight:bold; 49 | } 50 | 51 | i, em, cite { 52 | display:inline; 53 | font-style:italic; 54 | } 55 | 56 | ins, u { 57 | text-decoration:underline 58 | } 59 | 60 | del, s, strike { 61 | text-decoration:line-through 62 | } 63 | 64 | center 65 | { 66 | text-align:center; 67 | display:block; 68 | } 69 | 70 | a:link 71 | { 72 | text-decoration: underline; 73 | color: #00f; 74 | cursor: pointer; 75 | } 76 | 77 | h1, h2, h3, h4, h5, h6, div { 78 | display:block; 79 | } 80 | 81 | h1 { 82 | font-weight:bold; 83 | margin-top:0.67em; 84 | margin-bottom:0.67em; 85 | font-size: 2em; 86 | } 87 | 88 | h2 { 89 | font-weight:bold; 90 | margin-top:0.83em; 91 | margin-bottom:0.83em; 92 | font-size: 1.5em; 93 | } 94 | 95 | h3 { 96 | font-weight:bold; 97 | margin-top:1em; 98 | margin-bottom:1em; 99 | font-size:1.17em; 100 | } 101 | 102 | h4 { 103 | font-weight:bold; 104 | margin-top:1.33em; 105 | margin-bottom:1.33em 106 | } 107 | 108 | h5 { 109 | font-weight:bold; 110 | margin-top:1.67em; 111 | margin-bottom:1.67em; 112 | font-size:.83em; 113 | } 114 | 115 | h6 { 116 | font-weight:bold; 117 | margin-top:2.33em; 118 | margin-bottom:2.33em; 119 | font-size:.67em; 120 | } 121 | 122 | br { 123 | display:inline-block; 124 | } 125 | 126 | br[clear="all"] 127 | { 128 | clear:both; 129 | } 130 | 131 | br[clear="left"] 132 | { 133 | clear:left; 134 | } 135 | 136 | br[clear="right"] 137 | { 138 | clear:right; 139 | } 140 | 141 | span { 142 | display:inline 143 | } 144 | 145 | img { 146 | display: inline-block; 147 | } 148 | 149 | img[align="right"] 150 | { 151 | float: right; 152 | } 153 | 154 | img[align="left"] 155 | { 156 | float: left; 157 | } 158 | 159 | hr { 160 | display: block; 161 | margin-top: 0.5em; 162 | margin-bottom: 0.5em; 163 | margin-left: auto; 164 | margin-right: auto; 165 | border-style: inset; 166 | border-width: 1px 167 | } 168 | 169 | 170 | /***************** TABLES ********************/ 171 | 172 | table { 173 | display: table; 174 | border-collapse: separate; 175 | border-spacing: 2px; 176 | border-top-color:gray; 177 | border-left-color:gray; 178 | border-bottom-color:black; 179 | border-right-color:black; 180 | font-size: medium; 181 | font-weight: normal; 182 | font-style: normal; 183 | } 184 | 185 | tbody, tfoot, thead { 186 | display:table-row-group; 187 | vertical-align:middle; 188 | } 189 | 190 | tr { 191 | display: table-row; 192 | vertical-align: inherit; 193 | border-color: inherit; 194 | } 195 | 196 | td, th { 197 | display: table-cell; 198 | vertical-align: inherit; 199 | border-width:1px; 200 | padding:1px; 201 | } 202 | 203 | th { 204 | font-weight: bold; 205 | } 206 | 207 | table[border] { 208 | border-style:solid; 209 | } 210 | 211 | table[border|=0] { 212 | border-style:none; 213 | } 214 | 215 | table[border] td, table[border] th { 216 | border-style:solid; 217 | border-top-color:black; 218 | border-left-color:black; 219 | border-bottom-color:gray; 220 | border-right-color:gray; 221 | } 222 | 223 | table[border|=0] td, table[border|=0] th { 224 | border-style:none; 225 | } 226 | 227 | table[align=left] { 228 | float: left; 229 | } 230 | 231 | table[align=right] { 232 | float: right; 233 | } 234 | 235 | table[align=center] { 236 | margin-left: auto; 237 | margin-right: auto; 238 | } 239 | 240 | caption { 241 | display: table-caption; 242 | } 243 | 244 | td[nowrap], th[nowrap] { 245 | white-space:nowrap; 246 | } 247 | 248 | tt, code, kbd, samp { 249 | font-family: monospace 250 | } 251 | 252 | pre, xmp, plaintext, listing { 253 | display: block; 254 | font-family: monospace; 255 | white-space: pre; 256 | margin: 1em 0 257 | } 258 | 259 | /***************** LISTS ********************/ 260 | 261 | ul, menu, dir { 262 | display: block; 263 | list-style-type: disc; 264 | margin-top: 1em; 265 | margin-bottom: 1em; 266 | margin-left: 0; 267 | margin-right: 0; 268 | padding-left: 40px 269 | } 270 | 271 | ol { 272 | display: block; 273 | list-style-type: decimal; 274 | margin-top: 1em; 275 | margin-bottom: 1em; 276 | margin-left: 0; 277 | margin-right: 0; 278 | padding-left: 40px 279 | } 280 | 281 | li { 282 | display: list-item; 283 | } 284 | 285 | ul ul, ol ul { 286 | list-style-type: circle; 287 | } 288 | 289 | ol ol ul, ol ul ul, ul ol ul, ul ul ul { 290 | list-style-type: square; 291 | } 292 | 293 | dd { 294 | display: block; 295 | margin-left: 40px; 296 | } 297 | 298 | dl { 299 | display: block; 300 | margin-top: 1em; 301 | margin-bottom: 1em; 302 | margin-left: 0; 303 | margin-right: 0; 304 | } 305 | 306 | dt { 307 | display: block; 308 | } 309 | 310 | ol ul, ul ol, ul ul, ol ol { 311 | margin-top: 0; 312 | margin-bottom: 0 313 | } 314 | 315 | blockquote { 316 | display: block; 317 | margin-top: 1em; 318 | margin-bottom: 1em; 319 | margin-left: 40px; 320 | margin-right: 40px; 321 | } 322 | 323 | /*********** FORM ELEMENTS ************/ 324 | 325 | form { 326 | display: block; 327 | margin-top: 0em; 328 | } 329 | 330 | option { 331 | display: none; 332 | } 333 | 334 | input, textarea, keygen, select, button, isindex { 335 | margin: 0em; 336 | color: initial; 337 | line-height: normal; 338 | text-transform: none; 339 | text-indent: 0; 340 | text-shadow: none; 341 | display: inline-block; 342 | } 343 | input[type="hidden"] { 344 | display: none; 345 | } 346 | 347 | 348 | article, aside, footer, header, hgroup, nav, section 349 | { 350 | display: block; 351 | } 352 | 353 | sub { 354 | vertical-align: sub; 355 | font-size: smaller; 356 | } 357 | 358 | sup { 359 | vertical-align: super; 360 | font-size: smaller; 361 | } 362 | 363 | figure { 364 | display: block; 365 | margin-top: 1em; 366 | margin-bottom: 1em; 367 | margin-left: 40px; 368 | margin-right: 40px; 369 | } 370 | 371 | figcaption { 372 | display: block; 373 | } 374 | 375 | )##"; } 376 | #endif // LH_MASTER_CSS_H 377 | -------------------------------------------------------------------------------- /src/media_query.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_MEDIA_QUERY_H 2 | #define LH_MEDIA_QUERY_H 3 | 4 | namespace litehtml 5 | { 6 | struct media_query_expression 7 | { 8 | typedef std::vector vector; 9 | media_feature feature; 10 | int val; 11 | int val2; 12 | bool check_as_bool; 13 | 14 | media_query_expression() 15 | { 16 | check_as_bool = false; 17 | feature = media_feature_none; 18 | val = 0; 19 | val2 = 0; 20 | } 21 | 22 | bool check(const media_features& features) const; 23 | }; 24 | 25 | class media_query 26 | { 27 | public: 28 | typedef std::shared_ptr ptr; 29 | typedef std::vector vector; 30 | private: 31 | media_query_expression::vector m_expressions; 32 | bool m_not; 33 | media_type m_media_type; 34 | public: 35 | media_query(); 36 | media_query(const media_query& val); 37 | 38 | static media_query::ptr create_from_string(const string& str, const std::shared_ptr& doc); 39 | bool check(const media_features& features) const; 40 | }; 41 | 42 | class media_query_list 43 | { 44 | public: 45 | typedef std::shared_ptr ptr; 46 | typedef std::vector vector; 47 | private: 48 | media_query::vector m_queries; 49 | bool m_is_used; 50 | public: 51 | media_query_list(); 52 | media_query_list(const media_query_list& val); 53 | 54 | static media_query_list::ptr create_from_string(const string& str, const std::shared_ptr& doc); 55 | bool is_used() const; 56 | bool apply_media_features(const media_features& features); // returns true if the m_is_used changed 57 | }; 58 | 59 | inline media_query_list::media_query_list(const media_query_list& val) 60 | { 61 | m_is_used = val.m_is_used; 62 | m_queries = val.m_queries; 63 | } 64 | 65 | inline media_query_list::media_query_list() 66 | { 67 | m_is_used = false; 68 | } 69 | 70 | inline bool media_query_list::is_used() const 71 | { 72 | return m_is_used; 73 | } 74 | 75 | } 76 | 77 | #endif // LH_MEDIA_QUERY_H 78 | -------------------------------------------------------------------------------- /src/num_cvt.h: -------------------------------------------------------------------------------- 1 | #ifndef NUM_CVT_H 2 | #define NUM_CVT_H 3 | 4 | #include 5 | #include "os_types.h" 6 | 7 | namespace litehtml 8 | { 9 | namespace num_cvt 10 | { 11 | string to_latin_lower(int val); 12 | string to_latin_upper(int val); 13 | string to_greek_lower(int val); 14 | string to_roman_lower(int value); 15 | string to_roman_upper(int value); 16 | } 17 | } 18 | 19 | #endif // NUM_CVT_H -------------------------------------------------------------------------------- /src/os_types.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_OS_TYPES_H 2 | #define LH_OS_TYPES_H 3 | 4 | #include 5 | #include 6 | 7 | namespace litehtml 8 | { 9 | using std::string; 10 | typedef std::uintptr_t uint_ptr; 11 | 12 | #if defined( WIN32 ) || defined( _WIN32 ) || defined( WINCE ) 13 | 14 | // noexcept appeared since Visual Studio 2015 15 | #if defined(_MSC_VER) && _MSC_VER < 1900 16 | #define noexcept 17 | #endif 18 | 19 | #define t_itoa(value, buffer, size, radix) _itoa_s(value, buffer, size, radix) 20 | #define t_snprintf(s, n, format, ...) _snprintf_s(s, _TRUNCATE, n, format, __VA_ARGS__) 21 | 22 | #else 23 | 24 | #define t_itoa(value, buffer, size, radix) snprintf(buffer, size, "%d", value) 25 | #define t_snprintf(s, n, format, ...) snprintf(s, n, format, __VA_ARGS__) 26 | 27 | #endif 28 | } 29 | 30 | #endif // LH_OS_TYPES_H 31 | -------------------------------------------------------------------------------- /src/render_block.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_BLOCK_H 2 | #define LITEHTML_RENDER_BLOCK_H 3 | 4 | #include "render_item.h" 5 | 6 | namespace litehtml 7 | { 8 | class render_item_block : public render_item 9 | { 10 | protected: 11 | /** 12 | * Render block content. 13 | * 14 | * @param x - horizontal position of the content 15 | * @param y - vertical position of the content 16 | * @param second_pass - true is this is the second pass. 17 | * @param ret_width - input minimal width. 18 | * @param self_size - defines calculated size of block 19 | * @return return value is the minimal width of the content in block. Must be greater or equal to ret_width parameter 20 | */ 21 | virtual int _render_content(int /*x*/, int /*y*/, bool /*second_pass*/, const containing_block_context &/*self_size*/, formatting_context* /*fmt_ctx*/) {return 0;} 22 | int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; 23 | int place_float(const std::shared_ptr &el, int top, const containing_block_context &self_size, formatting_context* fmt_ctx); 24 | virtual void fix_line_width(element_float /*flt*/, 25 | const containing_block_context &/*containing_block_size*/, formatting_context* /*fmt_ctx*/) 26 | {} 27 | 28 | public: 29 | explicit render_item_block(std::shared_ptr src_el) : render_item(std::move(src_el)) 30 | {} 31 | 32 | std::shared_ptr clone() override 33 | { 34 | return std::make_shared(src_el()); 35 | } 36 | std::shared_ptr init() override; 37 | }; 38 | } 39 | 40 | #endif //LITEHTML_RENDER_BLOCK_H 41 | -------------------------------------------------------------------------------- /src/render_block_context.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_BLOCK_CONTEXT_H 2 | #define LITEHTML_RENDER_BLOCK_CONTEXT_H 3 | 4 | #include "render_block.h" 5 | 6 | namespace litehtml 7 | { 8 | /** 9 | * In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a 10 | * containing block. 11 | * https://www.w3.org/TR/CSS22/visuren.html#block-formatting 12 | */ 13 | class render_item_block_context : public render_item_block 14 | { 15 | protected: 16 | int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; 17 | 18 | public: 19 | explicit render_item_block_context(std::shared_ptr src_el) : render_item_block(std::move(src_el)) 20 | {} 21 | 22 | std::shared_ptr clone() override 23 | { 24 | return std::make_shared(src_el()); 25 | } 26 | int get_first_baseline() override; 27 | int get_last_baseline() override; 28 | }; 29 | } 30 | 31 | #endif //LITEHTML_RENDER_BLOCK_CONTEXT_H 32 | -------------------------------------------------------------------------------- /src/render_flex.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_FLEX_H 2 | #define LITEHTML_RENDER_FLEX_H 3 | 4 | #include "render_block.h" 5 | #include "flex_item.h" 6 | #include "flex_line.h" 7 | 8 | namespace litehtml 9 | { 10 | class render_item_flex : public render_item_block 11 | { 12 | std::list m_lines; 13 | 14 | std::list get_lines(const containing_block_context &self_size, formatting_context *fmt_ctx, bool is_row_direction, 15 | int container_main_size, bool single_line); 16 | int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; 17 | 18 | public: 19 | explicit render_item_flex(std::shared_ptr src_el) : render_item_block(std::move(src_el)) 20 | {} 21 | 22 | std::shared_ptr clone() override 23 | { 24 | return std::make_shared(src_el()); 25 | } 26 | std::shared_ptr init() override; 27 | 28 | int get_first_baseline() override; 29 | int get_last_baseline() override; 30 | }; 31 | } 32 | 33 | #endif //LITEHTML_RENDER_FLEX_H 34 | -------------------------------------------------------------------------------- /src/render_image.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_IMAGE_H 2 | #define LITEHTML_RENDER_IMAGE_H 3 | 4 | #include "render_item.h" 5 | 6 | namespace litehtml 7 | { 8 | class render_item_image : public render_item 9 | { 10 | protected: 11 | int calc_max_height(int image_height, int containing_block_height); 12 | int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; 13 | 14 | public: 15 | explicit render_item_image(std::shared_ptr src_el) : render_item(std::move(src_el)) 16 | {} 17 | 18 | std::shared_ptr clone() override 19 | { 20 | return std::make_shared(src_el()); 21 | } 22 | }; 23 | } 24 | 25 | #endif //LITEHTML_RENDER_IMAGE_H 26 | -------------------------------------------------------------------------------- /src/render_inline.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_INLINE_H 2 | #define LITEHTML_RENDER_INLINE_H 3 | 4 | #include "render_item.h" 5 | 6 | namespace litehtml 7 | { 8 | class render_item_inline : public render_item 9 | { 10 | protected: 11 | position::vector m_boxes; 12 | 13 | public: 14 | explicit render_item_inline(std::shared_ptr src_el) : render_item(std::move(src_el)) 15 | {} 16 | 17 | void get_inline_boxes( position::vector& boxes ) const override { boxes = m_boxes; } 18 | void set_inline_boxes( position::vector& boxes ) override { m_boxes = boxes; } 19 | void add_inline_box( const position& box ) override { m_boxes.emplace_back(box); }; 20 | void clear_inline_boxes() override { m_boxes.clear(); } 21 | int get_first_baseline() override 22 | { 23 | return src_el()->css().get_font_metrics().height - src_el()->css().get_font_metrics().base_line(); 24 | } 25 | int get_last_baseline() override 26 | { 27 | return src_el()->css().get_font_metrics().height - src_el()->css().get_font_metrics().base_line(); 28 | } 29 | 30 | std::shared_ptr clone() override 31 | { 32 | return std::make_shared(src_el()); 33 | } 34 | }; 35 | } 36 | 37 | #endif //LITEHTML_RENDER_INLINE_H 38 | 39 | -------------------------------------------------------------------------------- /src/render_inline_context.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_INLINE_CONTEXT_H 2 | #define LITEHTML_RENDER_INLINE_CONTEXT_H 3 | 4 | #include "render_block.h" 5 | 6 | namespace litehtml 7 | { 8 | /** 9 | * An inline formatting context is established by a block container box that contains no block-level boxes. 10 | * https://www.w3.org/TR/CSS22/visuren.html#inline-formatting 11 | */ 12 | class render_item_inline_context : public render_item_block 13 | { 14 | /** 15 | * Structure contains elements with display: inline 16 | * members: 17 | * - element: render_item with display: inline 18 | * - boxes: rectangles represented inline element content. There are can be many boxes if content 19 | * is split into some lines 20 | * - start_box: the start position of currently calculated box 21 | */ 22 | struct inlines_item 23 | { 24 | std::shared_ptr element; 25 | position::vector boxes; 26 | position start_box; 27 | 28 | explicit inlines_item(const std::shared_ptr& el) : element(el) {} 29 | }; 30 | protected: 31 | std::vector > m_line_boxes; 32 | int m_max_line_width; 33 | 34 | int _render_content(int x, int y, bool second_pass, const containing_block_context &self_size, formatting_context* fmt_ctx) override; 35 | void fix_line_width(element_float flt, 36 | const containing_block_context &self_size, formatting_context* fmt_ctx) override; 37 | 38 | std::list > finish_last_box(bool end_of_render, const containing_block_context &self_size); 39 | void place_inline(std::unique_ptr item, const containing_block_context &self_size, formatting_context* fmt_ctx); 40 | int new_box(const std::unique_ptr& el, line_context& line_ctx, const containing_block_context &self_size, formatting_context* fmt_ctx); 41 | void apply_vertical_align() override; 42 | public: 43 | explicit render_item_inline_context(std::shared_ptr src_el) : render_item_block(std::move(src_el)), m_max_line_width(0) 44 | {} 45 | 46 | std::shared_ptr clone() override 47 | { 48 | return std::make_shared(src_el()); 49 | } 50 | 51 | int get_first_baseline() override; 52 | int get_last_baseline() override; 53 | }; 54 | } 55 | 56 | #endif //LITEHTML_RENDER_INLINE_CONTEXT_H 57 | -------------------------------------------------------------------------------- /src/render_item.h: -------------------------------------------------------------------------------- 1 | py::class_>(m, "render_item") 2 | /* 3 | explicit render_item(std::shared_ptr src_el); 4 | 5 | virtual ~render_item() = default; 6 | 7 | std::list>& children() 8 | { 9 | return m_children; 10 | } 11 | */ 12 | .def("pos", &lh::render_item::pos) 13 | //.def("skip", &lh::render_item::skip) 14 | //void skip(bool val) 15 | .def("right", &lh::render_item::right) 16 | .def("left", &lh::render_item::left) 17 | .def("top", &lh::render_item::top) 18 | .def("bottom", &lh::render_item::bottom) 19 | .def("height", &lh::render_item::height) 20 | .def("width", &lh::render_item::width) 21 | .def("padding_top", &lh::render_item::padding_top) 22 | .def("padding_bottom", &lh::render_item::padding_bottom) 23 | .def("padding_left", &lh::render_item::padding_left) 24 | .def("padding_right", &lh::render_item::padding_right) 25 | .def("border_top", &lh::render_item::border_top) 26 | .def("border_bottom", &lh::render_item::border_bottom) 27 | .def("border_left", &lh::render_item::border_left) 28 | .def("border_right", &lh::render_item::border_right) 29 | .def("margin_top", &lh::render_item::margin_top) 30 | .def("margin_bottom", &lh::render_item::margin_bottom) 31 | .def("margin_left", &lh::render_item::margin_left) 32 | .def("margin_right", &lh::render_item::margin_right) 33 | /* 34 | //std::shared_ptr parent() const 35 | margins& get_margins() 36 | margins& get_paddings() 37 | void set_paddings(const margins& val) 38 | margins& get_borders() 39 | int content_offset_top() const 40 | inline int content_offset_bottom() const 41 | int content_offset_left() const 42 | int content_offset_right() const 43 | int content_offset_width() const 44 | int content_offset_height() const 45 | int box_sizing_left() const 46 | int box_sizing_right() const 47 | int box_sizing_width() const 48 | int box_sizing_top() const 49 | int box_sizing_bottom() const 50 | int box_sizing_height() const 51 | void parent(const std::shared_ptr& par) 52 | const std::shared_ptr& src_el() const 53 | const css_properties& css() const 54 | void add_child(const std::shared_ptr& ri) 55 | bool is_root() const 56 | bool collapse_top_margin() const 57 | bool collapse_bottom_margin() const 58 | bool is_visible() const 59 | bool is_flex_item() const 60 | int render(int x, int y, const containing_block_context& containing_block_size, formatting_context* fmt_ctx, bool second_pass = false); 61 | void apply_relative_shift(const containing_block_context &containing_block_size); 62 | void calc_outlines( int parent_width ); 63 | int calc_auto_margins(int parent_width); // returns left margin 64 | 65 | virtual std::shared_ptr init(); 66 | virtual void apply_vertical_align() {} 67 | virtual int get_first_baseline() { return height() - margin_bottom(); } 68 | virtual int get_last_baseline() { return height() - margin_bottom(); } 69 | 70 | virtual std::shared_ptr clone() 71 | { 72 | return std::make_shared(src_el()); 73 | } 74 | std::tuple< 75 | std::shared_ptr, 76 | std::shared_ptr, 77 | std::shared_ptr 78 | > split_inlines(); 79 | bool fetch_positioned(); 80 | void render_positioned(render_type rt = render_all); 81 | void add_positioned(const std::shared_ptr &el); 82 | void get_redraw_box(litehtml::position& pos, int x = 0, int y = 0); 83 | void calc_document_size( litehtml::size& sz, litehtml::size& content_size, int x = 0, int y = 0 ); 84 | virtual void get_inline_boxes( position::vector& boxes ) const {}; 85 | virtual void set_inline_boxes( position::vector& boxes ) {}; 86 | virtual void add_inline_box( const position& box ) {}; 87 | virtual void clear_inline_boxes() {}; 88 | void draw_stacking_context( uint_ptr hdc, int x, int y, const position* clip, bool with_positioned ); 89 | virtual void draw_children( uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex ); 90 | virtual int get_draw_vertical_offset() { return 0; } 91 | virtual std::shared_ptr get_child_by_point(int x, int y, int client_x, int client_y, draw_flag flag, int zindex); 92 | std::shared_ptr get_element_by_point(int x, int y, int client_x, int client_y); 93 | bool is_point_inside( int x, int y ); 94 | void dump(litehtml::dumper& cout); 95 | position get_placement() const; 96 | void get_rendering_boxes( position::vector& redraw_boxes); 97 | */ 98 | ; 99 | -------------------------------------------------------------------------------- /src/render_table.h: -------------------------------------------------------------------------------- 1 | #ifndef LITEHTML_RENDER_TABLE_H 2 | #define LITEHTML_RENDER_TABLE_H 3 | 4 | #include "render_item.h" 5 | 6 | namespace litehtml 7 | { 8 | class render_item_table : public render_item 9 | { 10 | protected: 11 | // data for table rendering 12 | std::unique_ptr m_grid; 13 | int m_border_spacing_x; 14 | int m_border_spacing_y; 15 | 16 | int _render(int x, int y, const containing_block_context &containing_block_size, formatting_context* fmt_ctx, bool second_pass) override; 17 | 18 | public: 19 | explicit render_item_table(std::shared_ptr src_el); 20 | 21 | std::shared_ptr clone() override 22 | { 23 | return std::make_shared(src_el()); 24 | } 25 | void draw_children(uint_ptr hdc, int x, int y, const position* clip, draw_flag flag, int zindex) override; 26 | int get_draw_vertical_offset() override; 27 | std::shared_ptr init() override; 28 | }; 29 | 30 | class render_item_table_part : public render_item 31 | { 32 | public: 33 | explicit render_item_table_part(std::shared_ptr src_el) : render_item(std::move(src_el)) 34 | {} 35 | 36 | std::shared_ptr clone() override 37 | { 38 | return std::make_shared(src_el()); 39 | } 40 | }; 41 | 42 | class render_item_table_row : public render_item 43 | { 44 | public: 45 | explicit render_item_table_row(std::shared_ptr src_el) : render_item(std::move(src_el)) 46 | {} 47 | 48 | std::shared_ptr clone() override 49 | { 50 | return std::make_shared(src_el()); 51 | } 52 | void get_inline_boxes( position::vector& boxes ) const override; 53 | }; 54 | } 55 | 56 | #endif //LITEHTML_RENDER_TABLE_H 57 | -------------------------------------------------------------------------------- /src/string_id.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_STRING_ID_H 2 | #define LH_STRING_ID_H 3 | 4 | namespace litehtml 5 | { 6 | 7 | #define STRING_ID(...)\ 8 | enum string_id { __VA_ARGS__ };\ 9 | const auto initial_string_ids = #__VA_ARGS__; 10 | 11 | STRING_ID( 12 | 13 | // HTML tags 14 | _a_, 15 | _abbr_, 16 | _acronym_, 17 | _address_, 18 | _applet_, 19 | _area_, 20 | _article_, 21 | _aside_, 22 | _audio_, 23 | _b_, 24 | _base_, 25 | _basefont_, 26 | _bdi_, 27 | _bdo_, 28 | _big_, 29 | _blockquote_, 30 | _body_, 31 | _br_, 32 | _button_, 33 | _canvas_, 34 | _caption_, 35 | _center_, 36 | _cite_, 37 | _code_, 38 | _col_, 39 | _colgroup_, 40 | _data_, 41 | _datalist_, 42 | _dd_, 43 | _del_, 44 | _details_, 45 | _dfn_, 46 | _dialog_, 47 | _dir_, 48 | _div_, 49 | _dl_, 50 | _dt_, 51 | _em_, 52 | _embed_, 53 | _fieldset_, 54 | _figcaption_, 55 | _figure_, 56 | _footer_, 57 | _form_, 58 | _frame_, 59 | _frameset_, 60 | _h1_, 61 | _h2_, 62 | _h3_, 63 | _h4_, 64 | _h5_, 65 | _h6_, 66 | _head_, 67 | _header_, 68 | _hr_, 69 | _html_, 70 | _i_, 71 | _iframe_, 72 | _img_, 73 | _input_, 74 | _ins_, 75 | _kbd_, 76 | _label_, 77 | _legend_, 78 | _li_, 79 | _link_, 80 | _main_, 81 | _map_, 82 | _mark_, 83 | _meta_, 84 | _meter_, 85 | _nav_, 86 | _noframes_, 87 | _noscript_, 88 | _object_, 89 | _ol_, 90 | _optgroup_, 91 | _option_, 92 | _output_, 93 | _p_, 94 | _param_, 95 | _picture_, 96 | _pre_, 97 | _progress_, 98 | _q_, 99 | _rp_, 100 | _rt_, 101 | _ruby_, 102 | _s_, 103 | _samp_, 104 | _script_, 105 | _section_, 106 | _select_, 107 | _small_, 108 | _source_, 109 | _span_, 110 | _strike_, 111 | _strong_, 112 | _style_, 113 | _sub_, 114 | _summary_, 115 | _sup_, 116 | _svg_, 117 | _table_, 118 | _tbody_, 119 | _td_, 120 | _template_, 121 | _textarea_, 122 | _tfoot_, 123 | _th_, 124 | _thead_, 125 | _time_, 126 | _title_, 127 | _tr_, 128 | _track_, 129 | _tt_, 130 | _u_, 131 | _ul_, 132 | _var_, 133 | _video_, 134 | _wbr_, 135 | 136 | // litehtml internal tags 137 | __tag_before_, // note: real tag cannot start with '-' 138 | __tag_after_, 139 | 140 | // CSS pseudo-elements 141 | _before_, 142 | _after_, 143 | 144 | // CSS pseudo-classes 145 | _root_, 146 | _only_child_, 147 | _only_of_type_, 148 | _first_child_, 149 | _first_of_type_, 150 | _last_child_, 151 | _last_of_type_, 152 | _nth_child_, 153 | _nth_of_type_, 154 | _nth_last_child_, 155 | _nth_last_of_type_, 156 | _not_, 157 | _lang_, 158 | 159 | _active_, 160 | _hover_, 161 | 162 | // CSS property names 163 | _background_, 164 | _background_color_, 165 | _background_image_, 166 | _background_image_baseurl_, 167 | _background_repeat_, 168 | _background_origin_, 169 | _background_clip_, 170 | _background_attachment_, 171 | _background_size_, 172 | _background_position_, 173 | _background_position_x_, 174 | _background_position_y_, 175 | 176 | _border_, 177 | _border_width_, 178 | _border_style_, 179 | _border_color_, 180 | 181 | _border_spacing_, 182 | __litehtml_border_spacing_x_, 183 | __litehtml_border_spacing_y_, 184 | 185 | _border_left_, 186 | _border_right_, 187 | _border_top_, 188 | _border_bottom_, 189 | 190 | _border_left_style_, 191 | _border_right_style_, 192 | _border_top_style_, 193 | _border_bottom_style_, 194 | 195 | _border_left_width_, 196 | _border_right_width_, 197 | _border_top_width_, 198 | _border_bottom_width_, 199 | 200 | _border_left_color_, 201 | _border_right_color_, 202 | _border_top_color_, 203 | _border_bottom_color_, 204 | 205 | _border_radius_, 206 | _border_radius_x_, 207 | _border_radius_y_, 208 | 209 | _border_bottom_left_radius_, 210 | _border_bottom_left_radius_x_, 211 | _border_bottom_left_radius_y_, 212 | 213 | _border_bottom_right_radius_, 214 | _border_bottom_right_radius_x_, 215 | _border_bottom_right_radius_y_, 216 | 217 | _border_top_left_radius_, 218 | _border_top_left_radius_x_, 219 | _border_top_left_radius_y_, 220 | 221 | _border_top_right_radius_, 222 | _border_top_right_radius_x_, 223 | _border_top_right_radius_y_, 224 | 225 | _list_style_, 226 | _list_style_type_, 227 | _list_style_position_, 228 | _list_style_image_, 229 | _list_style_image_baseurl_, 230 | 231 | _margin_, 232 | _margin_left_, 233 | _margin_right_, 234 | _margin_top_, 235 | _margin_bottom_, 236 | _padding_, 237 | _padding_left_, 238 | _padding_right_, 239 | _padding_top_, 240 | _padding_bottom_, 241 | 242 | _font_, 243 | _font_family_, 244 | _font_style_, 245 | _font_variant_, 246 | _font_weight_, 247 | _font_size_, 248 | _line_height_, 249 | _text_decoration_, 250 | 251 | _white_space_, 252 | _text_align_, 253 | _vertical_align_, 254 | _color_, 255 | _width_, 256 | _height_, 257 | _min_width_, 258 | _min_height_, 259 | _max_width_, 260 | _max_height_, 261 | _position_, 262 | _overflow_, 263 | _display_, 264 | _visibility_, 265 | _box_sizing_, 266 | _z_index_, 267 | _float_, 268 | _clear_, 269 | _text_indent_, 270 | _left_, 271 | _right_, 272 | _top_, 273 | _bottom_, 274 | _cursor_, 275 | _content_, 276 | _border_collapse_, 277 | _text_transform_, 278 | 279 | _flex_, 280 | _flex_flow_, 281 | _flex_direction_, 282 | _flex_wrap_, 283 | _justify_content_, 284 | _align_items_, 285 | _align_content_, 286 | _align_self_, 287 | _flex_grow_, 288 | _flex_shrink_, 289 | _flex_basis_, 290 | 291 | _caption_side_, 292 | _order_, 293 | 294 | _counter_reset_, 295 | _counter_increment_, 296 | ); 297 | #undef STRING_ID 298 | extern const string_id empty_id; // _id("") 299 | extern const string_id star_id; // _id("*") 300 | 301 | string_id _id(const string& str); 302 | const string& _s(string_id id); 303 | 304 | } // namespace litehtml 305 | 306 | #endif // LH_STRING_ID_H 307 | -------------------------------------------------------------------------------- /src/style.h: -------------------------------------------------------------------------------- 1 | #ifndef LH_STYLE_H 2 | #define LH_STYLE_H 3 | 4 | namespace litehtml 5 | { 6 | enum property_type 7 | { 8 | prop_type_invalid, // indicates "not found" condition in style::get_property 9 | prop_type_inherit, // "inherit" was specified as the value of this property 10 | 11 | prop_type_enum_item, 12 | prop_type_enum_item_vector, 13 | prop_type_length, 14 | prop_type_length_vector, 15 | prop_type_number, 16 | prop_type_color, 17 | prop_type_string, 18 | prop_type_string_vector, 19 | prop_type_size_vector, 20 | 21 | prop_type_var, // also string, but needs further parsing because of var() 22 | }; 23 | 24 | class property_value 25 | { 26 | public: 27 | property_type m_type; 28 | bool m_important; 29 | 30 | union { 31 | int m_enum_item; 32 | int_vector m_enum_item_vector; 33 | css_length m_length; 34 | length_vector m_length_vector; 35 | float m_number; 36 | web_color m_color; 37 | string m_string; 38 | string_vector m_string_vector; 39 | size_vector m_size_vector; 40 | }; 41 | 42 | property_value() 43 | : m_type(prop_type_invalid) 44 | { 45 | } 46 | property_value(bool important, property_type type) 47 | : m_type(type), m_important(important) 48 | { 49 | } 50 | property_value(const string& str, bool important, property_type type = prop_type_string) 51 | : m_type(type), m_important(important), m_string(str) 52 | { 53 | } 54 | property_value(const string_vector& vec, bool important) 55 | : m_type(prop_type_string_vector), m_important(important), m_string_vector(vec) 56 | { 57 | } 58 | property_value(const css_length& length, bool important) 59 | : m_type(prop_type_length), m_important(important), m_length(length) 60 | { 61 | } 62 | property_value(const length_vector& vec, bool important) 63 | : m_type(prop_type_length_vector), m_important(important), m_length_vector(vec) 64 | { 65 | } 66 | property_value(float number, bool important) 67 | : m_type(prop_type_number), m_important(important), m_number(number) 68 | { 69 | } 70 | property_value(int enum_item, bool important) 71 | : m_type(prop_type_enum_item), m_important(important), m_enum_item(enum_item) 72 | { 73 | } 74 | property_value(const int_vector& vec, bool important) 75 | : m_type(prop_type_enum_item_vector), m_important(important), m_enum_item_vector(vec) 76 | { 77 | } 78 | property_value(web_color color, bool important) 79 | : m_type(prop_type_color), m_important(important), m_color(color) 80 | { 81 | } 82 | property_value(const size_vector& vec, bool important) 83 | : m_type(prop_type_size_vector), m_important(important), m_size_vector(vec) 84 | { 85 | } 86 | ~property_value() 87 | { 88 | switch (m_type) 89 | { 90 | case prop_type_string: 91 | case prop_type_var: 92 | m_string.~string(); 93 | break; 94 | case prop_type_string_vector: 95 | m_string_vector.~string_vector(); 96 | break; 97 | case prop_type_length: 98 | m_length.~css_length(); 99 | break; 100 | case prop_type_length_vector: 101 | m_length_vector.~length_vector(); 102 | break; 103 | case prop_type_enum_item_vector: 104 | m_enum_item_vector.~int_vector(); 105 | break; 106 | case prop_type_color: 107 | m_color.~web_color(); 108 | break; 109 | case prop_type_size_vector: 110 | m_size_vector.~size_vector(); 111 | break; 112 | default: 113 | break; 114 | } 115 | } 116 | property_value& operator=(const property_value& val) 117 | { 118 | this->~property_value(); 119 | 120 | switch (val.m_type) 121 | { 122 | case prop_type_invalid: 123 | new(this) property_value(); 124 | break; 125 | case prop_type_inherit: 126 | new(this) property_value(val.m_important, val.m_type); 127 | break; 128 | case prop_type_string: 129 | case prop_type_var: 130 | new(this) property_value(val.m_string, val.m_important, val.m_type); 131 | break; 132 | case prop_type_string_vector: 133 | new(this) property_value(val.m_string_vector, val.m_important); 134 | break; 135 | case prop_type_enum_item: 136 | new(this) property_value(val.m_enum_item, val.m_important); 137 | break; 138 | case prop_type_enum_item_vector: 139 | new(this) property_value(val.m_enum_item_vector, val.m_important); 140 | break; 141 | case prop_type_length: 142 | new(this) property_value(val.m_length, val.m_important); 143 | break; 144 | case prop_type_length_vector: 145 | new(this) property_value(val.m_length_vector, val.m_important); 146 | break; 147 | case prop_type_number: 148 | new(this) property_value(val.m_number, val.m_important); 149 | break; 150 | case prop_type_color: 151 | new(this) property_value(val.m_color, val.m_important); 152 | break; 153 | case prop_type_size_vector: 154 | new(this) property_value(val.m_size_vector, val.m_important); 155 | break; 156 | } 157 | 158 | return *this; 159 | } 160 | }; 161 | 162 | typedef std::map props_map; 163 | 164 | class style 165 | { 166 | public: 167 | typedef std::shared_ptr 64 | 65 | 66 | 67 |
68 | 69 | 70 | 73 | 80 | 81 | 82 | 89 | 97 | 98 |
71 |
12. Identyfikator podatkowy NIP / numer PESEL
12345678901 72 |
74 |
75 |
76 | 13. Zagraniczny numer identyfikacyjny podatnika (numer dokumentu stwierdzającego tożsamość)11) 77 |
78 |
79 |
83 |
84 |
85 | 14. Rodzaj numeru identyfikacyjnego (dokumentu stwierdzającego tożsamość) 86 |
87 |
88 |
90 |
91 |
92 | 15. Kraj wydania numeru identyfikacyjnego (dokumentu stwierdzającego tożsamość) 93 |
PL  94 | (POLSKA) 95 |
96 |
99 | 100 | 101 | 106 | 107 |
102 |
11. Rodzaj obowiązku podatkowego podatnika
103 | 1. nieograniczony 104 | obowiązek podatkowy (rezydent) 105 |
108 |
109 | 110 | 111 | --------------------------------------------------------------------------------