diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..80d3506a
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,84 @@
+# Generated from CLion C/C++ Code Style settings
+Language: Cpp
+BasedOnStyle: Google
+ColumnLimit: 100
+SortIncludes: true
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignOperands: Align
+AllowAllArgumentsOnNextLine: false
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: false
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: Always
+AllowShortLambdasOnASingleLine: All
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterReturnType: None
+AlwaysBreakTemplateDeclarations: Yes
+BreakBeforeBraces: Custom
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: false
+ SplitEmptyRecord: true
+BreakBeforeBinaryOperators: None
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: BeforeColon
+BreakInheritanceList: BeforeColon
+CompactNamespaces: false
+ContinuationIndentWidth: 4
+IndentCaseLabels: true
+IndentPPDirectives: None
+IndentWidth: 2
+KeepEmptyLinesAtTheStartOfBlocks: true
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+DerivePointerAlignment: false
+PointerAlignment: Left
+ReflowComments: false
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+IncludeBlocks: Merge
+TabWidth: 2
+UseTab: Never
+
+---
+Language: ObjC
+BasedOnStyle: Google
+ColumnLimit: 100
+
+# Only sort headers in each include block
+SortIncludes: true
+IncludeBlocks: Preserve
+DerivePointerAlignment: false
+PointerAlignment: Left
+AllowShortFunctionsOnASingleLine: None
+BraceWrapping:
+ SplitEmptyFunction: true
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..f2bf5a96
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,22 @@
+*.png filter=lfs diff=lfs merge=lfs -text
+*.pag filter=lfs diff=lfs merge=lfs -text
+*.jpg filter=lfs diff=lfs merge=lfs -text
+*.webp filter=lfs diff=lfs merge=lfs -text
+*.aep filter=lfs diff=lfs merge=lfs -text
+*.ttf filter=lfs diff=lfs merge=lfs -text
+*.ttc filter=lfs diff=lfs merge=lfs -text
+*.otf filter=lfs diff=lfs merge=lfs -text
+*.mp4 filter=lfs diff=lfs merge=lfs -text
+*.mov filter=lfs diff=lfs merge=lfs -text
+*.aac filter=lfs diff=lfs merge=lfs -text
+*.mp3 filter=lfs diff=lfs merge=lfs -text
+*.m4a filter=lfs diff=lfs merge=lfs -text
+*.gif filter=lfs diff=lfs merge=lfs -text
+*.a filter=lfs diff=lfs merge=lfs -text
+*.dylib filter=lfs diff=lfs merge=lfs -text
+*.dll filter=lfs diff=lfs merge=lfs -text
+*.lib filter=lfs diff=lfs merge=lfs -text
+*.so filter=lfs diff=lfs merge=lfs -text
+*.lzma2 filter=lfs diff=lfs merge=lfs -text
+*.wasm filter=lfs diff=lfs merge=lfs -text
+*.bin filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/ISSUE_TEMPLATE/bug_report_en.md b/.github/ISSUE_TEMPLATE/bug_report_en.md
new file mode 100644
index 00000000..4ddc6ef8
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report_en.md
@@ -0,0 +1,34 @@
+---
+name: Bug report
+about: Create a report to help us improve TGFX
+title: ''
+labels: ''
+assignees: 'domchen'
+
+---
+
+
+
+
+## Which Version of TGFX are you using?
+
+1.0.0
+
+## What Platform are you on?
+
+iOS 12, Android 10, macOS 10.15.3, Chrome 87.0 ...
+
+## Expected Behavior
+
+
+## Actual Behavior
+
+
+## Code Example
+
+## Related File
+
\ No newline at end of file
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..eda8bc24
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,7 @@
+---
+blank_issues_enabled: false
+contact_links:
+ -
+ about: "Please use Discussions to ask usage questions or suggest new features"
+ name: Question & Feature Request
+ url: "https://github.com/libpag/tgfx/discussions/1"
diff --git a/.github/workflows/autotest.yml b/.github/workflows/autotest.yml
new file mode 100644
index 00000000..85003c5b
--- /dev/null
+++ b/.github/workflows/autotest.yml
@@ -0,0 +1,116 @@
+# This is a basic workflow to help you get started with Actions
+
+name: autotest
+
+# Controls when the workflow will run
+on:
+ # Triggers the workflow on push or pull request events but only for the master branch
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+ autotest:
+ # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
+ # You can convert this to a matrix build if you need cross-platform coverage.
+ # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+ runs-on: macos-latest
+
+ steps:
+ - name: Get environment cache
+ id: cache-environment
+ uses: actions/cache@v2
+ with:
+ path: |
+ /usr/local/Cellar/ninja
+ /usr/local/Cellar/icu4c
+ /usr/local/bin/ninja
+ /usr/local/Cellar/node
+ /usr/local/bin/node
+ /usr/local/Cellar/yasm
+ /usr/local/bin/yasm
+ /usr/local/bin/depsync
+ /usr/local/lib/node_modules/depsync
+ /usr/local/Cellar/gcovr
+ /usr/local/bin/gcovr
+ /usr/local/Cellar/emsdk
+ /usr/local/Cellar/emsdk/upstream/emscripten
+ /usr/local/Cellar/emsdk/node/14.18.2_64bit/bin
+ /usr/local/bin/em++
+ /usr/local/bin/em-config
+ /usr/local/bin/emar
+ /usr/local/bin/embuilder
+ /usr/local/bin/emcc
+ /usr/local/bin/emcmake
+ /usr/local/bin/emconfigure
+ /usr/local/bin/emdump
+ /usr/local/bin/emdwp
+ /usr/local/bin/emmake
+ /usr/local/bin/emnm
+ /usr/local/bin/emrun
+ /usr/local/bin/emprofile
+ /usr/local/bin/emscons
+ /usr/local/bin/emsize
+ /usr/local/bin/emstrip
+ /usr/local/bin/emsymbolizer
+ /usr/local/bin/emcc.py
+ /usr/local/bin/emcmake.py
+ /usr/local/bin/emar.py
+ key: tgfx-environment-autotest-20221018
+ restore-keys: |
+ tgfx-environment-autotest-20221018
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 0
+ lfs: true
+ - name: Get thirdParty cache
+ id: cache-thirdParty
+ uses: actions/cache@v2
+ with:
+ path: |
+ third_party
+ vendor_tools
+ test/baseline/.cache
+ key: third_party-autotest-01-${{ hashFiles('DEPS') }}-${{ hashFiles('vendor.json') }}-${{ hashFiles('test/baseline/version.json') }}
+ restore-keys: third_party-autotest-
+ - name: Run sync_deps script
+ run: |
+ chmod +x sync_deps.sh
+ ./sync_deps.sh
+ shell: bash
+
+ - if: github.event_name == 'push'
+ name: Build cache(push)
+ run: |
+ node build_vendor -p mac
+ if [ ! $(which gcovr) ]; then
+ brew install gcovr
+ fi
+ chmod +x update_baseline.sh
+ ./update_baseline.sh 1
+ mkdir result
+ cp -r test/baseline result
+
+ - if: github.event_name == 'pull_request'
+ name: Run autotest script
+ run: |
+ chmod +x autotest.sh
+ ./autotest.sh
+
+ - name: codecov
+ if: github.event_name == 'pull_request'
+ uses: codecov/codecov-action@v2.1.0
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ file: tgfx/result/coverage.xml
+ - name: The job has failed
+ if: ${{ failure() }}
+ uses: actions/upload-artifact@v2
+ with:
+ name: result
+ path: result
+ - uses: actions/upload-artifact@v2
+ with:
+ name: result
+ path: result
diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml
new file mode 100644
index 00000000..b19d2977
--- /dev/null
+++ b/.github/workflows/build_linux.yml
@@ -0,0 +1,51 @@
+# This is a basic workflow to help you get started with Actions
+
+name: build_linux
+
+# Controls when the workflow will run
+on:
+ # Triggers the workflow on push or pull request events but only for the master branch
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+ build_linux:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ lfs: true
+ - name: Get thirdParty cache
+ id: cache-thirdParty
+ uses: actions/cache@v2
+ with:
+ path: |
+ third_party
+ vendor_tools
+ key: third_party-linux-${{ hashFiles('DEPS') }}-${{ hashFiles('vendor.json') }}
+ restore-keys: third_party-linux-
+
+ - uses: seanmiddleditch/gha-setup-ninja@master
+ - name: Run sync_deps script
+ run: |
+ chmod +x sync_deps.sh
+ ./sync_deps.sh
+
+ - if: github.event_name == 'push'
+ name: Build cache(push)
+ run: |
+ node build_vendor -p linux
+
+ - if: github.event_name == 'pull_request'
+ name: Run build_linux script
+ run: |
+ chmod +x build_linux.sh
+ ./build_linux.sh
+ cd linux
+ mkdir build
+ cd build
+ cmake ../
+ make -j8
\ No newline at end of file
diff --git a/.github/workflows/build_web.yml b/.github/workflows/build_web.yml
new file mode 100644
index 00000000..b72d83bb
--- /dev/null
+++ b/.github/workflows/build_web.yml
@@ -0,0 +1,92 @@
+# This is a basic workflow to help you get started with Actions
+
+name: build_web
+
+# Controls when the workflow will run
+on:
+ # Triggers the workflow on push or pull request events but only for the master branch
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+ build_web:
+ # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
+ # You can convert this to a matrix build if you need cross-platform coverage.
+ # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+ runs-on: macos-latest
+
+ steps:
+ - name: Get environment cache
+ id: cache-environment
+ uses: actions/cache@v2
+ with:
+ path: |
+ /usr/local/Cellar/ninja
+ /usr/local/Cellar/icu4c
+ /usr/local/bin/ninja
+ /usr/local/Cellar/yasm
+ /usr/local/bin/yasm
+ /usr/local/bin/depsync
+ /usr/local/lib/node_modules/depsync
+ /usr/local/Cellar/gcovr
+ /usr/local/bin/gcovr
+ /usr/local/Cellar/emsdk
+ /usr/local/Cellar/emsdk/upstream/emscripten
+ /usr/local/Cellar/emsdk/node/14.18.2_64bit/bin
+ /usr/local/bin/em++
+ /usr/local/bin/em-config
+ /usr/local/bin/emar
+ /usr/local/bin/embuilder
+ /usr/local/bin/emcc
+ /usr/local/bin/emcmake
+ /usr/local/bin/emconfigure
+ /usr/local/bin/emdump
+ /usr/local/bin/emdwp
+ /usr/local/bin/emmake
+ /usr/local/bin/emnm
+ /usr/local/bin/emrun
+ /usr/local/bin/emprofile
+ /usr/local/bin/emscons
+ /usr/local/bin/emsize
+ /usr/local/bin/emstrip
+ /usr/local/bin/emsymbolizer
+ /usr/local/bin/emcc.py
+ /usr/local/bin/emcmake.py
+ /usr/local/bin/emar.py
+ key: tgfx-environment-autotest-20221018
+ restore-keys: |
+ tgfx-environment-autotest-20221018
+ - uses: actions/checkout@v3
+ with:
+ lfs: true
+ - name: Get thirdParty cache
+ id: cache-thirdParty
+ uses: actions/cache@v2
+ with:
+ path: |
+ third_party
+ vendor_tools
+ web/node_node_modules
+ key: third_party-web-${{ hashFiles('DEPS') }}-${{ hashFiles('vendor.json') }}
+ restore-keys: third_party-web-
+
+ - name: Run sync_deps script
+ run: |
+ chmod +x sync_deps.sh
+ ./sync_deps.sh
+
+ - if: github.event_name == 'push'
+ name: Build cache(push)
+ run: |
+ node build_vendor -p web
+ if [ ! $(which gcovr) ]; then
+ brew install gcovr
+ fi
+ - if: github.event_name == 'pull_request'
+ name: Run build script
+ run: |
+ cd web/script
+ chmod +x build.sh
+ ./build.sh
diff --git a/.github/workflows/build_win.yml b/.github/workflows/build_win.yml
new file mode 100644
index 00000000..f9385de1
--- /dev/null
+++ b/.github/workflows/build_win.yml
@@ -0,0 +1,49 @@
+# This is a basic workflow to help you get started with Actions
+
+name: build_win
+
+# Controls when the workflow will run
+on:
+ # Triggers the workflow on push or pull request events but only for the master branch
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+ build_win:
+ # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
+ # You can convert this to a matrix build if you need cross-platform coverage.
+ # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+ runs-on: windows-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ lfs: true
+ - name: Get thirdParty cache
+ id: cache-thirdParty
+ uses: actions/cache@v2
+ with:
+ path: |
+ third_party
+ vendor_tools
+ key: third_party-win-${{ hashFiles('DEPS') }}-${{ hashFiles('vendor.json') }}
+ restore-keys: third_party-win-
+
+ - name: Run depsync
+ run: |
+ npm install depsync -g
+ depsync
+ shell: bash
+
+ - if: github.event_name == 'push'
+ name: Build cache(push)
+ run: |
+ node build_vendor -p win
+
+ - if: github.event_name == 'pull_request'
+ name: Windows build
+ run: |
+ node ./vendor_tools/cmake-build tgfx -p win -a x64 -o ./win/libtgfx -v -i
+ shell: bash
\ No newline at end of file
diff --git a/.github/workflows/code_format.yml b/.github/workflows/code_format.yml
new file mode 100644
index 00000000..8d323f4c
--- /dev/null
+++ b/.github/workflows/code_format.yml
@@ -0,0 +1,25 @@
+name: code_format
+
+on:
+ pull_request:
+ branches: [ main ]
+ push:
+ branches: [ main ]
+
+env:
+ # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
+ BUILD_TYPE: Debug
+
+jobs:
+ code_format:
+ # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
+ # You can convert this to a matrix build if you need cross-platform coverage.
+ # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
+ runs-on: macos-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Run codeformat script
+ run: |
+ chmod +x codeformat.sh
+ ./codeformat.sh
+ shell: bash
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..bfc87c83
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,78 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+#*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+#*.a
+#*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+# Gradle
+captures/
+build/
+
+
+# Android
+.gradle
+.externalNativeBuild
+local.properties
+
+# IDEA Projects
+!.idea
+**/.idea/*
+!**/.idea/fileTemplates/
+!**/.idea/misc.xml
+
+/third_party
+/out
+cmake-build-*
+node_modules
+Build/
+test/out/
+DerivedData/
+xcuserdata
+xcshareddata
+*.xcworkspace
+.DS_Store
+.temp
+Pods/
+Podfile.lock
+Adobe After Effects Auto-Save/
+.cxx
+/.sync_deps.cmake
+/build.yml
+.vs
+win/Win32Demo/x64
+win/x64
+win/build
+win/libtgfx
+win/Debug/
+win/Release/
+win/Win32Demo/Debug/
+win/Win32Demo/Release/
+QTCMAKE.cfg
+test/baseline/.cache
+/result
+
+
+vendor_tools/
+.vscode
\ No newline at end of file
diff --git a/.idea/fileTemplates/includes/TGFX File Header.h b/.idea/fileTemplates/includes/TGFX File Header.h
new file mode 100644
index 00000000..9a045aca
--- /dev/null
+++ b/.idea/fileTemplates/includes/TGFX File Header.h
@@ -0,0 +1,17 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/.idea/fileTemplates/internal/C Header File.h b/.idea/fileTemplates/internal/C Header File.h
new file mode 100644
index 00000000..d7f0678b
--- /dev/null
+++ b/.idea/fileTemplates/internal/C Header File.h
@@ -0,0 +1,7 @@
+#parse("TGFX File Header.h")
+
+#pragma once
+
+namespace tgfx {
+
+} // namespace tgfx
diff --git a/.idea/fileTemplates/internal/C Source File.c b/.idea/fileTemplates/internal/C Source File.c
new file mode 100644
index 00000000..6b8866ad
--- /dev/null
+++ b/.idea/fileTemplates/internal/C Source File.c
@@ -0,0 +1,4 @@
+#parse("TGFX File Header.h")
+#if (${HEADER_FILENAME})
+#[[#include]]# "${HEADER_FILENAME}"
+#end
diff --git a/.idea/fileTemplates/internal/C++ Class Header.h b/.idea/fileTemplates/internal/C++ Class Header.h
new file mode 100644
index 00000000..e1c28ff0
--- /dev/null
+++ b/.idea/fileTemplates/internal/C++ Class Header.h
@@ -0,0 +1,9 @@
+#parse("TGFX File Header.h")
+
+#pragma once
+
+namespace tgfx {
+class ${NAME} {
+ public:
+};
+} // namespace tgfx
diff --git a/.idea/fileTemplates/internal/C++ Class.cc b/.idea/fileTemplates/internal/C++ Class.cc
new file mode 100644
index 00000000..6df4f00d
--- /dev/null
+++ b/.idea/fileTemplates/internal/C++ Class.cc
@@ -0,0 +1,7 @@
+#parse("TGFX File Header.h")
+
+#[[#include]]# "${HEADER_FILENAME}"
+
+namespace tgfx {
+
+} // namespace tgfx
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..0213d840
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 00000000..91e60cd7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,344 @@
+cmake_minimum_required(VERSION 3.1)
+project(TGFX)
+
+#set(CMAKE_VERBOSE_MAKEFILE ON)
+include(./vendor_tools/vendor.cmake)
+
+# Options for building tgfx
+option(TGFX_USE_OPENGL "Allow use of OpenGL as GPU backend" ON)
+option(TGFX_USE_QT "Allow build with QT frameworks." OFF)
+option(TGFX_USE_SWIFTSHADER "Allow build with SwiftShader library" OFF)
+
+if (APPLE OR WEB)
+ option(TGFX_USE_FREETYPE "Allow use of embedded freetype library" OFF)
+else ()
+ option(TGFX_USE_FREETYPE "Allow use of embedded freetype library" ON)
+endif ()
+
+if (IOS OR WEB)
+ option(TGFX_USE_WEBP_DECODE "Enable embedded WEBP decoding support" ON)
+elseif (NOT ANDROID)
+ option(TGFX_USE_PNG_DECODE "Enable embedded PNG decoding support" ON)
+ option(TGFX_USE_PNG_ENCODE "Enable embedded PNG encoding support" ON)
+ option(TGFX_USE_JPEG_DECODE "Enable embedded JPEG decoding support" ON)
+ option(TGFX_USE_JPEG_ENCODE "Enable embedded JPEG encoding support" ON)
+ option(TGFX_USE_WEBP_DECODE "Enable embedded WEBP decoding support" ON)
+ option(TGFX_USE_WEBP_ENCODE "Enable embedded WEBP encoding support" ON)
+endif ()
+
+message("TGFX_USE_OPENGL: ${TGFX_USE_OPENGL}")
+message("TGFX_USE_QT: ${TGFX_USE_QT}")
+message("TGFX_USE_SWIFTSHADER: ${TGFX_USE_SWIFTSHADER}")
+message("TGFX_USE_FREETYPE: ${TGFX_USE_FREETYPE}")
+message("TGFX_USE_PNG_DECODE: ${TGFX_USE_PNG_DECODE}")
+message("TGFX_USE_PNG_ENCODE: ${TGFX_USE_PNG_ENCODE}")
+message("TGFX_USE_JPEG_DECODE: ${TGFX_USE_JPEG_DECODE}")
+message("TGFX_USE_JPEG_ENCODE: ${TGFX_USE_JPEG_ENCODE}")
+message("TGFX_USE_WEBP_DECODE: ${TGFX_USE_WEBP_DECODE}")
+message("TGFX_USE_WEBP_ENCODE: ${TGFX_USE_WEBP_ENCODE}")
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+cmake_policy(SET CMP0063 NEW)
+set(CMAKE_CXX_VISIBILITY_PRESET hidden)
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ add_definitions(-Werror -Wall -Wextra -Weffc++ -pedantic -Werror=return-type)
+endif ()
+
+if (MSVC)
+ add_compile_options("/utf-8")
+ add_compile_options(/w44251 /w44275)
+ add_definitions(-DNOMINMAX -D_USE_MATH_DEFINES)
+endif (MSVC)
+
+# Sets flags
+if (CMAKE_BUILD_TYPE STREQUAL "Debug")
+ add_definitions(-DDEBUG)
+ #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g -O1")
+endif ()
+
+# collects tgfx common files.
+set(TGFX_INCLUDES ./ include src)
+file(GLOB_RECURSE TGFX_FILES
+ src/core/*.*
+ src/effects/*.*
+ src/images/*.*
+ src/shaders/*.*
+ src/shapes/*.*
+ src/utils/*.*
+ src/gpu/*.*)
+
+file(GLOB TGFX_PLATFORM_COMMON_FILES
+ src/codecs/*.*
+ src/vectors/*.*
+ src/platform/*.*)
+list(APPEND TGFX_FILES ${TGFX_PLATFORM_COMMON_FILES})
+
+if (TGFX_USE_QT)
+ set(TGFX_USE_SWIFTSHADER OFF)
+endif ()
+
+if (TGFX_USE_QT OR TGFX_USE_SWIFTSHADER)
+ set(TGFX_USE_OPENGL ON)
+endif ()
+
+if (TGFX_USE_FREETYPE)
+ # Freetype needs libpng
+ set(TGFX_USE_PNG_DECODE ON)
+endif ()
+
+if (TGFX_USE_PNG_DECODE)
+ add_definitions(-DTGFX_USE_PNG_DECODE)
+ set(TGFX_USE_PNG ON)
+endif ()
+
+if (TGFX_USE_PNG_ENCODE)
+ add_definitions(-DTGFX_USE_PNG_ENCODE)
+ set(TGFX_USE_PNG ON)
+endif ()
+
+if (TGFX_USE_JPEG_DECODE)
+ add_definitions(-DTGFX_USE_JPEG_DECODE)
+ set(TGFX_USE_JPEG ON)
+endif ()
+
+if (TGFX_USE_JPEG_ENCODE)
+ add_definitions(-DTGFX_USE_JPEG_ENCODE)
+ set(TGFX_USE_JPEG ON)
+endif ()
+
+if (TGFX_USE_WEBP_DECODE)
+ add_definitions(-DTGFX_USE_WEBP_DECODE)
+ set(TGFX_USE_WEBP ON)
+endif ()
+
+if (TGFX_USE_WEBP_ENCODE)
+ add_definitions(-DTGFX_USE_WEBP_ENCODE)
+ set(TGFX_USE_WEBP ON)
+endif ()
+
+if (TGFX_USE_JPEG)
+ list(APPEND TGFX_STATIC_VENDORS libjpeg-turbo)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/codecs/jpeg/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+ list(APPEND TGFX_INCLUDES third_party/out/libjpeg-turbo/${INCLUDE_ENTRY})
+endif ()
+
+if (TGFX_USE_WEBP)
+ list(APPEND TGFX_STATIC_VENDORS libwebp)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/codecs/webp/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+ list(APPEND TGFX_INCLUDES third_party/libwebp/src)
+endif ()
+
+if (TGFX_USE_PNG)
+ set(TGFX_USE_ZLIB ON)
+ list(APPEND TGFX_STATIC_VENDORS libpng)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/codecs/png/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+ list(APPEND TGFX_INCLUDES third_party/out/libpng/${INCLUDE_ENTRY})
+endif ()
+
+if (TGFX_USE_ZLIB)
+ list(APPEND TGFX_STATIC_VENDORS zlib)
+endif ()
+
+if (TGFX_USE_FREETYPE)
+ add_definitions(-DTGFX_USE_FREETYPE)
+ list(APPEND TGFX_STATIC_VENDORS freetype)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/vectors/freetype/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+ list(APPEND TGFX_INCLUDES third_party/freetype/include)
+elseif (WEB)
+ add_definitions(-DTGFX_BUILD_FOR_WEB)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/vectors/web/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+elseif (APPLE)
+ # Uses CoreGraphics instead.
+ add_definitions(-DTGFX_USE_CORE_GRAPHICS)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/vectors/coregraphics/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+endif ()
+
+if (TGFX_USE_OPENGL)
+ file(GLOB GFX_PLATFORM_FILES src/opengl/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+ file(GLOB_RECURSE GFX_PROCESSOR_FILES src/opengl/processors/*.*)
+ list(APPEND TGFX_FILES ${GFX_PROCESSOR_FILES})
+elseif (ANDROID)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/vulkan/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+elseif (APPLE)
+ file(GLOB_RECURSE GFX_PLATFORM_FILES src/metal/*.*)
+ list(APPEND TGFX_FILES ${GFX_PLATFORM_FILES})
+ find_library(Metal_LIBS Metal REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${Metal_LIBS})
+endif ()
+
+file(GLOB_RECURSE EGL_PLATFORM_FILES src/opengl/egl/*.*)
+
+if (TGFX_USE_QT)
+ # need to set the CMAKE_PREFIX_PATH to local QT installation path, for example :
+ # set(CMAKE_PREFIX_PATH /Users/username/Qt5.13.0/5.13.0/clang_64/lib/cmake)
+ find_package(Qt5OpenGL REQUIRED)
+ find_package(Qt5Gui REQUIRED)
+ find_package(Qt5Quick REQUIRED)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${Qt5OpenGL_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
+ list(APPEND GPU_PLATFORM_INCLUDES ${Qt5OpenGL_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS} ${Qt5Quick_INCLUDE_DIRS})
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/qt/*.*)
+ if (MACOS)
+ file(GLOB CGL_PLATFORM_FILES src/opengl/cgl/CGLHardwareTexture.mm)
+ list(APPEND GPU_PLATFORM_FILES ${CGL_PLATFORM_FILES})
+ add_definitions(-DGL_SILENCE_DEPRECATION)
+ find_library(OpenGL_LIBS OpenGL REQUIRED)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${OpenGL_LIBS})
+ endif ()
+elseif (TGFX_USE_SWIFTSHADER)
+ list(APPEND GPU_PLATFORM_INCLUDES vendor/swiftshader/include)
+ file(GLOB SWIFTSHADER_LIBS vendor/swiftshader/${LIBRARY_ENTRY}/*${CMAKE_SHARED_LIBRARY_SUFFIX})
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${SWIFTSHADER_LIBS})
+ list(APPEND GPU_PLATFORM_FILES ${EGL_PLATFORM_FILES})
+else ()
+ set(TGFX_USE_NATIVE_GL ON)
+endif ()
+
+list(APPEND TGFX_STATIC_VENDORS pathkit)
+list(APPEND TGFX_INCLUDES third_party/pathkit)
+list(APPEND TGFX_STATIC_VENDORS skcms)
+list(APPEND TGFX_INCLUDES third_party/skcms)
+
+if (WEB)
+ file(GLOB_RECURSE PLATFORM_FILES src/platform/web/*.*)
+ list(APPEND TGFX_PLATFORM_FILES ${PLATFORM_FILES})
+ if (TGFX_USE_NATIVE_GL)
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/webgl/*.*)
+ endif ()
+elseif (IOS)
+ # finds all required platform libraries.
+ find_library(UIKit_LIBS UIKit REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${UIKit_LIBS})
+ find_library(Foundation_LIBS Foundation REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${Foundation_LIBS})
+ find_library(QuartzCore_LIBS QuartzCore REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${QuartzCore_LIBS})
+ find_library(CoreGraphics_LIBS CoreGraphics REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CoreGraphics_LIBS})
+ find_library(CoreText_LIBS CoreText REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CoreText_LIBS})
+ find_library(CoreMedia_LIBS CoreMedia REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CoreMedia_LIBS})
+ find_library(CoreMedia_LIBS CoreMedia REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CoreMedia_LIBS})
+ find_library(ImageIO_LIBS ImageIO REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${ImageIO_LIBS})
+ find_library(CORE_VIDEO CoreVideo)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CORE_VIDEO})
+ find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${ICONV_LIBRARIES})
+
+ file(GLOB_RECURSE PLATFORM_FILES src/platform/apple/*.*)
+ list(APPEND TGFX_PLATFORM_FILES ${PLATFORM_FILES})
+
+ if (TGFX_USE_NATIVE_GL)
+ add_definitions(-DGL_SILENCE_DEPRECATION)
+ find_library(OpenGLES_LIBS OpenGLES REQUIRED)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${OpenGLES_LIBS})
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/eagl/*.*)
+ endif ()
+elseif (MACOS)
+ # finds all required platform libraries.
+ find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
+ find_library(QUARTZ_CORE QuartzCore REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${QUARTZ_CORE})
+ find_library(COCOA Cocoa REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${COCOA})
+ find_library(FOUNDATION Foundation REQUIRED)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${FOUNDATION})
+ find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${ICONV_LIBRARIES})
+ find_library(CORE_MEDIA CoreMedia)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CORE_MEDIA})
+
+ file(GLOB_RECURSE PLATFORM_FILES src/platform/apple/*.*)
+ list(APPEND TGFX_PLATFORM_FILES ${PLATFORM_FILES})
+
+ if (TGFX_USE_NATIVE_GL)
+ add_definitions(-DGL_SILENCE_DEPRECATION)
+ find_library(OpenGL_LIBS OpenGL REQUIRED)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${OpenGL_LIBS})
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/cgl/*.*)
+ endif ()
+
+elseif (ANDROID)
+
+ find_library(LOG_LIB log)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${LOG_LIB})
+ find_library(ANDROID_LIB android)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${ANDROID_LIB})
+ find_library(JNIGRAPHICS_LIB jnigraphics)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${JNIGRAPHICS_LIB})
+
+ file(GLOB_RECURSE PLATFORM_FILES src/platform/android/*.*)
+ list(APPEND TGFX_PLATFORM_FILES ${PLATFORM_FILES})
+
+ if (TGFX_USE_NATIVE_GL)
+ find_library(GLESV2_LIB GLESv2)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${GLESV2_LIB})
+ find_library(EGL_LIB EGL)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${EGL_LIB})
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/egl/*.*)
+ endif ()
+
+ # optimizes the output size
+ add_compile_options(-ffunction-sections -fdata-sections -Os -fno-exceptions -fno-rtti)
+
+elseif (WIN32)
+ find_library(Bcrypt_LIB Bcrypt)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${Bcrypt_LIB})
+ find_library(ws2_32_LIB ws2_32)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${ws2_32_LIB})
+ find_library(DWrite_LIB DWrite)
+ list(APPEND TGFX_PLATFORM_STATIC_LIBS ${DWrite_LIB})
+
+ file(GLOB_RECURSE PLATFORM_FILES src/platform/mock/*.*)
+ list(APPEND TGFX_PLATFORM_FILES ${PLATFORM_FILES})
+
+ if (TGFX_USE_NATIVE_GL)
+ file(GLOB ANGLE_LIBS vendor/angle/${PLATFORM}/${ARCH}/*${CMAKE_STATIC_LIBRARY_SUFFIX})
+ list(APPEND GPU_PLATFORM_STATIC_LIBS ${ANGLE_LIBS})
+ list(APPEND GPU_PLATFORM_INCLUDES vendor/angle/include)
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/egl/*.*)
+ endif ()
+elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
+ find_package(Threads)
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS ${CMAKE_THREAD_LIBS_INIT})
+ list(APPEND TGFX_PLATFORM_SHARED_LIBS dl)
+ add_compile_options(-fPIC -pthread)
+
+ file(GLOB_RECURSE PLATFORM_FILES src/platform/mock/*.*)
+ list(APPEND TGFX_PLATFORM_FILES ${PLATFORM_FILES})
+
+ if (TGFX_USE_NATIVE_GL)
+ find_library(GLESV2_LIB GLESv2)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${GLESV2_LIB})
+ find_library(EGL_LIB EGL)
+ list(APPEND GPU_PLATFORM_SHARED_LIBS ${EGL_LIB})
+ file(GLOB_RECURSE GPU_PLATFORM_FILES src/opengl/egl/*.*)
+ endif ()
+endif ()
+
+add_vendor_target(TGFX STATIC_VENDORS ${TGFX_STATIC_VENDORS} SHARED_VENDORS ${TGFX_SHARED_VENDORS})
+list(APPEND TGFX_PLATFORM_STATIC_LIBS ${TGFX_VENDOR_STATIC_LIBRARIES})
+list(APPEND TGFX_PLATFORM_SHARED_LIBS ${TGFX_VENDOR_SHARED_LIBRARIES})
+
+get_directory_property(HasParent PARENT_DIRECTORY)
+if (HasParent)
+ set(TGFX_PLATFORM_STATIC_LIBS ${TGFX_PLATFORM_STATIC_LIBS} PARENT_SCOPE)
+endif ()
+
+add_library(tgfx STATIC ${TGFX_VENDOR_TARGET} ${PLATFORM_VENDOR_TARGETS} ${TGFX_FILES} ${TGFX_PLATFORM_FILES} ${GPU_PLATFORM_FILES})
+target_include_directories(tgfx PUBLIC include PRIVATE ${TGFX_INCLUDES} ${GPU_PLATFORM_INCLUDES})
+merge_libraries_into(tgfx ${TGFX_STATIC_LIBS} ${TGFX_PLATFORM_STATIC_LIBS})
+target_link_libraries(tgfx ${TGFX_PLATFORM_SHARED_LIBS} ${GPU_PLATFORM_SHARED_LIBS})
\ No newline at end of file
diff --git a/CODEOWNERS b/CODEOWNERS
new file mode 100644
index 00000000..ef4ddca0
--- /dev/null
+++ b/CODEOWNERS
@@ -0,0 +1,12 @@
+# Default owners:
+* @domchen @lvpengwei @luckyzhliu
+
+*.js @domchen @lvpengwei @luckyzhliu
+*.ts @domchen @lvpengwei @luckyzhliu
+*.sh @kevingpqi123 @domchen @lvpengwei @luckyzhliu
+/* @kevingpqi123 @domchen @lvpengwei @luckyzhliu
+/web/ @domchen @lvpengwei @luckyzhliu
+/.github/ @kevingpqi123 @domchen @lvpengwei @luckyzhliu
+/test/ @kevingpqi123 @domchen @lvpengwei @luckyzhliu
+/linux/ @kevingpqi123 @domchen @lvpengwei @luckyzhliu
+/win/ @FusionXu @kevingpqi123 @domchen @lvpengwei @luckyzhliu
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 00000000..1353ef58
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,50 @@
+# Contributing to tgfx
+Welcome to [report Issues](https://github.com/Tencent/tgfx/issues) or [pull requests](https://github.com/Tencent/tgfx/pulls). It's recommended to read the following Contributing Guide first before contributing.
+
+## Issues
+We use Github Issues to track public bugs and feature requests.
+
+### Search Known Issues First
+Please search the existing issues to see if any similar issue or feature request has already been filed. You should make sure your issue isn't redundant.
+
+### Reporting New Issues
+If you open an issue, the more information the better. Such as detailed description, screenshot or video of your problem, logcat and xlog or code blocks for your crash.
+
+## Pull Requests
+We strongly welcome your pull request to make tgfx better.
+
+### Branch Management
+There are two main branches here:
+
+1. `main` branch.
+ 1. It is our active developing branch. After full testing, we will periodically pull the pre-release branch based on the main branch.
+ 2. **You are recommended to submit bugfix or feature PR on `main` branch.**
+2. `release/{version}` branch.
+ 1. This is our stable release branch, which is fully tested and already used in many apps.
+
+Normal bugfix or feature request should be submitted to `main` branch.
+
+
+### Make Pull Requests
+The code team will monitor all pull request, we run some code check and test on it. After all tests passed, we will accecpt this PR.
+
+Before submitting a pull request, please make sure the followings are done:
+
+1. Fork the repo and create your branch from `main`.
+2. Update code or documentation if you have changed APIs.
+3. Add the copyright notice to the top of any new files you've added.
+4. Check your code lints and checkstyles.
+5. Test and test again your code.
+6. Now, you can submit your pull request on `main` branch.
+
+## Code Style Guide
+Use [Code Style for C/C++](http://zh-google-styleguide.readthedocs.io/en/latest/google-cpp-styleguide/).
+
+It is recommended to configure the clang-format we provide in the IDE
+
+* 2 spaces for indentation rather than tabs
+
+
+## License
+By contributing to tgfx, you agree that your contributions will be licensed
+under its [BSD 3-Clause License](./LICENSE.txt)
\ No newline at end of file
diff --git a/CPPLINT.cfg b/CPPLINT.cfg
new file mode 100644
index 00000000..88729376
--- /dev/null
+++ b/CPPLINT.cfg
@@ -0,0 +1,9 @@
+linelength=100
+root=src
+exclude_files=mac
+exclude_files=android
+exclude_files=ios
+exclude_files=qt
+exclude_files=vendor
+exclude_files=test
+exclude_files=.idea
\ No newline at end of file
diff --git a/DEPS b/DEPS
new file mode 100644
index 00000000..8d9d4714
--- /dev/null
+++ b/DEPS
@@ -0,0 +1,81 @@
+{
+ "version": "1.3.1",
+ "vars": {
+ "PAG_GROUP": "https://github.com/libpag"
+ },
+ "repos": {
+ "common": [
+ {
+ "url": "${PAG_GROUP}/vendor_tools.git",
+ "commit": "5593395a4a4328bc7e5ff11e5e90fc20ac61983c",
+ "dir": "vendor_tools"
+ },
+ {
+ "url": "${PAG_GROUP}/pathkit.git",
+ "commit": "f0c4736442a8e640e7f7978b6b9ed322148245bb",
+ "dir": "third_party/pathkit"
+ },
+ {
+ "url": "${PAG_GROUP}/skcms.git",
+ "commit": "26af768d918c8f9a693ce6ee1a0fc6611559d29e",
+ "dir": "third_party/skcms"
+ },
+ {
+ "url": "${PAG_GROUP}/swiftshader.git",
+ "commit": "040ee43bfeba9b6b532dbd8222df737aac2d55b1",
+ "dir": "third_party/swiftshader"
+ },
+ {
+ "url": "https://github.com/madler/zlib.git",
+ "commit": "cacf7f1d4e3d44d871b605da3b647f07d718623f",
+ "dir": "third_party/zlib"
+ },
+ {
+ "url": "https://github.com/glennrp/libpng.git",
+ "commit": "a40189cf881e9f0db80511c382292a5604c3c3d1",
+ "dir": "third_party/libpng"
+ },
+ {
+ "url": "https://github.com/webmproject/libwebp.git",
+ "commit": "9ce5843dbabcfd3f7c39ec7ceba9cbeb213cbfdf",
+ "dir": "third_party/libwebp"
+ },
+ {
+ "url": "https://github.com/libjpeg-turbo/libjpeg-turbo.git",
+ "commit": "0a9b9721782d3a60a5c16c8c9a7abf3d4b1ecd42",
+ "dir": "third_party/libjpeg-turbo"
+ },
+ {
+ "url": "https://github.com/freetype/freetype.git",
+ "commit": "86bc8a95056c97a810986434a3f268cbe67f2902",
+ "dir": "third_party/freetype"
+ },
+ {
+ "url": "https://github.com/google/googletest.git",
+ "commit": "e2239ee6043f73722e7aa812a459f54a28552929",
+ "dir": "third_party/googletest"
+ },
+ {
+ "url": "https://github.com/nlohmann/json.git",
+ "commit": "fec56a1a16c6e1c1b1f4e116a20e79398282626c",
+ "dir": "third_party/json"
+ }
+ ]
+ },
+ "actions": {
+ "common": [
+ {
+ "command": "depsync --clean",
+ "dir": "third_party"
+ },
+ {
+ "command": "git lfs prune",
+ "dir": "./"
+ },
+ {
+ "command": "git lfs pull",
+ "dir": "./"
+ }
+ ]
+ }
+}
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 00000000..e67fff0e
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,647 @@
+Tencent is pleased to support the open source community by making tgfx available.
+
+Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved. The below software in this distribution may have been modified by THL A29 Limited ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2022 THL A29 Limited.
+
+tgfx is licensed under the BSD 3-Clause License except for the third-party components listed below.
+
+
+Terms of the BSD 3-Clause License:
+--------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Other dependencies and licenses:
+
+
+Open Source Software Licensed under the The FreeType Project LICENSE and Other Licenses of the Third-Party Components therein:
+--------------------------------------------------------------------
+1. freetype
+Copyright (C) 2006-2022 by
+David Turner, Robert Wilhelm, and Werner Lemberg.
+
+
+Terms of the The FreeType Project LICENSE:
+--------------------------------------------------------------------
+The FreeType Project LICENSE
+ ----------------------------
+ 2006-Jan-27
+ Copyright 1996-2002, 2006 by
+ David Turner, Robert Wilhelm, and Werner Lemberg
+Introduction
+============
+ The FreeType Project is distributed in several archive packages;
+ some of them may contain, in addition to the FreeType font engine,
+ various tools and contributions which rely on, or relate to, the
+ FreeType Project.
+ This license applies to all files found in such packages, and
+ which do not fall under their own explicit license. The license
+ affects thus the FreeType font engine, the test programs,
+ documentation and makefiles, at the very least.
+ This license was inspired by the BSD, Artistic, and IJG
+ (Independent JPEG Group) licenses, which all encourage inclusion
+ and use of free software in commercial and freeware products
+ alike. As a consequence, its main points are that:
+ o We don't promise that this software works. However, we will be
+ interested in any kind of bug reports. (`as is' distribution)
+ o You can use this software for whatever you want, in parts or
+ full form, without having to pay us. (`royalty-free' usage)
+ o You may not pretend that you wrote this software. If you use
+ it, or only parts of it, in a program, you must acknowledge
+ somewhere in your documentation that you have used the
+ FreeType code. (`credits')
+ We specifically permit and encourage the inclusion of this
+ software, with or without modifications, in commercial products.
+ We disclaim all warranties covering The FreeType Project and
+ assume no liability related to The FreeType Project.
+ Finally, many people asked us for a preferred form for a
+ credit/disclaimer to use in compliance with this license. We thus
+ encourage you to use the following text:
+ """
+ Portions of this software are copyright © The FreeType
+ Project (www.freetype.org). All rights reserved.
+ """
+ Please replace with the value from the FreeType version you
+ actually use.
+Legal Terms
+===========
+0. Definitions
+--------------
+ Throughout this license, the terms `package', `FreeType Project',
+ and `FreeType archive' refer to the set of files originally
+ distributed by the authors (David Turner, Robert Wilhelm, and
+ Werner Lemberg) as the `FreeType Project', be they named as alpha,
+ beta or final release.
+ `You' refers to the licensee, or person using the project, where
+ `using' is a generic term including compiling the project's source
+ code as well as linking it to form a `program' or `executable'.
+ This program is referred to as `a program using the FreeType
+ engine'.
+ This license applies to all files distributed in the original
+ FreeType Project, including all source code, binaries and
+ documentation, unless otherwise stated in the file in its
+ original, unmodified form as distributed in the original archive.
+ If you are unsure whether or not a particular file is covered by
+ this license, you must contact us to verify this.
+ The FreeType Project is copyright (C) 1996-2000 by David Turner,
+ Robert Wilhelm, and Werner Lemberg. All rights reserved except as
+ specified below.
+1. No Warranty
+--------------
+ THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
+ KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
+ USE, OF THE FREETYPE PROJECT.
+2. Redistribution
+-----------------
+ This license grants a worldwide, royalty-free, perpetual and
+ irrevocable right and license to use, execute, perform, compile,
+ display, copy, create derivative works of, distribute and
+ sublicense the FreeType Project (in both source and object code
+ forms) and derivative works thereof for any purpose; and to
+ authorize others to exercise some or all of the rights granted
+ herein, subject to the following conditions:
+ o Redistribution of source code must retain this license file
+ (`FTL.TXT') unaltered; any additions, deletions or changes to
+ the original files must be clearly indicated in accompanying
+ documentation. The copyright notices of the unaltered,
+ original files must be preserved in all copies of source
+ files.
+ o Redistribution in binary form must provide a disclaimer that
+ states that the software is based in part of the work of the
+ FreeType Team, in the distribution documentation. We also
+ encourage you to put an URL to the FreeType web page in your
+ documentation, though this isn't mandatory.
+ These conditions apply to any software derived from or based on
+ the FreeType Project, not just the unmodified files. If you use
+ our work, you must acknowledge us. However, no fee need be paid
+ to us.
+3. Advertising
+--------------
+ Neither the FreeType authors and contributors nor you shall use
+ the name of the other for commercial, advertising, or promotional
+ purposes without specific prior written permission.
+ We suggest, but do not require, that you use one or more of the
+ following phrases to refer to this software in your documentation
+ or advertising materials: `FreeType Project', `FreeType Engine',
+ `FreeType library', or `FreeType Distribution'.
+ As you have not signed this license, you are not required to
+ accept it. However, as the FreeType Project is copyrighted
+ material, only this license, or another one contracted with the
+ authors, grants you the right to use, distribute, and modify it.
+ Therefore, by using, distributing, or modifying the FreeType
+ Project, you indicate that you understand and accept all the terms
+ of this license.
+4. Contacts
+-----------
+ There are two mailing lists related to FreeType:
+ o freetype@nongnu.org
+ Discusses general use and applications of FreeType, as well as
+ future and wanted additions to the library and distribution.
+ If you are looking for support, start in this list if you
+ haven't found anything to help you in the documentation.
+ o freetype-devel@nongnu.org
+ Discusses bugs, as well as engine internals, design issues,
+ specific licenses, porting, etc.
+ Our home page can be found at
+ https://www.freetype.org
+--- end of FTL.TXT ---
+
+
+
+Other Licenses of the Third-Party Components therein can be obtained from:
+https://skia.googlesource.com/third_party/freetype2.git/+/refs/heads/master/LICENSE.TXT
+
+
+Open Source Software Licensed under the IJG License and Other Licenses of the Third-Party Components therein:
+--------------------------------------------------------------------
+1. libjpeg-turbo
+Copyright (C) 1991-1996, Thomas G. Lane.
+Copyright (C) 2017, D. R. Commander.
+
+
+Terms of the IJG License:
+--------------------------------------------------------------------
+The Independent JPEG Group's JPEG software
+==========================================
+
+This distribution contains a release of the Independent JPEG Group's free JPEG
+software. You are welcome to redistribute this software and to use it for any
+purpose, subject to the conditions under LEGAL ISSUES, below.
+
+This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone,
+Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson,
+Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers,
+and other members of the Independent JPEG Group.
+
+IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee
+(also known as JPEG, together with ITU-T SG16).
+
+
+DOCUMENTATION ROADMAP
+=====================
+
+This file contains the following sections:
+
+OVERVIEW General description of JPEG and the IJG software.
+LEGAL ISSUES Copyright, lack of warranty, terms of distribution.
+REFERENCES Where to learn more about JPEG.
+ARCHIVE LOCATIONS Where to find newer versions of this software.
+FILE FORMAT WARS Software *not* to get.
+TO DO Plans for future IJG releases.
+
+Other documentation files in the distribution are:
+
+User documentation:
+ usage.txt Usage instructions for cjpeg, djpeg, jpegtran,
+ rdjpgcom, and wrjpgcom.
+ *.1 Unix-style man pages for programs (same info as usage.txt).
+ wizard.txt Advanced usage instructions for JPEG wizards only.
+ change.log Version-to-version change highlights.
+Programmer and internal documentation:
+ libjpeg.txt How to use the JPEG library in your own programs.
+ example.txt Sample code for calling the JPEG library.
+ structure.txt Overview of the JPEG library's internal structure.
+ coderules.txt Coding style rules --- please read if you contribute code.
+
+Please read at least usage.txt. Some information can also be found in the JPEG
+FAQ (Frequently Asked Questions) article. See ARCHIVE LOCATIONS below to find
+out where to obtain the FAQ article.
+
+If you want to understand how the JPEG code works, we suggest reading one or
+more of the REFERENCES, then looking at the documentation files (in roughly
+the order listed) before diving into the code.
+
+
+OVERVIEW
+========
+
+This package contains C software to implement JPEG image encoding, decoding,
+and transcoding. JPEG (pronounced "jay-peg") is a standardized compression
+method for full-color and grayscale images. JPEG's strong suit is compressing
+photographic images or other types of images that have smooth color and
+brightness transitions between neighboring pixels. Images with sharp lines or
+other abrupt features may not compress well with JPEG, and a higher JPEG
+quality may have to be used to avoid visible compression artifacts with such
+images.
+
+JPEG is lossy, meaning that the output pixels are not necessarily identical to
+the input pixels. However, on photographic content and other "smooth" images,
+very good compression ratios can be obtained with no visible compression
+artifacts, and extremely high compression ratios are possible if you are
+willing to sacrifice image quality (by reducing the "quality" setting in the
+compressor.)
+
+This software implements JPEG baseline, extended-sequential, and progressive
+compression processes. Provision is made for supporting all variants of these
+processes, although some uncommon parameter settings aren't implemented yet.
+We have made no provision for supporting the hierarchical or lossless
+processes defined in the standard.
+
+We provide a set of library routines for reading and writing JPEG image files,
+plus two sample applications "cjpeg" and "djpeg", which use the library to
+perform conversion between JPEG and some other popular image file formats.
+The library is intended to be reused in other applications.
+
+In order to support file conversion and viewing software, we have included
+considerable functionality beyond the bare JPEG coding/decoding capability;
+for example, the color quantization modules are not strictly part of JPEG
+decoding, but they are essential for output to colormapped file formats or
+colormapped displays. These extra functions can be compiled out of the
+library if not required for a particular application.
+
+We have also included "jpegtran", a utility for lossless transcoding between
+different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple
+applications for inserting and extracting textual comments in JFIF files.
+
+The emphasis in designing this software has been on achieving portability and
+flexibility, while also making it fast enough to be useful. In particular,
+the software is not intended to be read as a tutorial on JPEG. (See the
+REFERENCES section for introductory material.) Rather, it is intended to
+be reliable, portable, industrial-strength code. We do not claim to have
+achieved that goal in every aspect of the software, but we strive for it.
+
+We welcome the use of this software as a component of commercial products.
+No royalty is required, but we do ask for an acknowledgement in product
+documentation, as described under LEGAL ISSUES.
+
+
+LEGAL ISSUES
+============
+
+In plain English:
+
+1. We don't promise that this software works. (But if you find any bugs,
+ please let us know!)
+2. You can use this software for whatever you want. You don't have to pay us.
+3. You may not pretend that you wrote this software. If you use it in a
+ program, you must acknowledge somewhere in your documentation that
+ you've used the IJG code.
+
+In legalese:
+
+The authors make NO WARRANTY or representation, either express or implied,
+with respect to this software, its quality, accuracy, merchantability, or
+fitness for a particular purpose. This software is provided "AS IS", and you,
+its user, assume the entire risk as to its quality and accuracy.
+
+This software is copyright (C) 1991-2016, Thomas G. Lane, Guido Vollbeding.
+All Rights Reserved except as specified below.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+software (or portions thereof) for any purpose, without fee, subject to these
+conditions:
+(1) If any part of the source code for this software is distributed, then this
+README file must be included, with this copyright and no-warranty notice
+unaltered; and any additions, deletions, or changes to the original files
+must be clearly indicated in accompanying documentation.
+(2) If only executable code is distributed, then the accompanying
+documentation must state that "this software is based in part on the work of
+the Independent JPEG Group".
+(3) Permission for use of this software is granted only if the user accepts
+full responsibility for any undesirable consequences; the authors accept
+NO LIABILITY for damages of any kind.
+
+These conditions apply to any software derived from or based on the IJG code,
+not just to the unmodified library. If you use our work, you ought to
+acknowledge us.
+
+Permission is NOT granted for the use of any IJG author's name or company name
+in advertising or publicity relating to this software or products derived from
+it. This software may be referred to only as "the Independent JPEG Group's
+software".
+
+We specifically permit and encourage the use of this software as the basis of
+commercial products, provided that all warranty or liability claims are
+assumed by the product vendor.
+
+
+The IJG distribution formerly included code to read and write GIF files.
+To avoid entanglement with the Unisys LZW patent (now expired), GIF reading
+support has been removed altogether, and the GIF writer has been simplified
+to produce "uncompressed GIFs". This technique does not use the LZW
+algorithm; the resulting GIF files are larger than usual, but are readable
+by all standard GIF decoders.
+
+We are required to state that
+ "The Graphics Interchange Format(c) is the Copyright property of
+ CompuServe Incorporated. GIF(sm) is a Service Mark property of
+ CompuServe Incorporated."
+
+
+REFERENCES
+==========
+
+We recommend reading one or more of these references before trying to
+understand the innards of the JPEG software.
+
+The best short technical introduction to the JPEG compression algorithm is
+ Wallace, Gregory K. "The JPEG Still Picture Compression Standard",
+ Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44.
+(Adjacent articles in that issue discuss MPEG motion picture compression,
+applications of JPEG, and related topics.) If you don't have the CACM issue
+handy, a PDF file containing a revised version of Wallace's article is
+available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually
+a preprint for an article that appeared in IEEE Trans. Consumer Electronics)
+omits the sample images that appeared in CACM, but it includes corrections
+and some added material. Note: the Wallace article is copyright ACM and IEEE,
+and it may not be used for commercial purposes.
+
+A somewhat less technical, more leisurely introduction to JPEG can be found in
+"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by
+M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides
+good explanations and example C code for a multitude of compression methods
+including JPEG. It is an excellent source if you are comfortable reading C
+code but don't know much about data compression in general. The book's JPEG
+sample code is far from industrial-strength, but when you are ready to look
+at a full implementation, you've got one here...
+
+The best currently available description of JPEG is the textbook "JPEG Still
+Image Data Compression Standard" by William B. Pennebaker and Joan L.
+Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1.
+Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG
+standards (DIS 10918-1 and draft DIS 10918-2).
+
+The original JPEG standard is divided into two parts, Part 1 being the actual
+specification, while Part 2 covers compliance testing methods. Part 1 is
+titled "Digital Compression and Coding of Continuous-tone Still Images,
+Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS
+10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of
+Continuous-tone Still Images, Part 2: Compliance testing" and has document
+numbers ISO/IEC IS 10918-2, ITU-T T.83.
+
+The JPEG standard does not specify all details of an interchangeable file
+format. For the omitted details, we follow the "JFIF" conventions, revision
+1.02. JFIF version 1 has been adopted as ISO/IEC 10918-5 (05/2013) and
+Recommendation ITU-T T.871 (05/2011): Information technology - Digital
+compression and coding of continuous-tone still images: JPEG File Interchange
+Format (JFIF). It is available as a free download in PDF file format from
+https://www.iso.org/standard/54989.html and http://www.itu.int/rec/T-REC-T.871.
+A PDF file of the older JFIF 1.02 specification is available at
+http://www.w3.org/Graphics/JPEG/jfif3.pdf.
+
+The TIFF 6.0 file format specification can be obtained by FTP from
+ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme
+found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems.
+IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6).
+Instead, we recommend the JPEG design proposed by TIFF Technical Note #2
+(Compression tag 7). Copies of this Note can be obtained from
+http://www.ijg.org/files/. It is expected that the next revision
+of the TIFF spec will replace the 6.0 JPEG design with the Note's design.
+Although IJG's own code does not support TIFF/JPEG, the free libtiff library
+uses our library to implement TIFF/JPEG per the Note.
+
+
+ARCHIVE LOCATIONS
+=================
+
+The "official" archive site for this software is www.ijg.org.
+The most recent released version can always be found there in
+directory "files".
+
+The JPEG FAQ (Frequently Asked Questions) article is a source of some
+general information about JPEG.
+It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/
+and other news.answers archive sites, including the official news.answers
+archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/.
+If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu
+with body
+ send usenet/news.answers/jpeg-faq/part1
+ send usenet/news.answers/jpeg-faq/part2
+
+
+FILE FORMAT COMPATIBILITY
+=========================
+
+This software implements ITU T.81 | ISO/IEC 10918 with some extensions from
+ITU T.871 | ISO/IEC 10918-5 (JPEG File Interchange Format-- see REFERENCES).
+Informally, the term "JPEG image" or "JPEG file" most often refers to JFIF or
+a subset thereof, but there are other formats containing the name "JPEG" that
+are incompatible with the DCT-based JPEG standard or with JFIF (for instance,
+JPEG 2000 and JPEG XR). This software therefore does not support these
+formats. Indeed, one of the original reasons for developing this free software
+was to help force convergence on a common, interoperable format standard for
+JPEG files.
+
+JFIF is a minimal or "low end" representation. TIFF/JPEG (TIFF revision 6.0 as
+modified by TIFF Technical Note #2) can be used for "high end" applications
+that need to record a lot of additional data about an image.
+
+
+TO DO
+=====
+
+Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org.
+
+
+
+Other Licenses of the Third-Party Components therein can be obtained from:
+https://github.com/libjpeg-turbo/libjpeg-turbo/blob/2.0.0/LICENSE.md
+
+
+Open Source Software Licensed under the libpng license:
+--------------------------------------------------------------------
+1. libpng
+Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson
+
+
+Terms of the libpng license:
+--------------------------------------------------------------------
+This copy of the libpng notices is provided for your convenience. In case of
+any discrepancy between this copy and the notices in the file png.h that is
+included in the libpng distribution, the latter shall prevail.
+
+COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+
+If you modify libpng you may insert additional notices immediately following
+this sentence.
+
+This code is released under the libpng license.
+
+libpng versions 1.0.7, July 1, 2000 through 1.6.33, September 28, 2017 are
+Copyright (c) 2000-2002, 2004, 2006-2017 Glenn Randers-Pehrson, are
+derived from libpng-1.0.6, and are distributed according to the same
+disclaimer and license as libpng-1.0.6 with the following individuals
+added to the list of Contributing Authors:
+
+ Simon-Pierre Cadieux
+ Eric S. Raymond
+ Mans Rullgard
+ Cosmin Truta
+ Gilles Vollant
+ James Yu
+ Mandar Sahastrabuddhe
+ Google Inc.
+ Vadim Barkov
+
+and with the following additions to the disclaimer:
+
+ There is no warranty against interference with your enjoyment of the
+ library or against infringement. There is no warranty that our
+ efforts or the library will fulfill any of your particular purposes
+ or needs. This library is provided with all faults, and the entire
+ risk of satisfactory quality, performance, accuracy, and effort is with
+ the user.
+
+Some files in the "contrib" directory and some configure-generated
+files that are distributed with libpng have other copyright owners and
+are released under other open source licenses.
+
+libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
+libpng-0.96, and are distributed according to the same disclaimer and
+license as libpng-0.96, with the following individuals added to the list
+of Contributing Authors:
+
+ Tom Lane
+ Glenn Randers-Pehrson
+ Willem van Schaik
+
+libpng versions 0.89, June 1996, through 0.96, May 1997, are
+Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
+and are distributed according to the same disclaimer and license as
+libpng-0.88, with the following individuals added to the list of
+Contributing Authors:
+
+ John Bowler
+ Kevin Bracey
+ Sam Bushell
+ Magnus Holmgren
+ Greg Roelofs
+ Tom Tanner
+
+Some files in the "scripts" directory have other copyright owners
+but are released under this license.
+
+libpng versions 0.5, May 1995, through 0.88, January 1996, are
+Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
+
+For the purposes of this copyright and license, "Contributing Authors"
+is defined as the following set of individuals:
+
+ Andreas Dilger
+ Dave Martindale
+ Guy Eric Schalnat
+ Paul Schmidt
+ Tim Wegner
+
+The PNG Reference Library is supplied "AS IS". The Contributing Authors
+and Group 42, Inc. disclaim all warranties, expressed or implied,
+including, without limitation, the warranties of merchantability and of
+fitness for any purpose. The Contributing Authors and Group 42, Inc.
+assume no liability for direct, indirect, incidental, special, exemplary,
+or consequential damages, which may result from the use of the PNG
+Reference Library, even if advised of the possibility of such damage.
+
+Permission is hereby granted to use, copy, modify, and distribute this
+source code, or portions hereof, for any purpose, without fee, subject
+to the following restrictions:
+
+ 1. The origin of this source code must not be misrepresented.
+
+ 2. Altered versions must be plainly marked as such and must not
+ be misrepresented as being the original source.
+
+ 3. This Copyright notice may not be removed or altered from any
+ source or altered source distribution.
+
+The Contributing Authors and Group 42, Inc. specifically permit, without
+fee, and encourage the use of this source code as a component to
+supporting the PNG file format in commercial products. If you use this
+source code in a product, acknowledgment is not required but would be
+appreciated.
+
+END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE.
+
+TRADEMARK:
+
+The name "libpng" has not been registered by the Copyright owner
+as a trademark in any jurisdiction. However, because libpng has
+been distributed and maintained world-wide, continually since 1995,
+the Copyright owner claims "common-law trademark protection" in any
+jurisdiction where common-law trademark is recognized.
+
+OSI CERTIFICATION:
+
+Libpng is OSI Certified Open Source Software. OSI Certified Open Source is
+a certification mark of the Open Source Initiative. OSI has not addressed
+the additional disclaimers inserted at version 1.0.7.
+
+EXPORT CONTROL:
+
+The Copyright owner believes that the Export Control Classification
+Number (ECCN) for libpng is EAR99, which means not subject to export
+controls or International Traffic in Arms Regulations (ITAR) because
+it is open source, publicly available software, that does not contain
+any encryption software. See the EAR, paragraphs 734.3(b)(3) and
+734.7(b).
+
+Glenn Randers-Pehrson
+glennrp at users.sourceforge.net
+September 28, 2017
+
+
+
+Open Source Software Licensed under the BSD 3-Clause License:
+The below software in this distribution may have been modified by THL A29 Limited ("Tencent Modifications"). All Tencent Modifications are Copyright (C) 2022 THL A29 Limited.
+--------------------------------------------------------------------
+1. libwebp
+Copyright (c) 2010, Google Inc. All rights reserved.
+
+2. pathKit
+Copyright (c) 2011 Google Inc. All rights reserved.
+
+3. skcms
+Copyright 2018 Google Inc.
+
+
+Terms of the BSD 3-Clause License:
+--------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Open Source Software Licensed under the Zlib License:
+--------------------------------------------------------------------
+1. zlib
+Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+
+
+Terms of the Zlib License:
+--------------------------------------------------------------------
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+ (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..93a0f7f7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,124 @@
+
+
+[![license](https://img.shields.io/badge/license-BSD--3--Clause-blue)](https://github.com/libpag/tgfx/blob/master/LICENSE.txt)
+[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/libpag/tgfx/pulls)
+[![codecov](https://codecov.io/gh/libpag/tgfx/branch/main/graph/badge.svg)](https://codecov.io/gh/libpag/tgfx)
+[![Actions Status](https://github.com/libpag/tgfx/workflows/autotest/badge.svg?branch=main)](https://github.com/libpag/tgfx/actions)
+[![GitHub release (latest SemVer)](https://img.shields.io/github/v/release/libpag/tgfx)](https://github.com/libpag/tgfx/releases)
+
+## Introduction
+
+TGFX (Tencent Graphics) is a lightweight 2D graphics library designed for rendering texts,
+geometries, and images. It provides high-performance APIs that work across a variety of hardware and
+software platforms. TGFX was initially created as a core component of the [PAG](https://pag.art)
+project and has since become the default graphics engine for the [libpag](https://github.com/Tencent/libpag)
+library, starting from version 4.0. Its main objective is to offer a compelling alternative to the
+Skia graphics library while maintaining a smaller binary size. Over time, it has found its way into
+many other products, such as [Tencent Docs](https://docs.qq.com) and various video-editing apps.
+
+## Platform Support
+
+| Vector Backend | GPU Backend | Target Platforms | Status |
+|:--------------:|:--------------:|:----------------------------:|:-------------:|
+| FreeType | OpenGL | All | complete |
+| CoreGraphics | OpenGL | iOS, macOS | complete |
+| Canvas2D | WebGL | Web | complete |
+| CoreGraphics | Metal | iOS, macOS | in progress |
+| FreeType | Vulkan | Android, Linux | planned |
+
+
+## Branch Management
+
+- The `main` branch is our active developing branch which contains the latest features and bugfixes.
+- The branches under `release/` are our stable milestone branches which are fully tested. We will
+ periodically cut a `release/{version}` branch from the `main` branch. After one `release/{version}`
+ branch is cut, only high-priority fixes are checked into it.
+
+## System Requirements
+
+- iOS 9.0 or later
+- Android 4.4 or later
+- macOS 10.13 or later
+- Windows 7.0 or later
+- Chrome 69.0 or later (Web)
+- Safari 11.3 or later (Web)
+
+## Build Prerequisites
+
+- Xcode 11.0+
+- GCC 7.0+
+- CMake 3.10.2+
+- Visual Studio 2019
+- NDK 19.2.5345600 (**Please use this exact version of NDK, other versions may fail.**)
+
+## Dependency Management
+
+TGFX uses [depsync](https://github.com/domchen/depsync) tool to manage third-party dependencies.
+
+**For macOS platform:**
+
+Run the script in the root of the project:
+
+```
+./sync_deps.sh
+```
+
+This script will automatically install the necessary tools and synchronize all third-party repositories.
+
+**For other platforms:**
+
+First, make sure you have installed the latest version of node.js (You may need to restart your
+computer after this step). And then run the following command to install depsync tool:
+
+```
+npm install -g depsync
+```
+
+And then run `depsync` in the root directory of the project.
+
+```
+depsync
+```
+
+Git account and password may be required during synchronizing. Please make sure you have enabled the
+`git-credential-store` so that `CMakeList.txt` can trigger synchronizing automatically next time.
+
+
+## Build & Run
+
+We recommend using CLion IDE on the macOS platform for development. After the synchronization, you
+can open the project with CLion and build the TGFX library.
+
+**For macOS platform:**
+
+There are no extra configurations of CLion required.
+
+**For Windows platform:**
+
+Please follow the following steps to configure the CLion environment correctly:
+
+- Make sure you have installed at least the **[Desktop development with C++]** and **[Universal Windows Platform development]** components for VS2019.
+- Open the **File->Setting** panel, and go to **Build, Execution, Deployment->ToolChains**, then set the toolchain of CLion to **Visual Studio** with **amd64 (Recommended)** or **x86** architecture.
+
+**Note: If anything goes wrong during cmake building, please update the cmake commandline tool to the latest
+version and try again.**
+
+
+## Support Us
+
+If you find TGFX is helpful, please give us a **Star**. We sincerely appreciate your support :)
+
+
+## License
+
+TGFX is licensed under the [BSD-3-Clause License](./LICENSE.txt)
+
+[![Star History Chart](https://api.star-history.com/svg?repos=libpag/tgfx&type=Date)](https://star-history.com/#libpag/tgfx&Date)
+
+## Contribution
+
+If you have any ideas or suggestions to improve TGFX, welcome to open
+a [discussion](https://github.com/libpag/tgfx/discussions/new/choose)
+/ [issue](https://github.com/libpag/tgfx/issues/new/choose)
+/ [pull request](https://github.com/libpag/tgfx/pulls). Before making a pull request or issue,
+please make sure to read [Contributing Guide](./CONTRIBUTING.md).
diff --git a/autotest.sh b/autotest.sh
new file mode 100755
index 00000000..a0c8a619
--- /dev/null
+++ b/autotest.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+function make_dir() {
+ rm -rf $1
+ mkdir -p $1
+}
+echo "shell log - autotest start"
+if [[ $(uname) == 'Darwin' ]]; then
+ MAC_REQUIRED_TOOLS="gcovr"
+ for TOOL in ${MAC_REQUIRED_TOOLS[@]}; do
+ if [ ! $(which $TOOL) ]; then
+ if [ ! $(which brew) ]; then
+ echo "Homebrew not found. Trying to install..."
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ||
+ exit 1
+ fi
+ echo "$TOOL not found. Trying to install..."
+ brew install $TOOL || exit 1
+ fi
+ done
+fi
+
+echo $(pwd)
+
+COMPLIE_RESULT=true
+
+WORKSPACE=$(pwd)
+
+cd $WORKSPACE
+
+make_dir result
+make_dir build
+
+./update_baseline.sh 1
+cp -r $WORKSPACE/test/baseline $WORKSPACE/result
+
+cd build
+
+cmake -DCMAKE_CXX_FLAGS="-fprofile-arcs -ftest-coverage -g -O0" -DTGFX_USE_SWIFTSHADER=ON -DCMAKE_BUILD_TYPE=Debug ../
+if test $? -eq 0; then
+ echo "~~~~~~~~~~~~~~~~~~~CMakeLists OK~~~~~~~~~~~~~~~~~~"
+else
+ echo "~~~~~~~~~~~~~~~~~~~CMakeLists error~~~~~~~~~~~~~~~~~~"
+ exit
+fi
+
+cmake --build . --target TGFXFullTest -- -j 12
+if test $? -eq 0; then
+ echo "~~~~~~~~~~~~~~~~~~~TGFXFullTest make successed~~~~~~~~~~~~~~~~~~"
+else
+ echo "~~~~~~~~~~~~~~~~~~~TGFXFullTest make error~~~~~~~~~~~~~~~~~~"
+ exit 1
+fi
+
+./TGFXFullTest --gtest_output=json:TGFXFullTest.json
+
+if test $? -eq 0; then
+ echo "~~~~~~~~~~~~~~~~~~~TGFXFullTest successed~~~~~~~~~~~~~~~~~~"
+else
+ echo "~~~~~~~~~~~~~~~~~~~TGFXFullTest Failed~~~~~~~~~~~~~~~~~~"
+ COMPLIE_RESULT=false
+fi
+
+cp -a $WORKSPACE/build/*.json $WORKSPACE/result/
+
+cd ..
+
+gcovr -r . -e='test/*.*' -e='vendor/*.*'--html -o ./result/coverage.html
+gcovr -r . -e='test/*.*' -e='vendor/*.*' --xml-pretty -o ./result/coverage.xml
+
+rm -rf build
+
+cp -r $WORKSPACE/test/out $WORKSPACE/result
+
+if [ "$COMPLIE_RESULT" == false ]; then
+ exit 1
+fi
diff --git a/build_vendor b/build_vendor
new file mode 100755
index 00000000..dcf1bdd2
--- /dev/null
+++ b/build_vendor
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+// run 'node build_vendor -h" to print help message
+require("./vendor_tools/build");
\ No newline at end of file
diff --git a/codeformat.sh b/codeformat.sh
new file mode 100755
index 00000000..cb8cc075
--- /dev/null
+++ b/codeformat.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+if [[ $(uname) == 'Darwin' ]]; then
+ MAC_REQUIRED_TOOLS="python3"
+ for TOOL in ${MAC_REQUIRED_TOOLS[@]}; do
+ if [ ! $(which $TOOL) ]; then
+ if [ ! $(which brew) ]; then
+ echo "Homebrew not found. Trying to install..."
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ||
+ exit 1
+ fi
+ echo "$TOOL not found. Trying to install..."
+ brew install $TOOL || exit 1
+ fi
+ done
+ clangformat=`clang-format --version`
+ if [[ $clangformat =~ "14." ]]
+ then
+ echo "----$clangformat----"
+ else
+ echo "----install clang-format----"
+ pip3 install clang-format==14
+ fi
+fi
+
+echo "----begin to scan code format----"
+find include/ -iname '*.h' -print0 | xargs clang-format -i
+# shellcheck disable=SC2038
+find src -name "*.cpp" -print -o -name "*.h" -print -o -name "*.mm" -print -o -name "*.m" -print | xargs clang-format -i
+# shellcheck disable=SC2038
+find test \( -path test/framework/lzma \) -prune -o -name "*.cpp" -print -o -name "*.h" -print | xargs clang-format -i
+
+git diff
+result=`git diff`
+if [[ $result =~ "diff" ]]
+then
+ echo "----Failed to pass coding specification----"
+ exit 1
+else
+ echo "----Pass coding specification----"
+fi
+
+echo "----Complete the scan code format-----"
+
diff --git a/include/tgfx/core/AlphaType.h b/include/tgfx/core/AlphaType.h
new file mode 100644
index 00000000..f7aaf56e
--- /dev/null
+++ b/include/tgfx/core/AlphaType.h
@@ -0,0 +1,44 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Describes how to interpret the alpha component of a pixel.
+ */
+enum class AlphaType {
+ /**
+ * uninitialized.
+ */
+ Unknown,
+ /**
+ * pixel is opaque.
+ */
+ Opaque,
+ /**
+ * pixel components are premultiplied by alpha.
+ */
+ Premultiplied,
+ /**
+ * pixel components are independent of alpha.
+ */
+ Unpremultiplied,
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Bitmap.h b/include/tgfx/core/Bitmap.h
new file mode 100644
index 00000000..b8ba84ac
--- /dev/null
+++ b/include/tgfx/core/Bitmap.h
@@ -0,0 +1,237 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Color.h"
+#include "tgfx/core/Data.h"
+#include "tgfx/core/EncodedFormat.h"
+#include "tgfx/core/ImageBuffer.h"
+#include "tgfx/core/ImageInfo.h"
+#include "tgfx/platform/HardwareBuffer.h"
+
+namespace tgfx {
+class PixelRef;
+
+/**
+ * Bitmap describes a two-dimensional raster pixel array. Bitmap points to PixelRef, which describes
+ * the physical array of pixels and is optimized for creating textures. If the pixel array is
+ * primarily read-only, use Image for better performance. Declaring Bitmap const prevents altering
+ * ImageInfo: the Bitmap height, width, and so on cannot change. It does not affect PixelRef: a
+ * caller may write its pixels. Bitmap is not thread safe.
+ */
+class Bitmap {
+ public:
+ /**
+ * Creates an empty Bitmap without pixels, and with an empty ImageInfo.
+ */
+ Bitmap() = default;
+
+ /**
+ * Creates a new Bitmap and tries to allocate its pixels by the specified width, height, and
+ * native color type. If the alphaOnly is true, sets ImageInfo to ColorType::ALPHA_8. If the
+ * tryHardware is true and there is hardware buffer support on the current platform, a hardware
+ * backed PixelRef is allocated. Otherwise, a raster PixelRef is allocated. The isEmpty() method
+ * of the Bitmap will return true if allocation fails.
+ */
+ Bitmap(int width, int height, bool alphaOnly = false, bool tryHardware = true);
+
+ /**
+ * Copies settings from src to returned Bitmap. Shares pixels if src has pixels allocated, so both
+ * bitmaps reference the same pixels.
+ */
+ Bitmap(const Bitmap& src);
+
+ /**
+ * Copies settings from src to returned Bitmap. Moves ownership of src pixels to Bitmap.
+ */
+ Bitmap(Bitmap&& src);
+
+ /**
+ * Creates a new Bitmap from the platform-specific hardware buffer. For example, the hardware
+ * buffer could be an AHardwareBuffer on the android platform or a CVPixelBufferRef on the apple
+ * platform. The Bitmap takes a reference to the hardwareBuffer.
+ */
+ explicit Bitmap(HardwareBufferRef hardwareBuffer);
+
+ /**
+ * Copies settings from src to returned Bitmap. Shares pixels if src has pixels allocated, so both
+ * bitmaps reference the same pixels.
+ */
+ Bitmap& operator=(const Bitmap& src);
+
+ /**
+ * Copies settings from src to returned Bitmap. Moves ownership of src pixels to Bitmap.
+ */
+ Bitmap& operator=(Bitmap&& src);
+
+ /**
+ * Sets ImageInfo to width, height, and the native color type; and allocates pixel memory. If
+ * the alphaOnly is true, sets ImageInfo to ColorType::ALPHA_8. If the tryHardware is true and
+ * there is hardware buffer support on the current platform, a hardware-backed PixelRef is
+ * allocated. Otherwise, a raster PixelRef is allocated. Returns true if the PixelRef is
+ * allocated successfully.
+ */
+ bool allocPixels(int width, int height, bool alphaOnly = false, bool tryHardware = true);
+
+ /**
+ * Locks and returns the writable pixels, the base address corresponding to the pixel origin.
+ */
+ void* lockPixels();
+
+ /**
+ * Locks and returns the read-only pixels, the base address corresponding to the pixel origin.
+ */
+ const void* lockPixels() const;
+
+ /**
+ * Call this to balance a successful call to lockPixels().
+ */
+ void unlockPixels() const;
+
+ /**
+ * Return true if the Bitmap describes an empty area of pixels.
+ */
+ bool isEmpty() const {
+ return _info.isEmpty();
+ }
+
+ /**
+ * Returns an ImageInfo describing the width, height, color type, alpha type, and row bytes of the
+ * pixels.
+ */
+ const ImageInfo& info() const {
+ return _info;
+ }
+
+ /**
+ * Returns the width of the pixels.
+ */
+ int width() const {
+ return _info.width();
+ }
+
+ /**
+ * Returns the height of the pixels.
+ */
+ int height() const {
+ return _info.height();
+ }
+
+ /**
+ * Returns the ColorType of the pixels.
+ */
+ ColorType colorType() const {
+ return _info.colorType();
+ }
+
+ /**
+ * Returns the AlphaType of the pixels.
+ */
+ AlphaType alphaType() const {
+ return _info.alphaType();
+ }
+
+ /**
+ * Returns true if pixels represent transparency only. If true, each pixel is packed in 8 bits as
+ * defined by ColorType::ALPHA_8.
+ */
+ bool isAlphaOnly() const {
+ return _info.isAlphaOnly();
+ }
+
+ /**
+ * Returns the rowBytes of the pixels.
+ */
+ size_t rowBytes() const {
+ return _info.rowBytes();
+ }
+
+ /**
+ * Returns the byte size of the pixels.
+ */
+ size_t byteSize() const {
+ return _info.byteSize();
+ }
+
+ /**
+ * Returns true if the Bitmap is backed by a platform-specified hardware buffer. A hardware-backed
+ * Bitmap allows sharing buffers across CPU and GPU, which can be used to speed up the texture
+ * uploading.
+ */
+ bool isHardwareBacked() const;
+
+ /**
+ * Retrieves the backing hardware buffer. This method does not acquire any additional reference to
+ * the returned hardware buffer. Returns nullptr if the Bitmap is not backed by a hardware buffer.
+ */
+ HardwareBufferRef getHardwareBuffer() const;
+
+ /**
+ * Encodes the pixels in Bitmap into a binary image format.
+ * @param format One of: EncodedFormat::JPEG, EncodedFormat::PNG, EncodedFormat::WEBP
+ * @param quality A platform and format specific metric trading off size and encoding error. When
+ * used, quality equaling 100 encodes with the least error. quality may be ignored by the encoder.
+ * @return Returns nullptr if encoding fails, or if the format is not supported.
+ */
+ std::shared_ptr encode(EncodedFormat format = EncodedFormat::PNG, int quality = 100) const;
+
+ /**
+ * Returns pixel at (x, y) as unpremultiplied color. Some color precision may be lost in the
+ * conversion to unpremultiplied color; original pixel data may have additional precision. Returns
+ * a transparent color if the point (x, y) is not contained by bounds.
+ */
+ Color getColor(int x, int y) const;
+
+ /**
+ * Copies a rect of pixels to dstPixels with specified ImageInfo. Copy starts at (srcX, srcY), and
+ * does not exceed Bitmap (width(), height()). Pixels are copied only if pixel conversion is
+ * possible. Returns true if pixels are copied to dstPixels.
+ */
+ bool readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX = 0, int srcY = 0) const;
+
+ /**
+ * Copies a rect of pixels from src. Copy starts at (dstX, dstY), and does not exceed
+ * Bitmap (width(), height()). Pixels are copied only if pixel conversion is possible and the
+ * bitmap is constructed from writable pixels. Returns true if src pixels are copied to Bitmap.
+ */
+ bool writePixels(const ImageInfo& srcInfo, const void* srcPixels, int dstX = 0, int dstY = 0);
+
+ /**
+ * Replaces all pixel values with transparent colors.
+ */
+ void clear();
+
+ /**
+ * Returns an ImageBuffer object capturing the pixels in the Bitmap. Subsequent writing of the
+ * Bitmap will not be captured. Instead, the Bitmap will copy its pixels to a new memory buffer if
+ * there is a subsequent writing call to the Bitmap while the returned ImageBuffer is still alive.
+ * If the Bitmap is modified frequently, create an ImageReader from the Bitmap instead, which
+ * allows you to continuously read the latest content from the Bitmap with minimal memory copying.
+ * Returns nullptr if the Bitmap is empty.
+ */
+ std::shared_ptr makeBuffer() const;
+
+ private:
+ ImageInfo _info = {};
+ std::shared_ptr pixelRef = nullptr;
+
+ friend class Pixmap;
+ friend class ImageReader;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/BlendMode.h b/include/tgfx/core/BlendMode.h
new file mode 100644
index 00000000..1a572554
--- /dev/null
+++ b/include/tgfx/core/BlendMode.h
@@ -0,0 +1,143 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Defines constant values for visual blend mode effects.
+ */
+enum class BlendMode {
+ /**
+ * Replaces destination with zero: fully transparent.
+ */
+ Clear,
+ /**
+ * Replaces destination.
+ */
+ Src,
+ /**
+ * Preserves destination.
+ */
+ Dst,
+ /**
+ * Source over destination.
+ */
+ SrcOver,
+ /**
+ * Destination over source.
+ */
+ DstOver,
+ /**
+ * Source trimmed inside destination.
+ */
+ SrcIn,
+ /**
+ * Destination trimmed by source.
+ */
+ DstIn,
+ /**
+ * Source trimmed outside destination.
+ */
+ SrcOut,
+ /**
+ * Destination trimmed outside source.
+ */
+ DstOut,
+ /**
+ * Source inside destination blended with destination.
+ */
+ SrcATop,
+ /**
+ * Destination inside source blended with source.
+ */
+ DstATop,
+ /**
+ * Each of source and destination trimmed outside the other.
+ */
+ Xor,
+ /**
+ * Sum of colors.
+ */
+ Plus,
+ /**
+ * Product of premultiplied colors; darkens destination.
+ */
+ Modulate,
+ /**
+ * Multiply inverse of pixels, inverting result; brightens destination.
+ */
+ Screen,
+ /**
+ * Multiply or screen, depending on destination.
+ */
+ Overlay,
+ /**
+ * Darker of source and destination.
+ */
+ Darken,
+ /**
+ * Lighter of source and destination.
+ */
+ Lighten,
+ /**
+ * Brighten destination to reflect source.
+ */
+ ColorDodge,
+ /**
+ * Darken destination to reflect source.
+ */
+ ColorBurn,
+ /**
+ * Multiply or screen, depending on source.
+ */
+ HardLight,
+ /**
+ * Lighten or darken, depending on source.
+ */
+ SoftLight,
+ /**
+ * Subtract darker from lighter with higher contrast.
+ */
+ Difference,
+ /**
+ * Subtract darker from lighter with lower contrast.
+ */
+ Exclusion,
+ /**
+ * Multiply source with destination, darkening image.
+ */
+ Multiply,
+ /**
+ * Hue of source with saturation and luminosity of destination.
+ */
+ Hue,
+ /**
+ * Saturation of source with hue and luminosity of destination.
+ */
+ Saturation,
+ /**
+ * Hue and saturation of source with luminosity of destination.
+ */
+ Color,
+ /**
+ * Luminosity of source with hue and saturation of destination.
+ */
+ Luminosity
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Canvas.h b/include/tgfx/core/Canvas.h
new file mode 100644
index 00000000..3e60f0b3
--- /dev/null
+++ b/include/tgfx/core/Canvas.h
@@ -0,0 +1,237 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/BlendMode.h"
+#include "tgfx/core/Font.h"
+#include "tgfx/core/Image.h"
+#include "tgfx/core/Paint.h"
+#include "tgfx/core/Path.h"
+#include "tgfx/core/SamplingOptions.h"
+#include "tgfx/core/Shape.h"
+#include "tgfx/core/TextBlob.h"
+
+namespace tgfx {
+class Surface;
+class SurfaceOptions;
+class Texture;
+struct CanvasState;
+class SurfaceDrawContext;
+class GpuPaint;
+
+/**
+ * Canvas provides an interface for drawing, and how the drawing is clipped and transformed. Canvas
+ * contains a stack of opacity, blend mode, matrix and clip values. Each Canvas draw call transforms
+ * the geometry of the object by the concatenation of all matrix values in the stack. The
+ * transformed geometry is clipped by the intersection of all of clip values in the stack.
+ */
+class Canvas {
+ public:
+ explicit Canvas(Surface* surface);
+
+ ~Canvas();
+
+ /**
+ * Retrieves the context associated with this Surface.
+ */
+ Context* getContext() const;
+
+ /**
+ * Returns the Surface this canvas draws into.
+ */
+ Surface* getSurface() const;
+
+ /**
+ * Returns the SurfaceOptions associated with the Canvas. Returns nullptr if the Canvas is not
+ * created from a Surface.
+ */
+ const SurfaceOptions* surfaceOptions() const;
+
+ /**
+ * Saves alpha, blend mode, matrix and clip. Calling restore() discards changes to them, restoring
+ * them to their state when save() was called. Saved Canvas state is put on a stack, multiple
+ * calls to save() should be balance by an equal number of calls to restore().
+ */
+ void save();
+
+ /**
+ * Removes changes to alpha, blend mode, matrix and clips since Canvas state was last saved. The
+ * state is removed from the stack. Does nothing if the stack is empty.
+ */
+ void restore();
+
+ /**
+ * Returns the current total matrix.
+ */
+ Matrix getMatrix() const;
+
+ /**
+ * Replaces transformation with specified matrix. Unlike concat(), any prior matrix state is
+ * overwritten.
+ * @param matrix matrix to copy, replacing existing Matrix
+ */
+ void setMatrix(const Matrix& matrix);
+
+ /**
+ * Sets Matrix to the identity matrix. Any prior matrix state is overwritten.
+ */
+ void resetMatrix();
+
+ /**
+ * Replaces the current Matrix with matrix premultiplied with the existing one. This has the
+ * effect of transforming the drawn geometry by matrix, before transforming the result with the
+ * existing Matrix.
+ */
+ void concat(const Matrix& matrix);
+
+ /**
+ * Returns the current global alpha.
+ */
+ float getAlpha() const;
+
+ /**
+ * Replaces the global alpha with specified newAlpha.
+ */
+ void setAlpha(float newAlpha);
+
+ /**
+ * Returns the current global blend mode.
+ */
+ BlendMode getBlendMode() const;
+
+ /**
+ * Replaces the global blend mode with specified new blend mode.
+ */
+ void setBlendMode(BlendMode blendMode);
+
+ /**
+ * Returns the current total clip.
+ */
+ Path getTotalClip() const;
+
+ /**
+ * Replaces clip with the intersection of clip and path. The path is transformed by Matrix before
+ * it is combined with clip.
+ */
+ void clipPath(const Path& path);
+
+ /**
+ * Fills clip with color. This has the effect of replacing all pixels contained by clip with
+ * color.
+ */
+ void clear(const Color& color = Color::Transparent());
+
+ /**
+ * Draws a rectangle with specified paint, using current current alpha, blend mode, clip and
+ * matrix.
+ */
+ void drawRect(const Rect& rect, const Paint& paint);
+
+ /**
+ * Draws a path with using current clip, matrix and specified paint.
+ */
+ void drawPath(const Path& path, const Paint& paint);
+
+ /**
+ * Draws a shape with using current clip, matrix and specified paint.
+ */
+ void drawShape(std::shared_ptr shape, const Paint& paint);
+
+ /**
+ * Draws an image, with its top-left corner at (left, top), using current clip, matrix and
+ * optional paint. If image->hasMipmaps() is true, uses FilterMode::Linear and MipMapMode::Linear
+ * as the sampling options. Otherwise, uses FilterMode::Linear and MipMapMode::None as the
+ * sampling options.
+ */
+ void drawImage(std::shared_ptr image, float left, float top, const Paint* paint = nullptr);
+
+ /**
+ * Draws a Image, with its top-left corner at (0, 0), using current alpha, clip and matrix
+ * premultiplied with existing Matrix. If image->hasMipmaps() is true, uses FilterMode::Linear
+ * and MipMapMode::Linear as the sampling options. Otherwise, uses FilterMode::Linear and
+ * MipMapMode::None as the sampling options.
+ */
+ void drawImage(std::shared_ptr image, const Matrix& matrix, const Paint* paint = nullptr);
+
+ /**
+ * Draws an image, with its top-left corner at (0, 0), using current clip, matrix and optional
+ * paint. If image->hasMipmaps() is true, uses FilterMode::Linear and MipMapMode::Linear as the
+ * sampling options. Otherwise, uses FilterMode::Linear and MipMapMode::None as the sampling
+ * options.
+ */
+ void drawImage(std::shared_ptr image, const Paint* paint = nullptr);
+
+ /**
+ * Draws an image, with its top-left corner at (0, 0), using current clip, matrix, sampling
+ * options and optional paint.
+ */
+ void drawImage(std::shared_ptr image, SamplingOptions sampling,
+ const Paint* paint = nullptr);
+
+ /**
+ * Draw array of glyphs with specified font, using current alpha, blend mode, clip and Matrix.
+ */
+ void drawGlyphs(const GlyphID glyphIDs[], const Point positions[], size_t glyphCount,
+ const Font& font, const Paint& paint);
+
+ // TODO(pengweilv): Support blend mode, atlas as source, colors as destination, colors can be
+ // nullptr.
+ void drawAtlas(std::shared_ptr atlas, const Matrix matrix[], const Rect tex[],
+ const Color colors[], size_t count, SamplingOptions sampling = SamplingOptions());
+
+ /**
+ * Triggers the immediate execution of all pending draw operations.
+ */
+ void flush();
+
+ private:
+ std::shared_ptr getClipTexture();
+
+ std::pair, bool> getClipRect();
+
+ std::unique_ptr getClipMask(const Rect& deviceBounds, Rect* scissorRect);
+
+ Rect clipLocalBounds(Rect localBounds);
+
+ void drawImage(std::shared_ptr image, SamplingOptions sampling, const Paint& paint);
+
+ void drawMask(const Rect& bounds, std::shared_ptr mask, GpuPaint paint);
+
+ void drawColorGlyphs(const GlyphID glyphIDs[], const Point positions[], size_t glyphCount,
+ const Font& font, const Paint& paint);
+
+ void drawMaskGlyphs(TextBlob* textBlob, const Paint& paint);
+
+ void fillPath(const Path& path, const Paint& paint);
+
+ bool drawAsClear(const Path& path, const GpuPaint& paint);
+
+ void draw(std::unique_ptr op, GpuPaint paint, bool aa = false);
+
+ bool nothingToDraw(const Paint& paint) const;
+
+ Surface* surface = nullptr;
+ std::shared_ptr _clipSurface = nullptr;
+ uint32_t clipID = 0;
+ std::shared_ptr state = nullptr;
+ SurfaceDrawContext* drawContext = nullptr;
+ std::vector> savedStateList = {};
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Color.h b/include/tgfx/core/Color.h
new file mode 100644
index 00000000..e631a08b
--- /dev/null
+++ b/include/tgfx/core/Color.h
@@ -0,0 +1,143 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+#include
+
+namespace tgfx {
+
+/**
+ * RGBA color value, holding four floating point components. Color components are always in a known
+ * order.
+ */
+struct Color {
+ /**
+ * Red component.
+ */
+ float red;
+
+ /**
+ * Green component.
+ */
+ float green;
+
+ /**
+ * Blue component.
+ */
+ float blue;
+
+ /**
+ * Alpha component.
+ */
+ float alpha;
+
+ /**
+ * Returns a fully transparent Color.
+ */
+ static const Color& Transparent();
+
+ /**
+ * Returns a fully opaque black Color.
+ */
+ static const Color& Black();
+
+ /**
+ * Returns a fully opaque white Color.
+ */
+ static const Color& White();
+
+ /**
+ * Returns color value from 8-bit component values.
+ */
+ static Color FromRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255);
+
+ /**
+ * Compares Color with other, and returns true if all components are equal.
+ */
+ bool operator==(const Color& other) const {
+ return alpha == other.alpha && red == other.red && green == other.green && blue == other.blue;
+ }
+
+ /**
+ * Compares Color with other, and returns true if not all components are equal.
+ */
+ bool operator!=(const Color& other) const {
+ return !(*this == other);
+ }
+
+ /**
+ * Returns a pointer to components of Color, for array access.
+ */
+ const float* array() const {
+ return &red;
+ }
+
+ /**
+ * Returns a pointer to components of Color, for array access.
+ */
+ float* array() {
+ return &red;
+ }
+
+ /**
+ * Returns one component.
+ * @param index one of: 0 (r), 1 (g), 2 (b), 3 (a)
+ * @return value corresponding to index.
+ */
+ float operator[](int index) const;
+
+ /**
+ * Returns one component.
+ * @param index one of: 0 (r), 1 (g), 2 (b), 3 (a)
+ * @return value corresponding to index.
+ */
+ float& operator[](int index);
+
+ /**
+ * Returns true if all channels are in [0, 1].
+ **/
+ bool isValid() const;
+
+ /**
+ * Returns true if Color is an opaque color.
+ */
+ bool isOpaque() const;
+
+ /**
+ * Returns a Color with alpha set to 1.0.
+ */
+ Color makeOpaque() const {
+ return {red, green, blue, 1.0f};
+ }
+
+ /**
+ * Returns a Color premultiplied by alpha.
+ */
+ Color premultiply() const {
+ return {red * alpha, green * alpha, blue * alpha, alpha};
+ }
+
+ /**
+ * Returns a Color unpremultiplied by alpha.
+ */
+ Color unpremultiply() const;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ColorFilter.h b/include/tgfx/core/ColorFilter.h
new file mode 100644
index 00000000..bdffb491
--- /dev/null
+++ b/include/tgfx/core/ColorFilter.h
@@ -0,0 +1,45 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+#include "tgfx/core/BlendMode.h"
+#include "tgfx/core/Color.h"
+
+namespace tgfx {
+class FragmentProcessor;
+
+class ColorFilter {
+ public:
+ static std::shared_ptr MakeLumaColorFilter();
+
+ static std::shared_ptr Blend(Color color, BlendMode mode);
+
+ static std::shared_ptr Matrix(const std::array& rowMajor);
+
+ virtual ~ColorFilter() = default;
+
+ virtual std::unique_ptr asFragmentProcessor() const = 0;
+
+ virtual bool isAlphaUnchanged() const {
+ return false;
+ }
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ColorType.h b/include/tgfx/core/ColorType.h
new file mode 100644
index 00000000..9fd6cfd0
--- /dev/null
+++ b/include/tgfx/core/ColorType.h
@@ -0,0 +1,72 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Describes how pixel bits encode color.
+ */
+enum class ColorType {
+ /**
+ * uninitialized.
+ */
+ Unknown,
+ /**
+ * Each pixel is stored as a single translucency (alpha) channel. This is very useful for
+ * storing masks efficiently, for instance. No color information is stored. With this
+ * configuration, each pixel requires 1 byte of memory.
+ */
+ ALPHA_8,
+ /**
+ * Each pixel is stored on 4 bytes. Each channel (RGB and alpha for translucency) is stored with 8
+ * bits of precision (256 possible values). The channel order is: red, green, blue, alpha.
+ */
+ RGBA_8888,
+ /**
+ * Each pixel is stored on 4 bytes. Each channel (RGB and alpha for translucency) is stored with 8
+ * bits of precision (256 possible values). The channel order is: blue, green, red, alpha.
+ */
+ BGRA_8888,
+ /**
+ * Each pixel is stored on 2 bytes, and only the RGB channels are encoded: red is stored with 5
+ * bits of precision (32 possible values), green is stored with 6 bits of precision (64 possible
+ * values), and blue is stored with 5 bits of precision.
+ */
+ RGB_565,
+ /**
+ * Each pixel is stored as a single grayscale level. No color information is stored. With this
+ * configuration, each pixel requires 1 byte of memory.
+ */
+ Gray_8,
+ /**
+ * Each pixel is stored on 8 bytes. Each channel (RGB and alpha for translucency) is stored as a
+ * half-precision floating point value. This configuration is particularly suited for wide-gamut
+ * and HDR content.
+ */
+ RGBA_F16,
+ /**
+ * Each pixel is stored on 4 bytes. Each RGB channel is stored with 10 bits of precision (1024
+ * possible values). There is an additional alpha channel that is stored with 2 bits of precision
+ * (4 possible values). This configuration is suited for wide-gamut and HDR content which does not
+ * require alpha blending, such that the memory cost is the same as RGBA_8888 while enabling
+ * higher color precision.
+ */
+ RGBA_1010102
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Data.h b/include/tgfx/core/Data.h
new file mode 100644
index 00000000..29c142f4
--- /dev/null
+++ b/include/tgfx/core/Data.h
@@ -0,0 +1,118 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+
+namespace tgfx {
+/**
+ * Data holds an immutable data buffer. Not only is the Data immutable, but the actual pointer
+ * that is returned by data() or bytes() is guaranteed to always be the same for the life of this
+ * instance.
+ */
+class Data {
+ public:
+ /**
+ * Creates a Data object from the specified file path.
+ */
+ static std::shared_ptr MakeFromFile(const std::string& filePath);
+
+ /**
+ * Creates a Data object by copying the specified data.
+ */
+ static std::shared_ptr MakeWithCopy(const void* data, size_t length);
+
+ /**
+ * Call this when the data parameter is already const, suitable for const globals. The caller must
+ * ensure the data parameter will always be the same and alive for the lifetime of the returned
+ * Data.
+ */
+ static std::shared_ptr MakeWithoutCopy(const void* data, size_t length);
+
+ /**
+ * Function that, if provided, will be called when the Data goes out of scope, allowing for
+ * custom allocation/freeing of the data's contents.
+ */
+ typedef void (*ReleaseProc)(const void* data, void* context);
+
+ /**
+ * A ReleaseProc using delete to release data.
+ */
+ static void DeleteProc(const void* data, void* context);
+
+ /**
+ * A ReleaseProc using free() to release data.
+ */
+ static void FreeProc(const void* data, void* context);
+
+ /**
+ * Creates a Data object, taking ownership of the specified data, and using the releaseProc to
+ * free it. The releaseProc may be nullptr.
+ */
+ static std::shared_ptr MakeAdopted(const void* data, size_t length,
+ ReleaseProc releaseProc = DeleteProc,
+ void* context = nullptr);
+
+ /**
+ * Creates a new empty Data object.
+ */
+ static std::shared_ptr MakeEmpty();
+
+ ~Data();
+
+ /**
+ * Returns the memory address of the data.
+ */
+ const void* data() const {
+ return _data;
+ }
+
+ /**
+ * Returns the read-only memory address of the data, but in this case it is cast to uint8_t*, to
+ * make it easy to add an offset to it.
+ */
+ const uint8_t* bytes() const {
+ return reinterpret_cast(_data);
+ }
+
+ /**
+ * Returns the byte size.
+ */
+ size_t size() const {
+ return _size;
+ }
+
+ /**
+ * Returns true if the Data is empty.
+ */
+ bool empty() const {
+ return _size == 0;
+ }
+
+ private:
+ const void* _data = nullptr;
+ size_t _size = 0;
+ ReleaseProc releaseProc = nullptr;
+ void* releaseContext = nullptr;
+
+ Data(const void* data, size_t length, ReleaseProc releaseProc, void* context);
+};
+
+} // namespace tgfx
diff --git a/include/tgfx/core/EncodedFormat.h b/include/tgfx/core/EncodedFormat.h
new file mode 100644
index 00000000..a8c854d6
--- /dev/null
+++ b/include/tgfx/core/EncodedFormat.h
@@ -0,0 +1,28 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+
+/**
+ * Describes the known formats a Pixmap can be encoded into.
+ */
+enum class EncodedFormat { JPEG, PNG, WEBP };
+
+} // namespace tgfx
diff --git a/include/tgfx/core/EncodedOrigin.h b/include/tgfx/core/EncodedOrigin.h
new file mode 100644
index 00000000..d68c3ff2
--- /dev/null
+++ b/include/tgfx/core/EncodedOrigin.h
@@ -0,0 +1,68 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Matrix.h"
+
+namespace tgfx {
+/**
+ * These values match the orientation www.exif.org/Exif2-2.PDF.
+ */
+enum class EncodedOrigin {
+ /**
+ * Default
+ */
+ TopLeft = 1,
+ /**
+ * Reflected across y-axis
+ */
+ TopRight = 2,
+ /**
+ * Rotated 180
+ */
+ BottomRight = 3,
+ /**
+ * Reflected across x-axis
+ */
+ BottomLeft = 4,
+ /**
+ * Reflected across x-axis, Rotated 90 CCW
+ */
+ LeftTop = 5,
+ /**
+ * Rotated 90 CW
+ */
+ RightTop = 6,
+ /**
+ * Reflected across x-axis, Rotated 90 CW
+ */
+ RightBottom = 7,
+ /**
+ * Rotated 90 CCW
+ */
+ LeftBottom = 8
+};
+
+/**
+ * Given an EncodedOrigin and the width and height of the source data, returns a matrix that
+ * transforms the source rectangle [0, 0, w, h] to a correctly oriented destination rectangle, with
+ * the upper left corner still at [0, 0].
+ */
+Matrix EncodedOriginToMatrix(EncodedOrigin origin, int width, int height);
+} // namespace tgfx
diff --git a/include/tgfx/core/Font.h b/include/tgfx/core/Font.h
new file mode 100644
index 00000000..7da41658
--- /dev/null
+++ b/include/tgfx/core/Font.h
@@ -0,0 +1,158 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Typeface.h"
+
+namespace tgfx {
+/**
+ * Font controls options applied when drawing and measuring text.
+ */
+class Font {
+ public:
+ /**
+ * Constructs Font with default values.
+ */
+ Font();
+
+ /**
+ * Constructs Font with default values with Typeface and size in points.
+ */
+ explicit Font(std::shared_ptr typeface, float size = 12.0f);
+
+ /**
+ * Returns a new font with the same attributes of this font, but with the specified size.
+ */
+ Font makeWithSize(float size) const;
+
+ /**
+ * Returns a typeface reference if set, or the default typeface reference, which is never nullptr.
+ */
+ std::shared_ptr getTypeface() const {
+ return typeface;
+ }
+
+ /**
+ * Sets a new Typeface to this Font.
+ */
+ void setTypeface(std::shared_ptr newTypeface);
+
+ /**
+ * Returns the point size of this font.
+ */
+ float getSize() const {
+ return size;
+ }
+
+ /**
+ * Sets text size in points. Has no effect if textSize is not greater than or equal to zero.
+ */
+ void setSize(float newSize);
+
+ /**
+ * Returns true if bold is approximated by increasing the stroke width when drawing glyphs.
+ */
+ bool isFauxBold() const {
+ return fauxBold;
+ }
+
+ /**
+ * Increases stroke width when drawing glyphs to approximate a bold typeface.
+ */
+ void setFauxBold(bool value) {
+ fauxBold = value;
+ }
+
+ /**
+ * Returns true if italic is approximated by adding skewX value of a canvas's matrix when
+ * drawing glyphs.
+ */
+ bool isFauxItalic() const {
+ return fauxItalic;
+ }
+
+ /**
+ * Adds skewX value of a canvas's matrix when drawing glyphs to approximate a italic typeface.
+ */
+ void setFauxItalic(bool value) {
+ fauxItalic = value;
+ }
+
+ /**
+ * Returns the FontMetrics associated with this font.
+ */
+ FontMetrics getMetrics() const {
+ return typeface->getMetrics(size);
+ }
+
+ /**
+ * Returns the glyph ID corresponds to the specified glyph name. The glyph name must be in utf-8
+ * encoding. Returns 0 if the glyph name is not associated with this typeface.
+ */
+ GlyphID getGlyphID(const std::string& name) const {
+ return typeface->getGlyphID(name);
+ }
+
+ /**
+ * Returns the bounding box of the specified glyph.
+ */
+ Rect getBounds(GlyphID glyphID) const {
+ return typeface->getBounds(glyphID, size, fauxBold, fauxItalic);
+ }
+
+ /**
+ * Returns the advance for specified glyph.
+ * @param glyphID The id of specified glyph.
+ * @param verticalText The intended drawing orientation of the glyph.
+ */
+ float getAdvance(GlyphID glyphID, bool verticalText = false) const {
+ return typeface->getAdvance(glyphID, size, fauxBold, fauxItalic, verticalText);
+ }
+
+ /**
+ * Creates a path corresponding to glyph outline. If glyph has an outline, copies outline to path
+ * and returns true. If glyph is described by a bitmap, returns false and ignores path parameter.
+ */
+ bool getPath(GlyphID glyphID, Path* path) const {
+ return typeface->getPath(glyphID, size, fauxBold, fauxItalic, path);
+ }
+
+ /**
+ * Creates an image buffer capturing the content of the specified glyph. The returned matrix
+ * should apply to the glyph image when drawing.
+ */
+ std::shared_ptr getGlyphImage(GlyphID glyphID, Matrix* matrix) const {
+ return typeface->getGlyphImage(glyphID, size, fauxBold, fauxItalic, matrix);
+ }
+
+ /**
+ * Calculates the offset from the default (horizontal) origin to the vertical origin for specified
+ * glyph.
+ */
+ Point getVerticalOffset(GlyphID glyphID) const {
+ return typeface->getVerticalOffset(glyphID, size, fauxBold, fauxItalic);
+ }
+
+ private:
+ std::shared_ptr typeface = nullptr;
+ float size = 12.0f;
+ bool fauxBold = false;
+ bool fauxItalic = false;
+};
+} // namespace tgfx
\ No newline at end of file
diff --git a/include/tgfx/core/FontMetrics.h b/include/tgfx/core/FontMetrics.h
new file mode 100644
index 00000000..6f39fc2d
--- /dev/null
+++ b/include/tgfx/core/FontMetrics.h
@@ -0,0 +1,82 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+class FontMetrics {
+ public:
+ /**
+ * Extent above baseline.
+ */
+ float top = 0;
+ /**
+ * Distance to reserve above baseline.
+ */
+ float ascent = 0;
+ /**
+ * Distance to reserve below baseline.
+ */
+ float descent = 0;
+ /**
+ * Extent below baseline.
+ */
+ float bottom = 0;
+ /**
+ * Distance to add between lines.
+ */
+ float leading = 0;
+ /**
+ * Minimum x.
+ */
+ float xMin = 0;
+ /**
+ * Maximum x.
+ */
+ float xMax = 0;
+ /**
+ * Height of lower-case 'x'.
+ */
+ float xHeight = 0;
+ /**
+ * Height of an upper-case letter.
+ */
+ float capHeight = 0;
+ /**
+ * Underline thickness.
+ */
+ float underlineThickness = 0;
+ /**
+ * Underline position relative to baseline.
+ */
+ float underlinePosition = 0;
+};
+
+struct GlyphMetrics {
+ float width = 0;
+ float height = 0;
+
+ // The offset from the glyphs' origin on the baseline to the top left of the glyph mask.
+ float top = 0;
+ float left = 0;
+
+ // The advance for this glyph.
+ float advanceX = 0;
+ float advanceY = 0;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Image.h b/include/tgfx/core/Image.h
new file mode 100644
index 00000000..be5454aa
--- /dev/null
+++ b/include/tgfx/core/Image.h
@@ -0,0 +1,276 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Data.h"
+#include "tgfx/core/EncodedOrigin.h"
+#include "tgfx/core/ImageGenerator.h"
+#include "tgfx/core/ImageInfo.h"
+#include "tgfx/core/Pixmap.h"
+#include "tgfx/core/SamplingOptions.h"
+#include "tgfx/core/TileMode.h"
+#include "tgfx/gpu/Backend.h"
+#include "tgfx/gpu/ImageOrigin.h"
+#include "tgfx/platform/HardwareBuffer.h"
+#include "tgfx/platform/NativeImage.h"
+
+namespace tgfx {
+class ImageSource;
+class Context;
+class TextureProxy;
+class FragmentProcessor;
+
+/**
+ * Image describes a two-dimensional array of pixels to draw. The pixels may be decoded in an
+ * ImageBuffer, encoded in a Picture or compressed data stream, or located in GPU memory as a GPU
+ * texture. The Image class is safe across threads and cannot be modified after it is created. The
+ * width and height of an Image are always greater than zero. Creating an Image with zero width or
+ * height returns nullptr. The corresponding GPU cache is immediately marked as expired if all
+ * Images with the same ImageSource are released, which becomes recyclable and will be purged at
+ * some point in the future.
+ */
+class Image {
+ public:
+ /**
+ * Creates an Image from the file path. An Image is returned if the format of the image file is
+ * recognized and supported. Recognized formats vary by platform.
+ */
+ static std::shared_ptr MakeFromFile(const std::string& filePath);
+
+ /**
+ * Creates an Image from the encoded data. An Image is returned if the format of the encoded data
+ * is recognized and supported. Recognized formats vary by platform.
+ */
+ static std::shared_ptr MakeFromEncoded(std::shared_ptr encodedData);
+
+ /**
+ * Creates an Image from the platform-specific NativeImage. For example, the NativeImage could be
+ * a jobject that represents a java Bitmap on the android platform or a CGImageRef on the apple
+ * platform. The returned Image object takes a reference to the nativeImage. Returns nullptr if
+ * the nativeImage is nullptr or the current platform has no NativeImage support.
+ */
+ static std::shared_ptr MakeFrom(NativeImageRef nativeImage);
+
+ /**
+ * Creates an Image from the image generator. An Image is returned if the generator is not
+ * nullptr. The image generator may wrap codec data or custom data.
+ */
+ static std::shared_ptr MakeFrom(std::shared_ptr generator);
+
+ /**
+ * Creates an Image from the ImageInfo and shares pixels from the immutable Data object. The
+ * returned Image takes a reference to the pixels. The caller must ensure the pixels are always
+ * the same for the lifetime of the returned Image. If the ImageInfo is unsuitable for direct
+ * texture uploading, the Image will internally create an ImageGenerator for pixel format
+ * conventing instead of an ImageBuffer. Returns nullptr if the ImageInfo is empty or the pixels
+ * are nullptr.
+ */
+ static std::shared_ptr MakeFrom(const ImageInfo& info, std::shared_ptr pixels);
+
+ /**
+ * Creates an Image from the Bitmap, sharing bitmap pixels. The Bitmap will allocate new internal
+ * pixel memory and copy the original pixels into it if there is a subsequent call of pixel
+ * writing to the Bitmap. Therefore, the content of the returned Image will always be the same.
+ */
+ static std::shared_ptr MakeFrom(const Bitmap& bitmap);
+
+ /**
+ * Creates an Image from the platform-specific hardware buffer. For example, the hardware buffer
+ * could be an AHardwareBuffer on the android platform or a CVPixelBufferRef on the apple
+ * platform. The returned Image takes a reference to the hardwareBuffer. The caller must
+ * ensure the buffer content stays unchanged for the lifetime of the returned Image. The
+ * colorSpace is ignored if the hardwareBuffer contains only one plane, which is not in the YUV
+ * format. Returns nullptr if the hardwareBuffer is nullptr.
+ */
+ static std::shared_ptr MakeFrom(HardwareBufferRef hardwareBuffer,
+ YUVColorSpace colorSpace = YUVColorSpace::BT601_LIMITED);
+
+ /**
+ * Creates an Image in the I420 format with the specified YUVData and the YUVColorSpace. Returns
+ * nullptr if the yuvData is invalid.
+ */
+ static std::shared_ptr MakeI420(std::shared_ptr yuvData,
+ YUVColorSpace colorSpace = YUVColorSpace::BT601_LIMITED);
+
+ /**
+ * Creates an Image in the NV12 format with the specified YUVData and the YUVColorSpace. Returns
+ * nullptr if the yuvData is invalid.
+ */
+ static std::shared_ptr MakeNV12(std::shared_ptr yuvData,
+ YUVColorSpace colorSpace = YUVColorSpace::BT601_LIMITED);
+
+ /**
+ * Creates an Image from the ImageBuffer, An Image is returned if the imageBuffer is not nullptr
+ * and its dimensions are greater than zero.
+ */
+ static std::shared_ptr MakeFrom(std::shared_ptr imageBuffer);
+
+ /**
+ * Creates an Image from the backendTexture associated with the context. The caller must ensure
+ * the backendTexture stays valid and unchanged for the lifetime of the returned Image. An Image
+ * is returned if the format of the backendTexture is recognized and supported. Recognized formats
+ * vary by GPU back-ends.
+ */
+ static std::shared_ptr MakeFrom(Context* context, const BackendTexture& backendTexture,
+ ImageOrigin origin = ImageOrigin::TopLeft);
+
+ /**
+ * Creates an Image from the backendTexture associated with the context, taking ownership of the
+ * backendTexture. The backendTexture will be released when no longer needed. The caller must
+ * ensure the backendTexture stays unchanged for the lifetime of the returned Image. An Image is
+ * returned if the format of the backendTexture is recognized and supported. Recognized formats
+ * vary by GPU back-ends.
+ */
+ static std::shared_ptr MakeAdopted(Context* context, const BackendTexture& backendTexture,
+ ImageOrigin origin = ImageOrigin::TopLeft);
+
+ virtual ~Image() = default;
+
+ /**
+ * Returns the width of the Image.
+ */
+ virtual int width() const;
+
+ /**
+ * Returns pixel row count.
+ */
+ virtual int height() const;
+
+ /**
+ * Returns true if pixels represent transparency only. If true, each pixel is packed in 8 bits as
+ * defined by ColorType::ALPHA_8.
+ */
+ bool isAlphaOnly() const;
+
+ /**
+ * Returns true if the Image is an RGBAAA image, which takes half of the original image as its RGB
+ * channels and the other half as its alpha channel.
+ */
+ virtual bool isRGBAAA() const;
+
+ /**
+ * Returns true if Image is backed by an image generator or other services that create their
+ * pixels on-demand.
+ */
+ bool isLazyGenerated() const;
+
+ /**
+ * Returns true if the Image was created from a GPU texture.
+ */
+ bool isTextureBacked() const;
+
+ /**
+ * Returns true if the Image has mipmap levels. The flag was set by the makeMipMapped() method,
+ * which may be ignored if the GPU or the associated image source does not support mipmaps.
+ */
+ bool hasMipmaps() const;
+
+ /**
+ * Retrieves the backend texture of the Image. Returns an invalid BackendTexture if the Image is
+ * not backed by a Texture.
+ */
+ BackendTexture getBackendTexture() const;
+
+ /**
+ * Returns an Image backed by GPU texture associated with the specified context. If there is a
+ * corresponding texture cache in the context, returns an Image wraps that texture. Otherwise,
+ * creates one immediately, which may block the calling thread. Returns the original Image if the
+ * Image is texture backed and the context is compatible with the backing GPU texture. Otherwise,
+ * returns nullptr. The associated CPU memory can be freed entirely by setting the original Image
+ * to nullptr, since the returned Image contains only a GPU texture.
+ */
+ std::shared_ptr makeTextureImage(Context* context) const;
+
+ /**
+ * Returns subset of Image. The subset must be fully contained by Image dimensions. The returned
+ * Image always shares pixels and caches with the original Image. Returns nullptr if the subset is
+ * empty, or the subset is not contained by bounds.
+ */
+ std::shared_ptr makeSubset(const Rect& subset) const;
+
+ /**
+ * Returns a decoded Image from the lazy Image. The returned Image shares the same texture cache
+ * with the original Image and immediately schedules an asynchronous decoding task, which will not
+ * block the calling thread. Returns the original Image if the Image is not lazy or has a
+ * corresponding texture cache in the specified context.
+ */
+ std::shared_ptr makeDecoded(Context* context = nullptr) const;
+
+ /**
+ * Returns an Image with mipmaps enabled. Returns the original Image if the Image has mipmaps
+ * enabled already or fails to enable mipmaps.
+ */
+ std::shared_ptr makeMipMapped() const;
+
+ /**
+ * Returns an Image with the RGBAAA layout that takes half of the original Image as its RGB
+ * channels and the other half as its alpha channel. Returns a subset Image if both alphaStartX
+ * and alphaStartY are zero. Returns nullptr if the original Image has an encoded origin, subset
+ * bounds, or an RGBAAA layout.
+ * @param displayWidth The display width of the RGBAAA image.
+ * @param displayHeight The display height of the RGBAAA image.
+ * @param alphaStartX The x position of where alpha area begins in the original image.
+ * @param alphaStartY The y position of where alpha area begins in the original image.
+ */
+ std::shared_ptr makeRGBAAA(int displayWidth, int displayHeight, int alphaStartX,
+ int alphaStartY);
+
+ /**
+ * Returns an Image with its origin transformed by the given EncodedOrigin. The returned Image
+ * always shares pixels and caches with the original Image.
+ */
+ std::shared_ptr applyOrigin(EncodedOrigin origin) const;
+
+ protected:
+ std::weak_ptr weakThis;
+ std::shared_ptr source = nullptr;
+
+ explicit Image(std::shared_ptr source);
+
+ virtual std::shared_ptr onCloneWith(std::shared_ptr newSource) const;
+
+ virtual std::shared_ptr onMakeSubset(const Rect& subset) const;
+
+ virtual std::shared_ptr onMakeRGBAAA(int displayWidth, int displayHeight, int alphaStartX,
+ int alphaStartY) const;
+
+ virtual std::shared_ptr onApplyOrigin(EncodedOrigin encodedOrigin) const;
+
+ virtual std::unique_ptr asFragmentProcessor(
+ Context* context, uint32_t surfaceFlags, TileMode tileModeX, TileMode tileModeY,
+ const SamplingOptions& sampling, const Matrix* localMatrix = nullptr);
+
+ private:
+ std::unique_ptr asFragmentProcessor(Context* context, uint32_t surfaceFlags,
+ const SamplingOptions& sampling);
+
+ static std::shared_ptr MakeFrom(std::shared_ptr texture);
+
+ static std::shared_ptr MakeFrom(std::shared_ptr source,
+ EncodedOrigin origin = EncodedOrigin::TopLeft);
+
+ std::shared_ptr cloneWithSource(std::shared_ptr newSource) const;
+
+ friend class ImageShader;
+ friend class BlurImageFilter;
+ friend class Canvas;
+ friend class Surface;
+ friend class Mask;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ImageBuffer.h b/include/tgfx/core/ImageBuffer.h
new file mode 100644
index 00000000..72ab1f7e
--- /dev/null
+++ b/include/tgfx/core/ImageBuffer.h
@@ -0,0 +1,117 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Data.h"
+#include "tgfx/core/ImageInfo.h"
+#include "tgfx/core/YUVColorSpace.h"
+#include "tgfx/core/YUVData.h"
+#include "tgfx/platform/HardwareBuffer.h"
+#include "tgfx/platform/NativeImage.h"
+
+namespace tgfx {
+class Context;
+class Texture;
+
+/**
+ * ImageBuffer describes a two-dimensional array of pixels and is optimized for creating textures.
+ * ImageBuffer is immutable and safe across threads. The content of an ImageBuffer never changes,
+ * but some ImageBuffers may have a limited lifetime and cannot create textures after they expire.
+ * For example, the ImageBuffers generated from an ImageReader. In other cases, ImageBuffers usually
+ * only expire if explicitly stated by the creator.
+ */
+class ImageBuffer {
+ public:
+ /**
+ * Creates an ImageBuffer from the platform-specific hardware buffer. For example, the hardware
+ * buffer could be an AHardwareBuffer on the android platform or a CVPixelBufferRef on the apple
+ * platform. The returned ImageBuffer takes a reference to the hardwareBuffer. The caller must
+ * ensure the buffer content stays unchanged for the lifetime of the returned ImageBuffer. The
+ * colorSpace is ignored if the hardwareBuffer contains only one plane, which is not in the YUV
+ * format. Returns nullptr if the hardwareBuffer is nullptr.
+ */
+ static std::shared_ptr MakeFrom(
+ HardwareBufferRef hardwareBuffer, YUVColorSpace colorSpace = YUVColorSpace::BT601_LIMITED);
+
+ /**
+ * Creates an ImageBuffer from the ImageInfo and shares pixels from the immutable Data object. The
+ * pixel data may be copied and converted to a new format which is more efficient for texture
+ * uploading. However, if the ImageInfo is suitable for direct texture uploading, the pixel data
+ * will be shared instead of copied. In that case, the caller must ensure the pixel data stay
+ * unchanged for the lifetime of the returned ImageBuffer. Returns nullptr if the info is empty or
+ * the pixels are nullptr.
+ * ImageInfo parameters suitable for direct texture uploading include:
+ * The alpha type is not AlphaType::Unpremultiplied;
+ * The color type is one of ColorType::ALPHA_8, ColorType::RGBA_8888, and ColorType::BGRA_8888.
+ */
+ static std::shared_ptr MakeFrom(const ImageInfo& info, std::shared_ptr pixels);
+
+ /**
+ * Creates an ImageBuffer in the I420 format with the specified YUVData and YUVColorSpace. The
+ * caller must ensure the yuvData stays unchanged for the lifetime of the returned ImageBuffer.
+ * Returns nullptr if the yuvData is invalid.
+ */
+ static std::shared_ptr MakeI420(
+ std::shared_ptr yuvData, YUVColorSpace colorSpace = YUVColorSpace::BT601_LIMITED);
+
+ /**
+ * Creates an ImageBuffer in the NV12 format with the specified YUVData and YUVColorSpace. The
+ * caller must ensure the yuvData stays unchanged for the lifetime of the returned ImageBuffer.
+ * Returns nullptr if the yuvData is invalid.
+ */
+ static std::shared_ptr MakeNV12(
+ std::shared_ptr yuvData, YUVColorSpace colorSpace = YUVColorSpace::BT601_LIMITED);
+
+ virtual ~ImageBuffer() = default;
+ /**
+ * Returns the width of the image buffer.
+ */
+ virtual int width() const = 0;
+
+ /**
+ * Returns the height of the image buffer.
+ */
+ virtual int height() const = 0;
+
+ /**
+ * Returns true if pixels represent transparency only. If true, each pixel is packed in 8 bits as
+ * defined by ColorType::ALPHA_8.
+ */
+ virtual bool isAlphaOnly() const = 0;
+
+ /**
+ * Returns true if the ImageBuffer is expired, which means it cannot create any new textures.
+ * However, you can still safely access all of its properties across threads.
+ */
+ virtual bool expired() const {
+ return false;
+ }
+
+ protected:
+ ImageBuffer() = default;
+
+ /**
+ * Creates a new Texture capturing the pixels of the ImageBuffer. The mipMapped parameter
+ * specifies whether created texture must allocate mip map levels.
+ */
+ virtual std::shared_ptr onMakeTexture(Context* context, bool mipMapped) const = 0;
+
+ friend class Texture;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ImageCodec.h b/include/tgfx/core/ImageCodec.h
new file mode 100644
index 00000000..4a91b706
--- /dev/null
+++ b/include/tgfx/core/ImageCodec.h
@@ -0,0 +1,107 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Data.h"
+#include "tgfx/core/EncodedFormat.h"
+#include "tgfx/core/EncodedOrigin.h"
+#include "tgfx/core/ImageGenerator.h"
+#include "tgfx/core/ImageInfo.h"
+#include "tgfx/core/Pixmap.h"
+#include "tgfx/platform/NativeImage.h"
+
+namespace tgfx {
+
+class ImageBuffer;
+
+/**
+ * Abstraction layer directly on top of an image codec.
+ */
+class ImageCodec : public ImageGenerator {
+ public:
+ /**
+ * If this file path represents an encoded image that we know how to decode, return an ImageCodec
+ * that can decode it. Otherwise, return nullptr.
+ */
+ static std::shared_ptr MakeFrom(const std::string& filePath);
+
+ /**
+ * If the file bytes represent an encoded image that we know how to decode, return an ImageCodec
+ * that can decode it. Otherwise, return nullptr.
+ */
+ static std::shared_ptr MakeFrom(std::shared_ptr imageBytes);
+
+ /**
+ * Creates a new ImageCodec object from a platform-specific NativeImage. For example, the
+ * NativeImage could be a jobject that represents a java Bitmap on the android platform or a
+ * CGImageRef on the apple platform.The returned ImageCodec object takes a reference on the
+ * nativeImage. Returns nullptr if the nativeImage is nullptr or the current platform has no
+ * NativeImage support.
+ */
+ static std::shared_ptr MakeFrom(NativeImageRef nativeImage);
+
+ /**
+ * Encodes the specified Pixmap into a binary image format. Returns nullptr if encoding fails.
+ */
+ static std::shared_ptr Encode(const Pixmap& pixmap, EncodedFormat format, int quality);
+
+ /**
+ * Returns the encoded origin of the target image.
+ */
+ EncodedOrigin origin() const {
+ return _origin;
+ }
+
+ bool isAlphaOnly() const override {
+ return false;
+ }
+
+ /**
+ * Decodes the image with the specified image info into the given pixels. Returns true if the
+ * decoding was successful. Note that we do not recommend calling this method due to performance
+ * reasons, especially on the web platform. Use the makeBuffer() method for better performance if
+ * your final goal is to draw the image.
+ */
+ virtual bool readPixels(const ImageInfo& dstInfo, void* dstPixels) const = 0;
+
+ protected:
+ ImageCodec(int width, int height, EncodedOrigin origin)
+ : ImageGenerator(width, height), _origin(origin) {
+ }
+
+ std::shared_ptr onMakeBuffer(bool tryHardware) const override;
+
+ private:
+ EncodedOrigin _origin = EncodedOrigin::TopLeft;
+
+ /**
+ * If the file path represents an encoded image that the current platform knows how to decode,
+ * returns an ImageCodec that can decode it. Otherwise, returns nullptr.
+ */
+ static std::shared_ptr MakeNativeCodec(const std::string& filePath);
+
+ /**
+ * If the file bytes represent an encoded image that the current platform knows how to decode,
+ * returns an ImageCodec that can decode it. Otherwise, returns nullptr.
+ */
+ static std::shared_ptr MakeNativeCodec(std::shared_ptr imageBytes);
+
+ friend class Pixmap;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ImageFilter.h b/include/tgfx/core/ImageFilter.h
new file mode 100644
index 00000000..f43bbff3
--- /dev/null
+++ b/include/tgfx/core/ImageFilter.h
@@ -0,0 +1,70 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/Image.h"
+#include "tgfx/core/Matrix.h"
+#include "tgfx/core/TileMode.h"
+#include "tgfx/gpu/Context.h"
+
+namespace tgfx {
+struct ImageFilterContext {
+ ImageFilterContext(Context* context, Matrix matrix, Rect clipBounds, std::shared_ptr image)
+ : context(context), deviceMatrix(matrix), clipBounds(clipBounds), source(std::move(image)) {
+ }
+
+ Context* context = nullptr;
+ Matrix deviceMatrix = Matrix::I();
+ Rect clipBounds = Rect::MakeEmpty();
+ std::shared_ptr source;
+};
+
+class ImageFilter {
+ public:
+ static std::shared_ptr Blur(float blurrinessX, float blurrinessY,
+ TileMode tileMode = TileMode::Decal,
+ const Rect& cropRect = Rect::MakeEmpty());
+
+ static std::shared_ptr DropShadow(float dx, float dy, float blurrinessX,
+ float blurrinessY, const Color& color,
+ const Rect& cropRect = Rect::MakeEmpty());
+
+ static std::shared_ptr DropShadowOnly(float dx, float dy, float blurrinessX,
+ float blurrinessY, const Color& color,
+ const Rect& cropRect = Rect::MakeEmpty());
+
+ virtual ~ImageFilter() = default;
+
+ virtual std::pair, Point> filterImage(
+ const ImageFilterContext& context) = 0;
+
+ Rect filterBounds(const Rect& rect) const;
+
+ protected:
+ explicit ImageFilter(const Rect cropRect) : cropRect(cropRect) {
+ }
+
+ bool applyCropRect(const Rect& srcRect, Rect* dstRect, const Rect* clipRect = nullptr) const;
+
+ virtual Rect onFilterNodeBounds(const Rect& srcRect) const;
+
+ Rect cropRect;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ImageGenerator.h b/include/tgfx/core/ImageGenerator.h
new file mode 100644
index 00000000..3af61712
--- /dev/null
+++ b/include/tgfx/core/ImageGenerator.h
@@ -0,0 +1,80 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/ImageBuffer.h"
+
+namespace tgfx {
+/**
+ * ImageGenerator defines the interfaces for generating ImageBuffer objects from encoded images or
+ * custom data.
+ */
+class ImageGenerator {
+ public:
+ virtual ~ImageGenerator() = default;
+
+ /**
+ * Returns the width of the target image.
+ */
+ int width() const {
+ return _width;
+ }
+
+ /**
+ * Returns the height of the target image.
+ */
+ int height() const {
+ return _height;
+ }
+
+ /**
+ * Returns true if the generator is guaranteed to produce transparency only pixels. If true, each
+ * pixel is packed in 8 bits as defined by ColorType::ALPHA_8.
+ */
+ virtual bool isAlphaOnly() const = 0;
+
+ /**
+ * Returns true if the ImageGenerator has built-in support for asynchronous decoding. If true, the
+ * makeBuffer() method will not block the calling thread.
+ */
+ virtual bool asyncSupport() const {
+ return false;
+ }
+
+ /**
+ * Crates a new image buffer capturing the pixels decoded from this image generator.
+ * ImageGenerator does not cache the returned image buffer, each call to this method allocates
+ * additional storage. Returns an ImageBuffer backed by hardware if tryHardware is true and
+ * the current platform supports creating it. Otherwise, a raster ImageBuffer is returned.
+ */
+ std::shared_ptr makeBuffer(bool tryHardware = true) const {
+ return onMakeBuffer(tryHardware);
+ }
+
+ protected:
+ ImageGenerator(int width, int height) : _width(width), _height(height) {
+ }
+
+ virtual std::shared_ptr onMakeBuffer(bool tryHardware) const = 0;
+
+ private:
+ int _width = 0;
+ int _height = 0;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/ImageInfo.h b/include/tgfx/core/ImageInfo.h
new file mode 100644
index 00000000..3b00400a
--- /dev/null
+++ b/include/tgfx/core/ImageInfo.h
@@ -0,0 +1,195 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "tgfx/core/AlphaType.h"
+#include "tgfx/core/ColorType.h"
+
+namespace tgfx {
+/**
+ * ImageInfo describes the properties for an area of pixels.
+ */
+class ImageInfo {
+ public:
+ /**
+ * Returns true if the specified width and height is a valid size for pixels.
+ */
+ static bool IsValidSize(int width, int height);
+
+ /**
+ * Creates a new ImageInfo. Parameters are validated to see if their values are legal, or that the
+ * combination is supported. Returns an empty ImageInfo if validating fails.
+ */
+ static ImageInfo Make(int width, int height, ColorType colorType,
+ AlphaType alphaType = AlphaType::Premultiplied, size_t rowBytes = 0);
+
+ static int GetBytesPerPixel(ColorType colorType);
+
+ /**
+ * Creates an empty ImageInfo.
+ */
+ ImageInfo() = default;
+
+ /**
+ * Returns true if ImageInfo describes an empty area of pixels.
+ */
+ bool isEmpty() const {
+ return _width <= 0;
+ }
+
+ /**
+ * Returns true if pixels represent transparency only. If true, each pixel is packed in 8 bits as
+ * defined by ColorType::ALPHA_8.
+ */
+ bool isAlphaOnly() const {
+ return _colorType == ColorType::ALPHA_8;
+ }
+
+ /**
+ * Returns the width of the pixels.
+ */
+ int width() const {
+ return _width;
+ }
+
+ /**
+ * Returns the height of the pixels.
+ */
+ int height() const {
+ return _height;
+ }
+
+ /**
+ * Returns the ColorType of the pixels.
+ */
+ ColorType colorType() const {
+ return _colorType;
+ }
+
+ /**
+ * Returns the AlphaType of the pixels.
+ */
+ AlphaType alphaType() const {
+ return _alphaType;
+ }
+
+ /**
+ * Returns the rowBytes of the pixels.
+ */
+ size_t rowBytes() const {
+ return _rowBytes;
+ }
+
+ /**
+ * Returns minimum bytes per row, computed from the width and colorType.
+ */
+ size_t minRowBytes() const {
+ return _width * bytesPerPixel();
+ }
+
+ /**
+ * Returns the byte size of the pixels, computed from the rowBytes and width.
+ */
+ size_t byteSize() const {
+ return _rowBytes * _height;
+ }
+
+ /**
+ * Returns number of bytes per pixel required by the colorType.
+ */
+ int bytesPerPixel() const;
+
+ /**
+ * Creates a new ImageInfo with dimensions set to width and height, and keep other properties the
+ * same.
+ */
+ ImageInfo makeWH(int newWidth, int newHeight) const {
+ return Make(newWidth, newHeight, _colorType, _alphaType, _rowBytes);
+ }
+
+ /**
+ * If (0, 0, width(), height()) intersects (x, y, targetWidth, targetHeight), returns a new
+ * ImageInfo with dimensions set to the size of intersection, and keep other properties the same.
+ * Otherwise, returns an empty ImageInfo.
+ */
+ ImageInfo makeIntersect(int x, int y, int targetWidth, int targetHeight) const;
+
+ /**
+ * Creates a new ImageInfo with alphaType set to newAlphaType, and keep other properties the same.
+ */
+ ImageInfo makeAlphaType(AlphaType newAlphaType) const {
+ return Make(_width, _height, _colorType, newAlphaType, _rowBytes);
+ }
+
+ /**
+ * Creates ImageInfo with colorType set to newColorType, rowBytes set to newRowBytes, and keep
+ * other properties the same.
+ */
+ ImageInfo makeColorType(ColorType newColorType, size_t newRowBytes = 0) const {
+ return Make(_width, _height, newColorType, _alphaType, newRowBytes);
+ }
+
+ /**
+ * Returns readable pixel address at (x, y) of specified base pixel address.
+ * Note: The x value will be clamped to the range of (0, width), and the y value will be clamped
+ * to the range of (0, height).
+ */
+ const void* computeOffset(const void* pixels, int x, int y) const;
+
+ /**
+ * Returns writable pixel address at (x, y) of specified base pixel address.
+ * Note: The x value will be clamped to the range of [0, width-1], and the y value will be clamped
+ * to the range of [0, height-1].
+ */
+ void* computeOffset(void* pixels, int x, int y) const;
+
+ /**
+ * Returns true if a is equivalent to b.
+ */
+ friend bool operator==(const ImageInfo& a, const ImageInfo& b) {
+ return memcmp(&a, &b, sizeof(ImageInfo)) == 0;
+ }
+
+ /**
+ * Returns true if a is not equivalent to b.
+ */
+ friend bool operator!=(const ImageInfo& a, const ImageInfo& b) {
+ return !(a == b);
+ }
+
+ private:
+ ImageInfo(int width, int height, ColorType colorType, AlphaType alphaType, size_t rowBytes)
+ : _width(width),
+ _height(height),
+ _colorType(colorType),
+ _alphaType(alphaType),
+ _rowBytes(rowBytes) {
+ }
+
+ int _width = 0;
+ int _height = 0;
+ ColorType _colorType = ColorType::Unknown;
+ AlphaType _alphaType = AlphaType::Unknown;
+ size_t _rowBytes = 0;
+};
+} // namespace tgfx
\ No newline at end of file
diff --git a/include/tgfx/core/ImageReader.h b/include/tgfx/core/ImageReader.h
new file mode 100644
index 00000000..7134d91c
--- /dev/null
+++ b/include/tgfx/core/ImageReader.h
@@ -0,0 +1,109 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+#include "tgfx/core/Bitmap.h"
+#include "tgfx/core/ImageBuffer.h"
+#include "tgfx/core/Mask.h"
+#include "tgfx/core/Rect.h"
+
+namespace tgfx {
+class Texture;
+class ImageStream;
+
+/**
+ * The ImageReader class allows direct access to ImageBuffers generated from an image stream. The
+ * image stream may come from a Bitmap, a Mask, or a video-related object of the native
+ * platform. You should call ImageReader::acquireNextBuffer() to read a new ImageBuffer each time
+ * when the image stream is modified. All ImageBuffers generated from one ImageReader share the same
+ * internal texture, which allows you to continuously read the latest content from the image stream
+ * with minimal memory copying. However, there are two limits:
+ *
+ * 1) The generated ImageBuffers are bound to the associated GPU Context when first being drawn
+ * and cannot be drawn to another Context anymore.
+ * 2) The generated ImageBuffers may have a limited lifetime and cannot create textures after
+ * expiration. Usually, the previously acquired ImageBuffer will expire after the newly
+ * created ImageBuffer is drawn. So there are only two ImageBuffers that can be accessed
+ * simultaneously. But if the image stream is backed by a hardware buffer, the previously
+ * acquired ImageBuffer immediately expires when the image stream is being modified.
+ *
+ * You can create multiple ImageReaders from the same image stream. ImageReader is safe across
+ * threads.
+ */
+class ImageReader {
+ public:
+ /**
+ * Creates a new ImageReader from the specified Bitmap. Returns nullptr if the bitmap is empty.
+ */
+ static std::shared_ptr MakeFrom(const Bitmap& bitmap);
+
+ /**
+ * Creates a new ImageReader from the specified Mask. Returns nullptr if the mask is nullptr.
+ */
+ static std::shared_ptr MakeFrom(std::shared_ptr mask);
+
+ virtual ~ImageReader();
+
+ /**
+ * Returns the width of generated image buffers.
+ */
+ int width() const;
+
+ /**
+ * Returns the height of generated image buffers.
+ */
+ int height() const;
+
+ /**
+ * Acquires the next ImageBuffer from the ImageReader after a new image frame has been rendered
+ * into the associated image stream. Usually, the previously acquired ImageBuffer will expire
+ * after the newly created ImageBuffer is drawn. But if the image stream is backed by a hardware
+ * buffer, the previously acquired ImageBuffer immediately expires when the image stream is being
+ * modified. Returns nullptr if the associated image stream has no content changes.
+ */
+ virtual std::shared_ptr acquireNextBuffer();
+
+ protected:
+ std::mutex locker = {};
+ std::weak_ptr weakThis;
+ std::shared_ptr stream = nullptr;
+
+ explicit ImageReader(std::shared_ptr stream);
+
+ private:
+ std::shared_ptr texture = nullptr;
+ uint64_t bufferVersion = 0;
+ uint64_t textureVersion = 0;
+ bool hasPendingChanges = true;
+ Rect dirtyBounds = Rect::MakeEmpty();
+
+ static std::shared_ptr MakeFrom(std::shared_ptr imageStream);
+
+ bool checkExpired(uint64_t contentVersion);
+
+ std::shared_ptr readTexture(uint64_t contentVersion, Context* context, bool mipMapped);
+
+ void onContentDirty(const Rect& bounds);
+
+ friend class ImageReaderBuffer;
+ friend class ImageStream;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Mask.h b/include/tgfx/core/Mask.h
new file mode 100644
index 00000000..3010efc1
--- /dev/null
+++ b/include/tgfx/core/Mask.h
@@ -0,0 +1,129 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Image.h"
+#include "tgfx/core/ImageBuffer.h"
+#include "tgfx/core/Path.h"
+#include "tgfx/core/Stroke.h"
+#include "tgfx/core/TextBlob.h"
+
+namespace tgfx {
+class ImageStream;
+
+/**
+ * Mask is a utility that can take an image described in a vector graphics format (paths, glyphs)
+ * and convert it into a raster image that can be used as a drawing mask. Mask is not thread safe,
+ * do not use it across multiple threads.
+ */
+class Mask {
+ public:
+ /**
+ * Creates a new Mask and tries to allocate its pixel memory by the specified width and height.
+ * If tryHardware is true and there is hardware buffer support on the current platform,
+ * a hardware-backed pixel buffer is allocated. Otherwise, a raster pixel buffer is allocated.
+ * Returns nullptr if allocation fails.
+ */
+ static std::shared_ptr Make(int width, int height, bool tryHardware = true);
+
+ virtual ~Mask() = default;
+
+ /**
+ * Returns the width of the Mask.
+ */
+ virtual int width() const = 0;
+
+ /**
+ * Returns the height of the Mask.
+ */
+ virtual int height() const = 0;
+
+ /**
+ * Returns true if the Mask is backed by a platform-specified hardware buffer.
+ */
+ virtual bool isHardwareBacked() const = 0;
+
+ /**
+ * Returns the current total matrix.
+ */
+ Matrix getMatrix() const {
+ return matrix;
+ }
+
+ /**
+ * Replaces transformation with the specified matrix.
+ */
+ void setMatrix(const Matrix& m) {
+ matrix = m;
+ }
+
+ /**
+ * Replaces the current Matrix with matrix premultiplied with the existing one. This has the
+ * effect of transforming the filling geometry by matrix, before transforming the result with
+ * the existing Matrix.
+ */
+ void concat(const Matrix& m) {
+ matrix.preConcat(m);
+ }
+
+ /**
+ * Writes the fills or outlines of the given Path to the Mask,with its top-left corner at (0, 0),
+ * using the current Matrix.
+ */
+ void fillPath(const Path& path, const Stroke* stroke = nullptr);
+
+ /**
+ * Writes the fills or outlines of the given TextBlob to the Mask,with its top-left corner at
+ * (0, 0), using the current Matrix. Returns false if the associated typeface has color glyphs and
+ * leaves the Mask unchanged.
+ */
+ bool fillText(const TextBlob* textBlob, const Stroke* stroke = nullptr);
+
+ /**
+ * Replaces all pixel values with transparent colors.
+ */
+ virtual void clear() = 0;
+
+ /**
+ * Returns an ImageBuffer object capturing the pixels in the Mask. Subsequent writing of the Mask
+ * will not be captured. Instead, the Mask will copy its pixels to a new memory buffer if there is
+ * a subsequent writing call to the Mask while the returned ImageBuffer is still alive. If the
+ * Mask is modified frequently, create an ImageReader from the Mask instead, which allows you to
+ * continuously read the latest content from the Mask with minimal memory copying. Returns nullptr
+ * if the Mask is empty.
+ */
+ virtual std::shared_ptr makeBuffer() const = 0;
+
+ protected:
+ virtual std::shared_ptr getImageStream() const = 0;
+
+ void onFillPath(const Path& path, const Matrix& m) {
+ onFillPath(path, m, false);
+ }
+
+ virtual void onFillPath(const Path& path, const Matrix& m, bool needsGammaCorrection) = 0;
+
+ virtual bool onFillText(const TextBlob* textBlob, const Stroke* stroke, const Matrix& matrix);
+
+ private:
+ Matrix matrix = Matrix::I();
+
+ friend class ImageReader;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/MaskFilter.h b/include/tgfx/core/MaskFilter.h
new file mode 100644
index 00000000..ccebb832
--- /dev/null
+++ b/include/tgfx/core/MaskFilter.h
@@ -0,0 +1,37 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "Shader.h"
+
+namespace tgfx {
+struct FPArgs;
+
+class FragmentProcessor;
+
+class MaskFilter {
+ public:
+ static std::shared_ptr Make(std::shared_ptr shader, bool inverted = false);
+
+ virtual ~MaskFilter() = default;
+
+ virtual std::unique_ptr asFragmentProcessor(const FPArgs& args) const = 0;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Matrix.h b/include/tgfx/core/Matrix.h
new file mode 100644
index 00000000..09ba5c2b
--- /dev/null
+++ b/include/tgfx/core/Matrix.h
@@ -0,0 +1,709 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/Rect.h"
+
+namespace tgfx {
+/***
+ * Matrix holds a 3x2 matrix for transforming coordinates. This allows mapping Point and vectors
+ * with translation, scaling, skewing, and rotation. Together these types of transformations are
+ * known as affine transformations. Affine transformations preserve the straightness of lines while
+ * transforming, so that parallel lines stay parallel. Matrix elements are in row major order.
+ * Matrix does not have a constructor, so it must be explicitly initialized.
+ */
+class Matrix {
+ public:
+ /**
+ * Sets Matrix to scale by (sx, sy). Returned matrix is:
+ *
+ * | sx 0 0 |
+ * | 0 sy 0 |
+ * | 0 0 1 |
+ *
+ * @param sx horizontal scale factor
+ * @param sy vertical scale factor
+ * @return Matrix with scale factors.
+ */
+ static Matrix MakeScale(float sx, float sy) {
+ Matrix m = {};
+ m.setScale(sx, sy);
+ return m;
+ }
+
+ /**
+ * Sets Matrix to scale by (scale, scale). Returned matrix is:
+ *
+ * | scale 0 0 |
+ * | 0 scale 0 |
+ * | 0 0 1 |
+ *
+ * @param scale horizontal and vertical scale factor
+ * @return Matrix with scale factors.
+ */
+ static Matrix MakeScale(float scale) {
+ Matrix m = {};
+ m.setScale(scale, scale);
+ return m;
+ }
+
+ /**
+ * Sets Matrix to translate by (tx, ty). Returned matrix is:
+ *
+ * | 1 0 tx |
+ * | 0 1 ty |
+ * | 0 0 1 |
+ *
+ * @param tx horizontal translation
+ * @param ty vertical translation
+ * @return Matrix with translation
+ */
+ static Matrix MakeTrans(float tx, float ty) {
+ Matrix m = {};
+ m.setTranslate(tx, ty);
+ return m;
+ }
+
+ /**
+ * Sets Matrix to:
+ *
+ * | scaleX skewX transX |
+ * | skewY scaleY transY |
+ * | 0 0 1 |
+ *
+ * @param scaleX horizontal scale factor
+ * @param skewX horizontal skew factor
+ * @param transX horizontal translation
+ * @param skewY vertical skew factor
+ * @param scaleY vertical scale factor
+ * @param transY vertical translation
+ * @return Matrix constructed from parameters
+ */
+ static Matrix MakeAll(float scaleX, float skewX, float transX, float skewY, float scaleY,
+ float transY) {
+ Matrix m = {};
+ m.setAll(scaleX, skewX, transX, skewY, scaleY, transY);
+ return m;
+ }
+
+ /**
+ * Returns true if Matrix is identity. The identity matrix is:
+ *
+ * | 1 0 0 |
+ * | 0 1 0 |
+ * | 0 0 1 |
+ *
+ * @return Returns true if the Matrix has no effect.
+ */
+ bool isIdentity() const {
+ return values[0] == 1 && values[1] == 0 && values[2] == 0 && values[3] == 0 && values[4] == 1 &&
+ values[5] == 0;
+ }
+
+ /**
+ * Returns one matrix value.
+ */
+ float operator[](int index) const {
+ return values[index];
+ }
+
+ /**
+ * Returns writable Matrix value.
+ */
+ float& operator[](int index) {
+ return values[index];
+ }
+
+ /**
+ * Returns one matrix value.
+ */
+ float get(int index) const {
+ return values[index];
+ }
+
+ /**
+ * Sets Matrix value.
+ */
+ void set(int index, float value) {
+ values[index] = value;
+ }
+
+ /**
+ * Copies six scalar values contained by Matrix into buffer, in member value ascending order:
+ * ScaleX, SkewX, TransX, SkewY, ScaleY, TransY.
+ * @param buffer storage for six scalar values.
+ */
+ void get6(float buffer[6]) const {
+ memcpy(buffer, values, 6 * sizeof(float));
+ }
+
+ /**
+ * Sets Matrix to six scalar values in buffer, in member value ascending order:
+ * ScaleX, SkewX, TransX, SkewY, ScaleY, TransY.
+ * Sets matrix to:
+ *
+ * | buffer[0] buffer[1] buffer[2] |
+ * | buffer[3] buffer[4] buffer[5] |
+ *
+ * @param buffer storage for six scalar values.
+ */
+ void set6(const float buffer[6]) {
+ memcpy(values, buffer, 6 * sizeof(float));
+ }
+
+ /**
+ * Copies nine scalar values contained by Matrix into buffer, in member value ascending order:
+ * ScaleX, SkewX, TransX, SkewY, ScaleY, TransY, 0, 0, 1.
+ * @param buffer storage for nine scalar values
+ */
+ void get9(float buffer[9]) const;
+
+ /**
+ * Returns the horizontal scale factor.
+ */
+ float getScaleX() const {
+ return values[SCALE_X];
+ }
+
+ /**
+ * Returns the vertical scale factor.
+ */
+ float getScaleY() const {
+ return values[SCALE_Y];
+ }
+
+ /**
+ * Returns the vertical skew factor.
+ */
+ float getSkewY() const {
+ return values[SKEW_Y];
+ }
+
+ /**
+ * Returns the horizontal scale factor.
+ */
+ float getSkewX() const {
+ return values[SKEW_X];
+ }
+
+ /**
+ * Returns the horizontal translation factor.
+ */
+ float getTranslateX() const {
+ return values[TRANS_X];
+ }
+
+ /**
+ * Returns the vertical translation factor.
+ */
+ float getTranslateY() const {
+ return values[TRANS_Y];
+ }
+
+ /**
+ * Sets the horizontal scale factor.
+ */
+ void setScaleX(float v) {
+ values[SCALE_X] = v;
+ }
+
+ /**
+ * Sets the vertical scale factor.
+ */
+ void setScaleY(float v) {
+ values[SCALE_Y] = v;
+ }
+
+ /**
+ * Sets the vertical skew factor.
+ */
+ void setSkewY(float v) {
+ values[SKEW_Y] = v;
+ }
+
+ /**
+ * Sets the horizontal skew factor.
+ */
+ void setSkewX(float v) {
+ values[SKEW_X] = v;
+ }
+
+ /**
+ * Sets the horizontal translation.
+ */
+ void setTranslateX(float v) {
+ values[TRANS_X] = v;
+ }
+
+ /**
+ * Sets the vertical translation.
+ */
+ void setTranslateY(float v) {
+ values[TRANS_Y] = v;
+ }
+
+ /**
+ * Sets all values from parameters. Sets matrix to:
+ *
+ * | scaleX skewX transX |
+ * | skewY scaleY transY |
+ * | 0 0 1 |
+ *
+ * @param scaleX horizontal scale factor to store
+ * @param skewX horizontal skew factor to store
+ * @param transX horizontal translation to store
+ * @param skewY vertical skew factor to store
+ * @param scaleY vertical scale factor to store
+ * @param transY vertical translation to store
+ */
+ void setAll(float scaleX, float skewX, float transX, float skewY, float scaleY, float transY);
+
+ /**
+ * Sets the Matrix to affine values, passed in column major order:
+ *
+ * | a c tx |
+ * | b d ty |
+ * | 0 1 |
+ *
+ * @param a horizontal scale factor
+ * @param b vertical skew factor
+ * @param c horizontal skew factor
+ * @param d vertical scale factor
+ * @param tx horizontal translation
+ * @param ty vertical translation
+ */
+ void setAffine(float a, float b, float c, float d, float tx, float ty);
+
+ /**
+ * Sets Matrix to identity; which has no effect on mapped Point. Sets Matrix to:
+ *
+ * | 1 0 0 |
+ * | 0 1 0 |
+ * | 0 0 1 |
+ *
+ * Also called setIdentity(); use the one that provides better inline documentation.
+ */
+ void reset();
+
+ /**
+ * Sets Matrix to identity; which has no effect on mapped Point. Sets Matrix to:
+ *
+ * | 1 0 0 |
+ * | 0 1 0 |
+ * | 0 0 1 |
+ *
+ * Also called reset(); use the one that provides better inline documentation.
+ */
+ void setIdentity() {
+ this->reset();
+ }
+
+ /**
+ * Sets Matrix to translate by (tx, ty).
+ * @param tx horizontal translation
+ * @param ty vertical translation
+ */
+ void setTranslate(float tx, float ty);
+
+ /**
+ * Sets Matrix to scale by sx and sy, about a pivot point at (px, py). The pivot point is
+ * unchanged when mapped with Matrix.
+ * @param sx horizontal scale factor
+ * @param sy vertical scale factor
+ * @param px pivot on x-axis
+ * @param py pivot on y-axis
+ */
+ void setScale(float sx, float sy, float px, float py);
+
+ /**
+ * Sets Matrix to scale by sx and sy about at pivot point at (0, 0).
+ * @param sx horizontal scale factor
+ * @param sy vertical scale factor
+ */
+ void setScale(float sx, float sy);
+
+ /**
+ * Sets Matrix to rotate by degrees about a pivot point at (px, py). The pivot point is
+ * unchanged when mapped with Matrix. Positive degrees rotates clockwise.
+ * @param degrees angle of axes relative to upright axes
+ * @param px pivot on x-axis
+ * @param py pivot on y-axis
+ */
+ void setRotate(float degrees, float px, float py);
+
+ /**
+ * Sets Matrix to rotate by degrees about a pivot point at (0, 0). Positive degrees rotates
+ * clockwise.
+ * @param degrees angle of axes relative to upright axes
+ */
+ void setRotate(float degrees);
+
+ /**
+ * Sets Matrix to rotate by sinValue and cosValue, about a pivot point at (px, py).
+ * The pivot point is unchanged when mapped with Matrix.
+ * Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
+ * Vector length specifies the scale factor.
+ */
+ void setSinCos(float sinV, float cosV, float px, float py);
+
+ /**
+ * Sets Matrix to rotate by sinValue and cosValue, about a pivot point at (0, 0).
+ * Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
+ * Vector length specifies the scale factor.
+ */
+ void setSinCos(float sinV, float cosV);
+
+ /**
+ * Sets Matrix to skew by kx and ky, about a pivot point at (px, py). The pivot point is
+ * unchanged when mapped with Matrix.
+ * @param kx horizontal skew factor
+ * @param ky vertical skew factor
+ * @param px pivot on x-axis
+ * @param py pivot on y-axis
+ */
+ void setSkew(float kx, float ky, float px, float py);
+
+ /**
+ * Sets Matrix to skew by kx and ky, about a pivot point at (0, 0).
+ * @param kx horizontal skew factor
+ * @param ky vertical skew factor
+ */
+ void setSkew(float kx, float ky);
+
+ /**
+ * Sets Matrix to Matrix a multiplied by Matrix b. Either a or b may be this.
+ *
+ * Given:
+ *
+ * | A B C | | J K L |
+ * a = | D E F |, b = | M N O |
+ * | G H I | | P Q R |
+ *
+ * sets Matrix to:
+ *
+ * | A B C | | J K L | | AJ+BM+CP AK+BN+CQ AL+BO+CR |
+ * a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
+ * | G H I | | P Q R | | GJ+HM+IP GK+HN+IQ GL+HO+IR |
+ *
+ * @param a Matrix on the left side of multiply expression
+ * @param b Matrix on the right side of multiply expression
+ */
+ void setConcat(const Matrix& a, const Matrix& b);
+
+ /**
+ * Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
+ */
+ void preTranslate(float tx, float ty);
+
+ /**
+ * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
+ */
+ void preScale(float sx, float sy, float px, float py);
+
+ /**
+ * Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
+ */
+ void preScale(float sx, float sy);
+
+ /**
+ * Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py)
+ */
+ void preRotate(float degrees, float px, float py);
+
+ /**
+ * Preconcats the matrix with the specified rotation. M' = M * R(degrees)
+ */
+ void preRotate(float degrees);
+
+ /**
+ * Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py)
+ */
+ void preSkew(float kx, float ky, float px, float py);
+
+ /**
+ * Preconcats the matrix with the specified skew. M' = M * K(kx, ky)
+ */
+ void preSkew(float kx, float ky);
+
+ /**
+ * Preconcats the matrix with the specified matrix. M' = M * other
+ */
+ void preConcat(const Matrix& other);
+
+ /**
+ * Postconcats the matrix with the specified translation. M' = T(tx, ty) * M
+ */
+ void postTranslate(float tx, float ty);
+
+ /**
+ * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
+ */
+ void postScale(float sx, float sy, float px, float py);
+
+ /**
+ * Postconcats the matrix with the specified scale. M' = S(sx, sy) * M
+ */
+ void postScale(float sx, float sy);
+
+ /**
+ * Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M
+ */
+ void postRotate(float degrees, float px, float py);
+
+ /**
+ * Postconcats the matrix with the specified rotation. M' = R(degrees) * M
+ */
+ void postRotate(float degrees);
+
+ /**
+ * Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M
+ */
+ void postSkew(float kx, float ky, float px, float py);
+
+ /**
+ * Postconcats the matrix with the specified skew. M' = K(kx, ky) * M
+ */
+ void postSkew(float kx, float ky);
+
+ /**
+ * Postconcats the matrix with the specified matrix. M' = other * M
+ */
+ void postConcat(const Matrix& other);
+
+ /**
+ * If this matrix can be inverted, return true and if the inverse is not null, set inverse to be
+ * the inverse of this matrix. If this matrix cannot be inverted, ignore the inverse and return
+ * false.
+ */
+ bool invert(Matrix* inverse) const {
+ if (this->isIdentity()) {
+ if (inverse) {
+ inverse->reset();
+ }
+ return true;
+ }
+ return this->invertNonIdentity(inverse);
+ }
+
+ /**
+ * Returns ture if the Matrix is invertible.
+ */
+ bool invertible() const;
+
+ /**
+ * Maps src Point array of length count to dst Point array of equal or greater length. Points are
+ * mapped by multiplying each Point by Matrix. Given:
+ *
+ * | A B C | | x |
+ * Matrix = | D E F |, pt = | y |
+ * | G H I | | 1 |
+ *
+ * where
+ *
+ * for (i = 0; i < count; ++i) {
+ * x = src[i].fX
+ * y = src[i].fY
+ * }
+ *
+ * each dst Point is computed as:
+ *
+ * |A B C| |x| Ax+By+C Dx+Ey+F
+ * Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+ * |G H I| |1| Gx+Hy+I Gx+Hy+I
+ *
+ * src and dst may point to the same storage.
+ *
+ * @param dst storage for mapped Point
+ * @param src Point to transform
+ * @param count number of Points to transform
+ */
+ void mapPoints(Point dst[], const Point src[], int count) const;
+
+ /**
+ * Maps pts Point array of length count in place. Points are mapped by multiplying each Point by
+ * Matrix. Given:
+ *
+ * | A B C | | x |
+ * Matrix = | D E F |, pt = | y |
+ * | G H I | | 1 |
+ *
+ * where
+ *
+ * for (i = 0; i < count; ++i) {
+ * x = pts[i].fX
+ * y = pts[i].fY
+ * }
+ *
+ * each resulting pts Point is computed as:
+ *
+ * |A B C| |x| Ax+By+C Dx+Ey+F
+ * Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+ * |G H I| |1| Gx+Hy+I Gx+Hy+I
+ *
+ * @param pts storage for mapped Point
+ * @param count number of Points to transform
+ */
+ void mapPoints(Point pts[], int count) const {
+ this->mapPoints(pts, pts, count);
+ }
+
+ /**
+ * Maps Point (x, y) to result. Point is mapped by multiplying by Matrix. Given:
+ *
+ * | A B C | | x |
+ * Matrix = | D E F |, pt = | y |
+ * | G H I | | 1 |
+ *
+ * the result is computed as:
+ *
+ * |A B C| |x| Ax+By+C Dx+Ey+F
+ * Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+ * |G H I| |1| Gx+Hy+I Gx+Hy+I
+ *
+ * @param x x-axis value of Point to map
+ * @param y y-axis value of Point to map
+ * @param result storage for mapped Point
+ */
+ void mapXY(float x, float y, Point* result) const;
+
+ /**
+ * Returns Point (x, y) multiplied by Matrix. Given:
+ *
+ * | A B C | | x |
+ * Matrix = | D E F |, pt = | y |
+ * | G H I | | 1 |
+ *
+ * the result is computed as:
+ *
+ * |A B C| |x| Ax+By+C Dx+Ey+F
+ * Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
+ * |G H I| |1| Gx+Hy+I Gx+Hy+I
+ *
+ * @param x x-axis value of Point to map
+ * @param y y-axis value of Point to map
+ * @return mapped Point
+ */
+ Point mapXY(float x, float y) const {
+ Point result = {};
+ this->mapXY(x, y, &result);
+ return result;
+ }
+
+ /**
+ * Returns true if Matrix maps Rect to another Rect. If true, the Matrix is identity, or scales,
+ * or rotates a multiple of 90 degrees, or mirrors on axes. In all cases, Matrix may also have
+ * translation. Matrix form is either:
+ *
+ * | scale-x 0 translate-x |
+ * | 0 scale-y translate-y |
+ * | 0 0 1 |
+ *
+ * or
+ *
+ * | 0 rotate-x translate-x |
+ * | rotate-y 0 translate-y |
+ * | 0 0 1 |
+ *
+ * for non-zero values of scale-x, scale-y, rotate-x, and rotate-y.
+ */
+ bool rectStaysRect() const;
+
+ /**
+ * Sets dst to bounds of src corners mapped by Matrix.
+ */
+ void mapRect(Rect* dst, const Rect& src) const;
+
+ /**
+ * Sets rect to bounds of rect corners mapped by Matrix.
+ */
+ void mapRect(Rect* rect) const {
+ mapRect(rect, *rect);
+ }
+
+ /**
+ * Returns bounds of src corners mapped by Matrix.
+ */
+ Rect mapRect(const Rect& src) const {
+ Rect dst = {};
+ mapRect(&dst, src);
+ return dst;
+ }
+
+ /** Compares a and b; returns true if a and b are numerically equal. Returns true even if sign
+ * of zero values are different. Returns false if either Matrix contains NaN, even if the other
+ * Matrix also contains NaN.
+ */
+ friend bool operator==(const Matrix& a, const Matrix& b);
+
+ /**
+ * Compares a and b; returns true if a and b are not numerically equal. Returns false even if
+ * sign of zero values are different. Returns true if either Matrix contains NaN, even if the
+ * other Matrix also contains NaN.
+ */
+ friend bool operator!=(const Matrix& a, const Matrix& b) {
+ return !(a == b);
+ }
+
+ /**
+ * Returns the minimum scaling factor of the Matrix by decomposing the scaling and skewing
+ * elements. Returns -1 if scale factor overflows.
+ */
+ float getMinScale() const;
+
+ /**
+ * Returns the maximum scaling factor of the Matrix by decomposing the scaling and skewing
+ * elements. Returns -1 if scale factor overflows.
+ */
+ float getMaxScale() const;
+
+ /**
+ * Returns true if all elements of the matrix are finite. Returns false if any element is
+ * infinity, or NaN.
+ */
+ bool isFinite() const;
+
+ /**
+ * Returns reference to const identity Matrix. Returned Matrix is set to:
+ *
+ * | 1 0 0 |
+ * | 0 1 0 |
+ * | 0 0 1 |
+ *
+ * @return const identity Matrix
+ */
+ static const Matrix& I();
+
+ private:
+ float values[6];
+ /**
+ * Matrix organizes its values in row order. These members correspond to each value in Matrix.
+ */
+ static constexpr int SCALE_X = 0; //!< horizontal scale factor
+ static constexpr int SKEW_X = 1; //!< horizontal skew factor
+ static constexpr int TRANS_X = 2; //!< horizontal translation
+ static constexpr int SKEW_Y = 3; //!< vertical skew factor
+ static constexpr int SCALE_Y = 4; //!< vertical scale factor
+ static constexpr int TRANS_Y = 5; //!< vertical translation
+
+ void setScaleTranslate(float sx, float sy, float tx, float ty);
+ bool invertNonIdentity(Matrix* inverse) const;
+ bool getMinMaxScaleFactors(float results[2]) const;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Paint.h b/include/tgfx/core/Paint.h
new file mode 100644
index 00000000..24982751
--- /dev/null
+++ b/include/tgfx/core/Paint.h
@@ -0,0 +1,218 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Color.h"
+#include "tgfx/core/Stroke.h"
+#include "tgfx/core/ImageFilter.h"
+#include "tgfx/core/MaskFilter.h"
+#include "tgfx/core/Shader.h"
+
+namespace tgfx {
+/**
+ * Defines enumerations for Paint.setStyle().
+ */
+enum class PaintStyle {
+ /**
+ * Set to fill geometry.
+ */
+ Fill,
+ /**
+ * Set to stroke geometry.
+ */
+ Stroke
+};
+
+/**
+ * Paint controls options applied when drawing.
+ */
+class Paint {
+ public:
+ /**
+ * Sets all Paint contents to their initial values. This is equivalent to replacing Paint with the
+ * result of Paint().
+ */
+ void reset();
+
+ /**
+ * Returns whether the geometry is filled, stroked, or filled and stroked.
+ */
+ PaintStyle getStyle() const {
+ return style;
+ }
+
+ /**
+ * Sets whether the geometry is filled, stroked, or filled and stroked.
+ */
+ void setStyle(PaintStyle newStyle) {
+ style = newStyle;
+ }
+
+ /**
+ * Retrieves alpha and RGB, unpremultiplied, as four floating point values.
+ */
+ Color getColor() const {
+ return color;
+ }
+
+ /**
+ * Sets alpha and RGB used when stroking and filling. The color is four floating point values,
+ * unpremultiplied.
+ */
+ void setColor(Color newColor) {
+ color = newColor;
+ }
+
+ /**
+ * Retrieves alpha from the color used when stroking and filling.
+ */
+ float getAlpha() const {
+ return color.alpha;
+ }
+
+ /**
+ * Replaces alpha, leaving RGB unchanged.
+ */
+ void setAlpha(float newAlpha) {
+ color.alpha = newAlpha;
+ }
+
+ /**
+ * Returns the thickness of the pen used by Paint to outline the shape.
+ * @return zero for hairline, greater than zero for pen thickness
+ */
+ float getStrokeWidth() const {
+ return stroke.width;
+ }
+
+ /**
+ * Sets the thickness of the pen used by the paint to outline the shape. Has no effect if width is
+ * less than zero.
+ * @param width zero thickness for hairline; greater than zero for pen thickness
+ */
+ void setStrokeWidth(float width) {
+ stroke.width = width;
+ }
+
+ /**
+ * Returns the geometry drawn at the beginning and end of strokes.
+ */
+ LineCap getLineCap() const {
+ return stroke.cap;
+ }
+
+ /**
+ * Sets the geometry drawn at the beginning and end of strokes.
+ */
+ void setLineCap(LineCap cap) {
+ stroke.cap = cap;
+ }
+
+ /**
+ * Returns the geometry drawn at the corners of strokes.
+ */
+ LineJoin getLineJoin() const {
+ return stroke.join;
+ }
+
+ /**
+ * Sets the geometry drawn at the corners of strokes.
+ */
+ void setLineJoin(LineJoin join) {
+ stroke.join = join;
+ }
+
+ /**
+ * Returns the limit at which a sharp corner is drawn beveled.
+ */
+ float getMiterLimit() const {
+ return stroke.miterLimit;
+ }
+
+ /**
+ * Sets the limit at which a sharp corner is drawn beveled.
+ */
+ void setMiterLimit(float limit) {
+ stroke.miterLimit = limit;
+ }
+
+ /**
+ * Returns the stroke options.
+ */
+ const Stroke* getStroke() const {
+ return &stroke;
+ }
+
+ /**
+ * Sets the stroke options.
+ */
+ void setStroke(const Stroke& newStroke) {
+ stroke = newStroke;
+ }
+
+ /**
+ * Returns optional colors used when filling a path if previously set, such as a gradient.
+ */
+ std::shared_ptr getShader() const {
+ return shader;
+ }
+
+ /**
+ * Sets optional colors used when filling a path, such as a gradient. If nullptr, color is used
+ * instead.
+ */
+ void setShader(std::shared_ptr newShader) {
+ shader = std::move(newShader);
+ }
+
+ std::shared_ptr getMaskFilter() const {
+ return maskFilter;
+ }
+
+ void setMaskFilter(std::shared_ptr newMaskFilter) {
+ maskFilter = std::move(newMaskFilter);
+ }
+
+ std::shared_ptr getColorFilter() const {
+ return colorFilter;
+ }
+
+ void setColorFilter(std::shared_ptr newColorFilter) {
+ colorFilter = std::move(newColorFilter);
+ }
+
+ // TODO(pengweilv): Used when drawing, currently only works with drawTexture.
+ void setImageFilter(std::shared_ptr newImageFilter) {
+ imageFilter = std::move(newImageFilter);
+ }
+
+ std::shared_ptr getImageFilter() const {
+ return imageFilter;
+ }
+
+ private:
+ PaintStyle style = PaintStyle::Fill;
+ Color color = Color::Black();
+ Stroke stroke = Stroke(0);
+ std::shared_ptr shader = nullptr;
+ std::shared_ptr maskFilter = nullptr;
+ std::shared_ptr colorFilter = nullptr;
+ std::shared_ptr imageFilter = nullptr;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Path.h b/include/tgfx/core/Path.h
new file mode 100644
index 00000000..efe6ae87
--- /dev/null
+++ b/include/tgfx/core/Path.h
@@ -0,0 +1,272 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Matrix.h"
+#include "tgfx/core/PathTypes.h"
+
+namespace tgfx {
+class PathRef;
+
+/**
+ * Path contain geometry. Path may be empty, or contain one or more verbs that outline a figure.
+ * Path always starts with a move verb to a Cartesian coordinate, and may be followed by additional
+ * verbs that add lines or curves. dding a close verb makes the geometry into a continuous loop, a
+ * closed contour. Path may contain any number of contours, each beginning with a move verb.
+ */
+class Path {
+ public:
+ /**
+ * Creates an empty path.
+ */
+ Path();
+
+ /**
+ * Compares a and b; returns true if they are equivalent.
+ */
+ friend bool operator==(const Path& a, const Path& b);
+
+ /**
+ * Compares a and b; returns true if they are not equivalent.
+ */
+ friend bool operator!=(const Path& a, const Path& b);
+
+ /**
+ * Returns PathFillType, the rule used to fill Path. PathFillType of a new Path is Path
+ * FillType::Winding.
+ */
+ PathFillType getFillType() const;
+
+ /**
+ * Sets PathFillType, the rule used to fill Path.
+ */
+ void setFillType(PathFillType fillType);
+
+ /**
+ * Returns if PathFillType is InverseWinding or InverseEvenOdd.
+ */
+ bool isInverseFillType() const;
+
+ /**
+ * Replaces PathFillType with its inverse.
+ */
+ void toggleInverseFillType();
+
+ /**
+ * Returns true if Path is equivalent to Rect when filled, Otherwise returns false, and leaves
+ * rect unchanged. The rect may be smaller than the Path bounds. Path bounds may include
+ * PathVerb::Move points that do not alter the area drawn by the returned rect.
+ */
+ bool asRect(Rect* rect) const;
+
+ /**
+ * Returns true if Path is equivalent to RRect when filled, Otherwise returns false, and leaves
+ * rRect unchanged.
+ */
+ bool asRRect(RRect* rRect) const;
+
+ /**
+ * Returns true if Path contains only one line;
+ */
+ bool isLine(Point line[2] = nullptr) const;
+
+ /**
+ * Returns the bounds of the path's points. If the path contains 0 or 1 points, the bounds is set
+ * to (0,0,0,0), and isEmpty() will return true. Note: this bounds may be larger than the actual
+ * shape, since curves do not extend as far as their control points.
+ */
+ Rect getBounds() const;
+
+ /**
+ * Returns true if Path is empty.
+ */
+ bool isEmpty() const;
+
+ /**
+ * Returns true if the point (x, y) is contained by Path, taking into account PathFillType.
+ */
+ bool contains(float x, float y) const;
+
+ /**
+ * Returns true if rect is contained by Path. This method is conservative. it may return false
+ * when rect is actually contained by Path. For now, only returns true if Path has one contour.
+ */
+ bool contains(const Rect& rect) const;
+
+ /**
+ * Adds beginning of contour at Point (x, y).
+ */
+ void moveTo(float x, float y);
+
+ /**
+ * Adds beginning of contour at point.
+ */
+ void moveTo(const Point& point);
+
+ /**
+ * Adds a line from last point to (x, y).
+ */
+ void lineTo(float x, float y);
+
+ /**
+ * Adds a line from last point to new point.
+ */
+ void lineTo(const Point& point);
+
+ /**
+ * Adds a quad curve from last point towards (controlX, controlY), ending at (x, y).
+ */
+ void quadTo(float controlX, float controlY, float x, float y);
+
+ /**
+ * Adds a quad curve from last point towards control, ending at point.
+ */
+ void quadTo(const Point& control, const Point& point);
+
+ /**
+ * Adds a cubic curve from last point towards (controlX1, controlY1), then towards
+ * (controlX2, controlY2), ending at (x, y).
+ */
+ void cubicTo(float controlX1, float controlY1, float controlX2, float controlY2, float x,
+ float y);
+
+ /**
+ * Adds a cubic curve from last point towards control1, then towards control2, ending at (x, y).
+ */
+ void cubicTo(const Point& control1, const Point& control2, const Point& point);
+
+ /**
+ * Closes the current contour of Path. A closed contour connects the first and last Point with
+ * line, forming a continuous loop.
+ */
+ void close();
+
+ /**
+ * Adds a rect to Path. If reversed is false, Rect begins at startIndex point and continues
+ * clockwise if reversed is false, counterclockwise if reversed is true. The indices of all points
+ * are as follows:
+ * 0 1
+ * *-------*
+ * | |
+ * *-------*
+ * 3 2
+ */
+ void addRect(const Rect& rect, bool reversed = false, unsigned startIndex = 0);
+
+ /**
+ * Adds a rect to Path. If reversed is false, Rect begins at startIndex point and continues
+ * clockwise if reversed is false, counterclockwise if reversed is true. The indices of all points
+ * are as follows:
+ * 0 1
+ * *-------*
+ * | |
+ * *-------*
+ * 3 2
+ */
+ void addRect(float left, float top, float right, float bottom, bool reversed = false,
+ unsigned startIndex = 0);
+
+ /**
+ * Adds a oval to path. Oval is upright ellipse bounded by Rect oval with radius equal to half
+ * oval width and half oval height. Oval begins at startIndex point and continues clockwise if
+ * reversed is false, counterclockwise if reversed is true. The indices of all points are as
+ * follows:
+ * 0
+ * --*--
+ * | |
+ * 3 * * 1
+ * | |
+ * --*--
+ * 2
+ */
+ void addOval(const Rect& oval, bool reversed = false, unsigned startIndex = 0);
+
+ /**
+ * Appends arc to Path, as the start of new contour. Arc added is part of ellipse bounded by oval,
+ * from startAngle through sweepAngle. Both startAngle and sweepAngle are measured in degrees,
+ * where zero degrees is aligned with the positive x-axis, and positive sweeps extends arc
+ * clockwise. If sweepAngle <= -360, or sweepAngle >= 360; and startAngle modulo 90 is nearly
+ * zero, append oval instead of arc. Otherwise, sweepAngle values are treated modulo 360, and arc
+ * may or may not draw depending on numeric rounding.
+ *
+ * @param oval bounds of ellipse containing arc
+ * @param startAngle starting angle of arc in degrees
+ * @param sweepAngle sweep, in degrees. Positive is clockwise; treated modulo 360
+ */
+ void addArc(const Rect& oval, float startAngle, float sweepAngle);
+
+ /**
+ * Adds a round rect to path. creating a new closed contour, each corner is 90 degrees of an
+ * ellipse with radius (radiusX, radiusY). The round rect begins at startIndex point and continues
+ * clockwise if reversed is false, counterclockwise if reversed is true. The indices of all points
+ * are as follows:
+ * 0 1
+ * *------*
+ * 7 * * 2
+ * | |
+ * 6 * * 3
+ * *------*
+ * 5 4
+ */
+ void addRoundRect(const Rect& rect, float radiusX, float radiusY, bool reversed = false,
+ unsigned startIndex = 0);
+
+ /**
+ * Adds a src to this Path.
+ */
+ void addPath(const Path& src, PathOp op = PathOp::Append);
+
+ /**
+ * Sets Path to its initial state. Internal storage associated with Path is released.
+ */
+ void reset();
+
+ /**
+ * Applies matrix to this Path, this transforms verb array, Point array, and weight.
+ */
+ void transform(const Matrix& matrix);
+
+ /**
+ * Reveres this path from back to front.
+ */
+ void reverse();
+
+ /**
+ * Iterates through verb array and associated Point array.
+ */
+ void decompose(const PathIterator& iterator, void* info = nullptr) const;
+
+ /**
+ * Returns the number of points in Path.
+ */
+ int countPoints() const;
+
+ /**
+ * Returns the number of verbs in Path.
+ */
+ int countVerbs() const;
+
+ private:
+ std::shared_ptr pathRef = nullptr;
+
+ PathRef* writableRef();
+
+ friend class PathRef;
+};
+} // namespace tgfx
\ No newline at end of file
diff --git a/include/tgfx/core/PathEffect.h b/include/tgfx/core/PathEffect.h
new file mode 100644
index 00000000..65f7ec2e
--- /dev/null
+++ b/include/tgfx/core/PathEffect.h
@@ -0,0 +1,60 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Path.h"
+#include "tgfx/core/Stroke.h"
+
+namespace tgfx {
+/**
+ * PathEffect applies transformation to a Path.
+ */
+class PathEffect {
+ public:
+ /**
+ * Creates a stroke path effect with the specified stroke options.
+ */
+ static std::unique_ptr MakeStroke(const Stroke* stroke);
+
+ /**
+ * Creates a dash path effect.
+ * @param intervals array containing an even number of entries (>=2), with the even indices
+ * specifying the length of "on" intervals, and the odd indices specifying the length of "off"
+ * intervals.
+ * @param count number of elements in the intervals array
+ * @param phase offset into the intervals array (mod the sum of all of the intervals).
+ */
+ static std::unique_ptr MakeDash(const float intervals[], int count, float phase);
+
+ /**
+ * Create a corner path effect.
+ * @param radius must be > 0 to have an effect. It specifies the distance from each corner that
+ * should be "rounded".
+ */
+ static std::unique_ptr MakeCorner(float radius);
+
+ virtual ~PathEffect() = default;
+
+ /**
+ * Applies this effect to specified path. Returns false if this effect cannot be applied, and
+ * leaves this path unchanged.
+ */
+ virtual bool applyTo(Path* path) const = 0;
+};
+} // namespace tgfx
\ No newline at end of file
diff --git a/include/tgfx/core/PathMeasure.h b/include/tgfx/core/PathMeasure.h
new file mode 100644
index 00000000..65a52405
--- /dev/null
+++ b/include/tgfx/core/PathMeasure.h
@@ -0,0 +1,61 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Path.h"
+
+namespace tgfx {
+/**
+ * PathMeasure calculates the length of a Path and cuts child segments from it.
+ */
+class PathMeasure {
+ public:
+ /**
+ * Initialize the PathMeasure with the specified path.
+ */
+ static std::unique_ptr MakeFrom(const Path& path);
+
+ virtual ~PathMeasure() = default;
+
+ /**
+ * Return the total length of the the path.
+ */
+ virtual float getLength() = 0;
+
+ /**
+ * Given a start and stop distance, return in result the intervening segment(s). If the segment is
+ * zero-length, return false, else return true. startD and stopD are pinned to legal values
+ * (0..getLength()). If startD > stopD then return false (and leave dst untouched).
+ */
+ virtual bool getSegment(float startD, float stopD, Path* result) = 0;
+
+ /**
+ * Pins distance to 0 <= distance <= getLength(), and then computes
+ * the corresponding position and tangent.
+ * Returns false if there is no path, or a zero-length path was specified, in which case
+ * position and tangent are unchanged.
+ */
+ virtual bool getPosTan(float distance, Point* position, Point* tangent) = 0;
+
+ /**
+ * Returns true if the current contour is closed().
+ */
+ virtual bool isClosed() = 0;
+};
+} // namespace tgfx
\ No newline at end of file
diff --git a/include/tgfx/core/PathTypes.h b/include/tgfx/core/PathTypes.h
new file mode 100644
index 00000000..68add062
--- /dev/null
+++ b/include/tgfx/core/PathTypes.h
@@ -0,0 +1,104 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/Point.h"
+
+namespace tgfx {
+/**
+ * PathFillType selects the rule used to fill Path.
+ */
+enum class PathFillType {
+ /**
+ * Enclosed by a non-zero sum of contour directions.
+ */
+ Winding,
+ /**
+ * Enclosed by an odd number of contours.
+ */
+ EvenOdd,
+ /**
+ * Enclosed by a zero sum of contour directions.
+ */
+ InverseWinding,
+ /**
+ * Enclosed by an even number of contours.
+ */
+ InverseEvenOdd,
+};
+
+/**
+ * The logical operations that can be performed when combining two paths.
+ */
+enum class PathOp {
+ /**
+ * Appended to destination unaltered.
+ */
+ Append,
+ /**
+ * Subtract the op path from the destination path.
+ */
+ Difference,
+ /**
+ * Intersect the two paths.
+ */
+ Intersect,
+ /**
+ * Union (inclusive-or) the two paths.
+ */
+ Union,
+ /**
+ * Exclusive-or the two paths.
+ */
+ XOR,
+};
+
+/**
+ * PathVerb instructs Path how to interpret one or more Point, manage contour, and terminate Path.
+ */
+enum class PathVerb {
+ /**
+ * PathIterator returns 1 point.
+ */
+ Move,
+ /**
+ * PathIterator returns 2 points.
+ */
+ Line,
+ /**
+ * PathIterator returns 3 points.
+ */
+ Quad,
+ /**
+ * PathIterator returns 4 points.
+ */
+ Cubic,
+ /**
+ * PathIterator returns 0 points.
+ */
+ Close
+};
+
+/**
+ * Zero to four Point are stored in points, depending on the returned PathVerb
+ */
+using PathIterator = std::function;
+
+} // namespace tgfx
diff --git a/include/tgfx/core/Pixmap.h b/include/tgfx/core/Pixmap.h
new file mode 100644
index 00000000..8e583efe
--- /dev/null
+++ b/include/tgfx/core/Pixmap.h
@@ -0,0 +1,219 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Bitmap.h"
+#include "tgfx/core/Rect.h"
+
+namespace tgfx {
+/**
+ * Pixmap provides a utility to pair ImageInfo width pixels. Pixmap is a low-level class that
+ * provides convenience functions to access raster destinations, which can convert the format of
+ * pixels from one to another. Pixmap does not try to manage the lifetime of the pixel memory. Use
+ * Bitmap to manage pixel memory. Pixmap is not thread safe.
+ */
+class Pixmap {
+ public:
+ /**
+ * Creates an empty Pixmap without pixels, and with an empty ImageInfo.
+ */
+ Pixmap() = default;
+
+ /**
+ * Creates a new Pixmap with the specified ImageInfo and read-only pixels. The memory lifetime of
+ * pixels is managed by the caller. When Pixmap goes out of scope, the pixels is unaffected.
+ */
+ Pixmap(const ImageInfo& info, const void* pixels);
+
+ /**
+ * Creates a new Bitmap with specified ImageInfo and writable pixels. The memory lifetime of
+ * pixels is managed by the caller. When Pixmap goes out of scope, the pixels is unaffected.
+ */
+ Pixmap(const ImageInfo& info, void* pixels);
+
+ /**
+ * Creates a new Pixmap from the specified read-only Bitmap. Pixmap will lock pixels from the
+ * Bitmap and take a reference on its PixelRef object. The Bitmap will remain locked until the
+ * Pixmap goes out of scope or reset.
+ */
+ explicit Pixmap(const Bitmap& bitmap);
+
+ /**
+ * Creates a new Pixmap from the specified writable Bitmap. Pixmap will lock pixels from the
+ * Bitmap and take a reference on its PixelRef object. The Bitmap will remain locked until the
+ * Pixmap goes out of scope or reset.
+ */
+ explicit Pixmap(Bitmap& bitmap);
+
+ ~Pixmap();
+
+ /**
+ * Sets the ImageInfo to empty, and pixels to nullptr.
+ */
+ void reset();
+
+ /**
+ * Sets the Pixmap to the specified info and pixels. The memory lifetime of pixels is managed by
+ * the caller. When Pixmap goes out of scope, the memory of pixels is unaffected.
+ */
+ void reset(const ImageInfo& info, const void* pixels);
+
+ /**
+ * Set the Pixmap to the specified ImageInfo and writable pixels. The memory lifetime of pixels is
+ * managed by the caller. When Pixmap goes out of scope, the memory of pixels is unaffected.
+ */
+ void reset(const ImageInfo& info, void* pixels);
+
+ /**
+ * Sets the Pixmap to the specified read-only Bitmap. Pixmap will lock pixels from the Bitmap and
+ * take a reference on its PixelRef object. The Bitmap will remain locked until the Pixmap goes
+ * out of scope or reset.
+ */
+ void reset(const Bitmap& bitmap);
+
+ /**
+ * Sets the Pixmap to the specified writable Bitmap. Pixmap will lock pixels from the Bitmap and
+ * take a reference on its PixelRef object. The Bitmap will remain locked until the Pixmap goes
+ * out of scope or reset.
+ */
+ void reset(Bitmap& bitmap);
+
+ /**
+ * Return true if the Pixmap describes an empty area of pixels.
+ */
+ bool isEmpty() const {
+ return _info.isEmpty();
+ }
+
+ /**
+ * Returns an ImageInfo describing the width, height, color type, alpha type, and row bytes of the
+ * pixels.
+ */
+ const ImageInfo& info() const {
+ return _info;
+ }
+
+ /**
+ * Returns the width of the pixels.
+ */
+ int width() const {
+ return _info.width();
+ }
+
+ /**
+ * Returns the height of the pixels.
+ */
+ int height() const {
+ return _info.height();
+ }
+
+ /**
+ * Returns the ColorType of the pixels.
+ */
+ ColorType colorType() const {
+ return _info.colorType();
+ }
+
+ /**
+ * Returns the AlphaType of the pixels.
+ */
+ AlphaType alphaType() const {
+ return _info.alphaType();
+ }
+
+ /**
+ * Returns true if pixels represent transparency only. If true, each pixel is packed in 8 bits as
+ * defined by ColorType::ALPHA_8.
+ */
+ bool isAlphaOnly() const {
+ return _info.isAlphaOnly();
+ }
+
+ /**
+ * Returns the rowBytes of the pixels.
+ */
+ size_t rowBytes() const {
+ return _info.rowBytes();
+ }
+
+ /**
+ * Returns the byte size of the pixels.
+ */
+ size_t byteSize() const {
+ return _info.byteSize();
+ }
+
+ /**
+ * Returns the pixel address, the base address corresponding to the pixel origin.
+ */
+ const void* pixels() const {
+ return _pixels;
+ }
+
+ /**
+ * Returns the writable pixel address, the base address corresponding to the pixel origin. Returns
+ * nullptr if the Pixmap is constructed from read-only pixels.
+ */
+ void* writablePixels() const {
+ return _writablePixels;
+ }
+
+ /**
+ * Returns pixel at (x, y) as unpremultiplied color. Some color precision may be lost in the
+ * conversion to unpremultiplied color; original pixel data may have additional precision. Returns
+ * a transparent color if the point (x, y) is not contained by bounds.
+ * @param x column index, zero or greater, and less than width()
+ * @param y row index, zero or greater, and less than height()
+ * @return pixel converted to unpremultiplied color
+ */
+ Color getColor(int x, int y) const;
+
+ /**
+ * Returns subset of the Pixmap. subset must be fully contained by Pixmap dimensions. Returns
+ * an empty Pixmap if subset is empty, or subset is not contained by bounds.
+ */
+ Pixmap makeSubset(const Rect& subset) const;
+
+ /**
+ * Copies a rect of pixels to dstPixels with specified ImageInfo. Copy starts at (srcX, srcY), and
+ * does not exceed Pixmap (width(), height()). Pixels are copied only if pixel conversion is
+ * possible. Returns true if pixels are copied to dstPixels.
+ */
+ bool readPixels(const ImageInfo& dstInfo, void* dstPixels, int srcX = 0, int srcY = 0) const;
+
+ /**
+ * Copies a rect of pixels from src. Copy starts at (dstX, dstY), and does not exceed
+ * Pixmap (width(), height()). Pixels are copied only if pixel conversion is possible and the
+ * Pixmap is constructed from writable pixels. Returns true if src pixels are copied to Pixmap.
+ */
+ bool writePixels(const ImageInfo& srcInfo, const void* srcPixels, int dstX = 0, int dstY = 0);
+
+ /**
+ * Replaces all pixel values with transparent colors. Returns false if the Pixmap is constructed
+ * from read-only pixels.
+ */
+ bool clear();
+
+ private:
+ ImageInfo _info = {};
+ const void* _pixels = nullptr;
+ void* _writablePixels = nullptr;
+ std::shared_ptr pixelRef = nullptr;
+};
+} // namespace tgfx
\ No newline at end of file
diff --git a/include/tgfx/core/Point.h b/include/tgfx/core/Point.h
new file mode 100644
index 00000000..09f6c19a
--- /dev/null
+++ b/include/tgfx/core/Point.h
@@ -0,0 +1,135 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+#include
+#include
+
+namespace tgfx {
+/**
+ * Point holds two 32-bit floating point coordinates.
+ */
+struct Point {
+ /**
+ * x-axis value.
+ */
+ float x;
+ /**
+ * y-axis value.
+ */
+ float y;
+
+ /**
+ * Creates a Point set to (0, 0).
+ */
+ static const Point& Zero() {
+ static const Point zero = Point::Make(0, 0);
+ return zero;
+ }
+
+ /**
+ * Creates a Point with specified x and y value.
+ */
+ static constexpr Point Make(float x, float y) {
+ return {x, y};
+ }
+
+ /**
+ * Creates a Point with specified x and y value.
+ */
+ static constexpr Point Make(int x, int y) {
+ return {static_cast(x), static_cast(y)};
+ }
+
+ /**
+ * Returns true if fX and fY are both zero.
+ */
+ bool isZero() const {
+ return (0 == x) & (0 == y);
+ }
+
+ /**
+ * Sets fX to x and fY to y.
+ */
+ void set(float xValue, float yValue) {
+ x = xValue;
+ y = yValue;
+ }
+
+ /**
+ * Adds offset (dx, dy) to Point.
+ */
+ void offset(float dx, float dy) {
+ x += dx;
+ y += dy;
+ }
+
+ /**
+ * Returns the Euclidean distance from origin.
+ */
+ float length() const {
+ return Point::Length(x, y);
+ }
+
+ /**
+ * Returns true if a is equivalent to b.
+ */
+ friend bool operator==(const Point& a, const Point& b) {
+ return a.x == b.x && a.y == b.y;
+ }
+
+ /**
+ * Returns true if a is not equivalent to b.
+ */
+ friend bool operator!=(const Point& a, const Point& b) {
+ return a.x != b.x || a.y != b.y;
+ }
+
+ /**
+ * Returns a Point from b to a; computed as (a.fX - b.fX, a.fY - b.fY).
+ */
+ friend Point operator-(const Point& a, const Point& b) {
+ return {a.x - b.x, a.y - b.y};
+ }
+
+ /**
+ * Returns Point resulting from Point a offset by Point b, computed as:
+ * (a.fX + b.fX, a.fY + b.fY).
+ */
+ friend Point operator+(const Point& a, const Point& b) {
+ return {a.x + b.x, a.y + b.y};
+ }
+
+ /**
+ * Returns the Euclidean distance from origin.
+ */
+ static float Length(float x, float y) {
+ return sqrt(x * x + y * y);
+ }
+
+ /**
+ * Returns the Euclidean distance between a and b.
+ */
+ static float Distance(const Point& a, const Point& b) {
+ return Length(a.x - b.x, a.y - b.y);
+ }
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Rect.h b/include/tgfx/core/Rect.h
new file mode 100644
index 00000000..6c452e73
--- /dev/null
+++ b/include/tgfx/core/Rect.h
@@ -0,0 +1,499 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/Point.h"
+#include "tgfx/core/Size.h"
+
+namespace tgfx {
+/**
+ * Rect holds four float coordinates describing the upper and lower bounds of a rectangle. Rect may
+ * be created from outer bounds or from position, width, and height. Rect describes an area; if its
+ * right is less than or equal to its left, or if its bottom is less than or equal to its top, it is
+ * considered empty.
+ */
+struct Rect {
+ /**
+ * smaller x-axis bounds.
+ */
+ float left;
+ /**
+ * smaller y-axis bounds.
+ */
+ float top;
+ /**
+ * larger x-axis bounds.
+ */
+ float right;
+ /**
+ * larger y-axis bounds.
+ */
+ float bottom;
+
+ /**
+ * Returns constructed Rect set to (0, 0, 0, 0).
+ */
+ static constexpr Rect MakeEmpty() {
+ return {0, 0, 0, 0};
+ }
+
+ /**
+ * Returns constructed Rect set to float values (0, 0, w, h). Does not validate input; w or h may
+ * be negative.
+ */
+ static constexpr Rect MakeWH(float w, float h) {
+ return {0, 0, w, h};
+ }
+
+ /**
+ * Returns constructed Rect set to float values (0, 0, w, h). Does not validate input; w or h may
+ * be negative.
+ */
+ static constexpr Rect MakeWH(int w, int h) {
+ return {0, 0, static_cast(w), static_cast(h)};
+ }
+
+ /**
+ * Returns constructed Rect set to (l, t, r, b). Does not sort input; Rect may result in left
+ * greater than right, or top greater than bottom.
+ */
+ static constexpr Rect MakeLTRB(float l, float t, float r, float b) {
+ return {l, t, r, b};
+ }
+
+ /**
+ * Returns constructed Rect set to (x, y, x + w, y + h). Does not validate input; w or h may be
+ * negative.
+ */
+ static constexpr Rect MakeXYWH(float x, float y, float w, float h) {
+ return {x, y, x + w, y + h};
+ }
+
+ /**
+ * Returns constructed Rect set to (x, y, x + w, y + h). Does not validate input; w or h may be
+ * negative.
+ */
+ static constexpr Rect MakeXYWH(int x, int y, int w, int h) {
+ return {static_cast(x), static_cast(y), static_cast(x + w),
+ static_cast(y + h)};
+ }
+
+ /**
+ * Returns constructed Rect set to (0, 0, size.width, size.height). Does not validate input;
+ * size.width or size.height may be negative.
+ */
+ static constexpr Rect MakeSize(const ISize& size) {
+ return Rect{0, 0, static_cast(size.width), static_cast(size.height)};
+ }
+
+ /**
+ * Returns constructed Rect set to (0, 0, size.width, size.height). Does not validate input;
+ * size.width or size.height may be negative.
+ */
+ static constexpr Rect MakeSize(const Size& size) {
+ return Rect{0, 0, size.width, size.height};
+ }
+
+ /**
+ * Returns true if left is equal to or greater than right, or if top is equal to or greater
+ * than bottom. Call sort() to reverse rectangles with negative width() or height().
+ */
+ bool isEmpty() const {
+ // We write it as the NOT of a non-empty rect, so we will return true if any values
+ // are NaN.
+ return !(left < right && top < bottom);
+ }
+
+ /**
+ * Returns true if left is equal to or less than right, or if top is equal to or less than
+ * bottom. Call sort() to reverse rectangles with negative width() or height().
+ */
+ bool isSorted() const {
+ return left <= right && top <= bottom;
+ }
+
+ /**
+ * Returns left edge of Rect, if sorted. Call isSorted() to see if Rect is valid. Call sort() to
+ * reverse left and right if needed.
+ */
+ float x() const {
+ return left;
+ }
+
+ /**
+ * Returns top edge of Rect, if sorted. Call isEmpty() to see if Rect may be invalid, and sort()
+ * to reverse top and bottom if needed.
+ */
+ float y() const {
+ return top;
+ }
+
+ /**
+ * Returns span on the x-axis. This does not check if Rect is sorted, or if result fits in 32-bit
+ * float; result may be negative or infinity.
+ */
+ float width() const {
+ return right - left;
+ }
+
+ /**
+ * Returns span on the y-axis. This does not check if Rect is sorted, or if result fits in 32-bit
+ * float; result may be negative or infinity.
+ */
+ float height() const {
+ return bottom - top;
+ }
+
+ /**
+ * Returns spans on the x-axis and y-axis.
+ * @return Size (width, height)
+ */
+ Size size() const {
+ return Size::Make(this->width(), this->height());
+ }
+
+ /**
+ * Returns average of left edge and right edge. Result does not change if Rect is sorted.
+ */
+ float centerX() const {
+ // don't use (left + bottom) * 0.5f as that might overflow before the 0.5f
+ return left * 0.5f + right * 0.5f;
+ }
+
+ /**
+ * Returns average of top edge and bottom edge. Result does not change if Rect is sorted.
+ */
+ float centerY() const {
+ // don't use (top + bottom) * 0.5f as that might overflow before the 0.5f
+ return top * 0.5f + bottom * 0.5f;
+ }
+
+ /**
+ * Returns true if all members in a: left, top, right, and bottom; are equal to the
+ * corresponding members in b.
+ * a and b are not equal if either contain NaN. a and b are equal if members contain zeroes with
+ * different signs.
+ */
+ friend bool operator==(const Rect& a, const Rect& b) {
+ return a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom;
+ }
+
+ /**
+ * Returns true if any in a: left, top, right, and bottom; does not equal the corresponding
+ * members in b.
+ * a and b are not equal if either contain NaN. a and b are equal if members contain zeroes with
+ * different signs.
+ */
+ friend bool operator!=(const Rect& a, const Rect& b) {
+ return a.left != b.left || a.right != b.right || a.top != b.top || a.bottom != b.bottom;
+ }
+
+ /**
+ * Sets Rect to (0, 0, 0, 0).
+ */
+ void setEmpty() {
+ *this = MakeEmpty();
+ }
+
+ /**
+ * Sets Rect to (left, top, right, bottom). left and right are not sorted; left is not necessarily
+ * less than right. top and bottom are not sorted; top is not necessarily less than bottom.
+ */
+ void setLTRB(float l, float t, float r, float b) {
+ left = l;
+ top = t;
+ right = r;
+ bottom = b;
+ }
+
+ /**
+ * Sets to bounds of Point array with count entries. Returns false if count is zero or smaller, or
+ * if Point array contains an infinity or NaN; in these cases sets Rect to (0, 0, 0, 0).
+ * Result is either empty or sorted: left is less than or equal to right, and top is less than
+ * or equal to bottom.
+ */
+ bool setBounds(const Point pts[], int count);
+
+ /**
+ * Sets Rect to (x, y, x + width, y + height). Does not validate input; width or height may be
+ * negative.
+ */
+ void setXYWH(float x, float y, float width, float height) {
+ left = x;
+ top = y;
+ right = x + width;
+ bottom = y + height;
+ }
+
+ /**
+ * Sets Rect to (0, 0, width, height). Does not validate input, width or height may be negative.
+ */
+ void setWH(float width, float height) {
+ left = 0;
+ top = 0;
+ right = width;
+ bottom = height;
+ }
+
+ /**
+ * Returns Rect offset by (dx, dy).
+ * If dx is negative, Rect returned is moved to the left.
+ * If dx is positive, Rect returned is moved to the right.
+ * If dy is negative, Rect returned is moved upward.
+ * If dy is positive, Rect returned is moved downward.
+ */
+ Rect makeOffset(float dx, float dy) const {
+ return MakeLTRB(left + dx, top + dy, right + dx, bottom + dy);
+ }
+
+ /**
+ * Returns Rect, inset by (dx, dy).
+ * If dx is negative, Rect returned is wider.
+ * If dx is positive, Rect returned is narrower.
+ * If dy is negative, Rect returned is taller.
+ * If dy is positive, Rect returned is shorter.
+ */
+ Rect makeInset(float dx, float dy) const {
+ return MakeLTRB(left + dx, top + dy, right - dx, bottom - dy);
+ }
+
+ /**
+ * Returns Rect, outset by (dx, dy).
+ * If dx is negative, Rect returned is narrower.
+ * If dx is positive, Rect returned is wider.
+ * If dy is negative, Rect returned is shorter.
+ * If dy is positive, Rect returned is taller.
+ */
+ Rect makeOutset(float dx, float dy) const {
+ return MakeLTRB(left - dx, top - dy, right + dx, bottom + dy);
+ }
+
+ /**
+ * Offsets Rect by adding dx to left, right; and by adding dy to top, bottom.
+ * If dx is negative, moves Rect to the left.
+ * If dx is positive, moves Rect to the right.
+ * If dy is negative, moves Rect upward.
+ * If dy is positive, moves Rect downward.
+ */
+ void offset(float dx, float dy) {
+ left += dx;
+ top += dy;
+ right += dx;
+ bottom += dy;
+ }
+
+ /**
+ * Offsets Rect by adding delta.fX to left, right; and by adding delta.fY to top, bottom.
+ * If delta.fX is negative, moves Rect to the left.
+ * If delta.fX is positive, moves Rect to the right.
+ * If delta.fY is negative, moves Rect upward.
+ * If delta.fY is positive, moves Rect downward.
+ */
+ void offset(const Point& delta) {
+ this->offset(delta.x, delta.y);
+ }
+
+ /**
+ * Offsets Rect so that left equals newX, and top equals newY. width and height are unchanged.
+ */
+ void offsetTo(float newX, float newY) {
+ right += newX - left;
+ bottom += newY - top;
+ left = newX;
+ top = newY;
+ }
+
+ /**
+ * Insets Rect by (dx, dy).
+ * If dx is positive, makes Rect narrower.
+ * If dx is negative, makes Rect wider.
+ * If dy is positive, makes Rect shorter.
+ * If dy is negative, makes Rect taller.
+ */
+ void inset(float dx, float dy) {
+ left += dx;
+ top += dy;
+ right -= dx;
+ bottom -= dy;
+ }
+
+ /**
+ * Outsets Rect by (dx, dy).
+ * If dx is positive, makes Rect wider.
+ * If dx is negative, makes Rect narrower.
+ * If dy is positive, makes Rect taller.
+ * If dy is negative, makes Rect shorter.
+ */
+ void outset(float dx, float dy) {
+ this->inset(-dx, -dy);
+ }
+
+ /**
+ * Scale the rectangle by scaleX and scaleY.
+ */
+ void scale(float scaleX, float scaleY);
+
+ /**
+ * Returns true if Rect intersects r, and sets Rect to intersection. Returns false if Rect does
+ * not intersect r, and leaves Rect unchanged. Returns false if either r or Rect is empty, leaving
+ * Rect unchanged.
+ */
+ bool intersect(const Rect& r) {
+ return this->intersect(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Constructs Rect to intersect from (left, top, right, bottom). Does not sort construction.
+ * Returns true if Rect intersects construction, and sets Rect to intersection.
+ * Returns false if Rect does not intersect construction, and leaves Rect unchanged.
+ * Returns false if either construction or Rect is empty, leaving Rect unchanged.
+ */
+ bool intersect(float l, float t, float r, float b);
+
+ /**
+ * Returns true if a intersects b, and sets Rect to intersection.
+ * Returns false if a does not intersect b, and leaves Rect unchanged.
+ * Returns false if either a or b is empty, leaving Rect unchanged.
+ */
+ bool intersect(const Rect& a, const Rect& b);
+
+ /**
+ * Constructs Rect to intersect from (left, top, right, bottom). Does not sort construction.
+ * Returns true if Rect intersects construction.
+ * Returns false if either construction or Rect is empty, or do not intersect.
+ */
+ bool intersects(float l, float t, float r, float b) const {
+ return Intersects(left, top, right, bottom, l, t, r, b);
+ }
+
+ /**
+ * Returns true if Rect intersects r. Returns false if either r or Rect is empty, or do not
+ * intersect.
+ */
+ bool intersects(const Rect& r) const {
+ return Intersects(left, top, right, bottom, r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Returns true if a intersects b. Returns false if either a or b is empty, or do not intersect.
+ */
+ static bool Intersects(const Rect& a, const Rect& b) {
+ return Intersects(a.left, a.top, a.right, a.bottom, b.left, b.top, b.right, b.bottom);
+ }
+
+ /**
+ * Constructs Rect to intersect from (left, top, right, bottom). Does not sort construction.
+ * Sets Rect to the union of itself and the construction. Has no effect if construction is empty.
+ * Otherwise, if Rect is empty, sets Rect to construction.
+ */
+ void join(float l, float t, float r, float b);
+
+ /**
+ * Sets Rect to the union of itself and r. Has no effect if r is empty. Otherwise, if Rect is
+ * empty, sets Rect to r.
+ */
+ void join(const Rect& r) {
+ this->join(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Returns true if: left <= x < right && top <= y < bottom. Returns false if Rect is empty.
+ */
+ bool contains(float x, float y) const {
+ return x >= left && x < right && y >= top && y < bottom;
+ }
+
+ /**
+ * Returns true if Rect contains r. Returns false if Rect is empty or r is empty. Rect contains r
+ * when Rect area completely includes r area.
+ */
+ bool contains(const Rect& r) const {
+ return left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom;
+ }
+
+ /**
+ * Sets Rect by discarding the fractional portion of left and top; and rounding up right and
+ * bottom.
+ */
+ void roundOut() {
+ left = floorf(left);
+ top = floorf(top);
+ right = ceilf(right);
+ bottom = ceilf(bottom);
+ }
+
+ /**
+ * Sets Rect by rounding of left, top, right and bottom.
+ */
+ void round() {
+ left = roundf(left);
+ top = roundf(top);
+ right = roundf(right);
+ bottom = roundf(bottom);
+ }
+
+ /**
+ * Swaps left and right if left is greater than right; and swaps top and bottom if top is
+ * greater than bottom. Result may be empty; and width() and height() will be zero or positive.
+ */
+ void sort() {
+ if (left > right) {
+ std::swap(left, right);
+ }
+
+ if (top > bottom) {
+ std::swap(top, bottom);
+ }
+ }
+
+ /**
+ * Returns Rect with left and right swapped if left is greater than right, and with top and
+ * bottom swapped if top is greater than bottom. Result may be empty, and width() and height()
+ * will be zero or positive.
+ */
+ Rect makeSorted() const {
+ return MakeLTRB(std::min(left, right), std::min(top, bottom), std::max(left, right),
+ std::max(top, bottom));
+ }
+
+ private:
+ static bool Intersects(float al, float at, float ar, float ab, float bl, float bt, float br,
+ float bb) {
+ float L = al > bl ? al : bl;
+ float R = ar < br ? ar : br;
+ float T = at > bt ? at : bt;
+ float B = ab < bb ? ab : bb;
+ return L < R && T < B;
+ }
+};
+
+/**
+ * Round Rect.
+ */
+struct RRect {
+ Rect rect = Rect::MakeEmpty();
+ Point radii = Point::Zero();
+
+ /**
+ * Scale the round rectangle by scaleX and scaleY.
+ */
+ void scale(float scaleX, float scaleY);
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/SamplingOptions.h b/include/tgfx/core/SamplingOptions.h
new file mode 100644
index 00000000..1e7e85e4
--- /dev/null
+++ b/include/tgfx/core/SamplingOptions.h
@@ -0,0 +1,59 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+enum class FilterMode {
+ /**
+ * Single sample point (nearest neighbor)
+ */
+ Nearest,
+
+ /**
+ * Interpolate between 2x2 sample points (bi-linear interpolation)
+ */
+ Linear,
+};
+
+enum class MipMapMode {
+ /**
+ * ignore mipmap levels, sample from the "base"
+ */
+ None,
+ /**
+ * Sample from the nearest level
+ */
+ Nearest,
+ /**
+ * Interpolate between the two nearest levels
+ */
+ Linear,
+};
+
+struct SamplingOptions {
+ SamplingOptions() = default;
+
+ explicit SamplingOptions(FilterMode filterMode, MipMapMode mipMapMode = MipMapMode::None)
+ : filterMode(filterMode), mipMapMode(mipMapMode) {
+ }
+
+ const FilterMode filterMode = FilterMode::Linear;
+ const MipMapMode mipMapMode = MipMapMode::None;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Shader.h b/include/tgfx/core/Shader.h
new file mode 100644
index 00000000..a911e622
--- /dev/null
+++ b/include/tgfx/core/Shader.h
@@ -0,0 +1,140 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/BlendMode.h"
+#include "tgfx/core/Color.h"
+#include "tgfx/core/ColorFilter.h"
+#include "tgfx/core/Image.h"
+#include "tgfx/core/Matrix.h"
+#include "tgfx/core/Point.h"
+#include "tgfx/core/SamplingOptions.h"
+#include "tgfx/core/TileMode.h"
+
+namespace tgfx {
+struct FPArgs;
+class Texture;
+class FragmentProcessor;
+
+/**
+ * Shaders specify the source color(s) for what is being drawn. If a paint has no shader, then the
+ * paint's color is used. If the paint has a shader, then the shader's color(s) are use instead, but
+ * they are modulated by the paint's alpha.
+ */
+class Shader {
+ public:
+ /**
+ * Creates a shader that draws the specified color.
+ */
+ static std::shared_ptr MakeColorShader(Color color);
+
+ /**
+ * Creates a shader that draws the specified image. The tile modes will be ignored if the image is
+ * an RGBAAA Image.
+ */
+ static std::shared_ptr MakeImageShader(std::shared_ptr image,
+ TileMode tileModeX = TileMode::Clamp,
+ TileMode tileModeY = TileMode::Clamp,
+ SamplingOptions sampling = SamplingOptions());
+
+ static std::shared_ptr MakeBlend(BlendMode mode, std::shared_ptr dst,
+ std::shared_ptr src);
+
+ /**
+ * Returns a shader that generates a linear gradient between the two specified points.
+ * @param startPoint The start point for the gradient.
+ * @param endPoint The end point for the gradient.
+ * @param colors The array of colors, to be distributed between the two points.
+ * @param positions May be empty. The relative position of each corresponding color in the colors
+ * array. If this is empty, the the colors are distributed evenly between the start and end point.
+ * If this is not empty, the values must begin with 0, end with 1.0, and intermediate values must
+ * be strictly increasing.
+ */
+ static std::shared_ptr MakeLinearGradient(const Point& startPoint, const Point& endPoint,
+ const std::vector& colors,
+ const std::vector& positions);
+
+ /**
+ * Returns a shader that generates a radial gradient given the center and radius.
+ * @param center The center of the circle for this gradient
+ * @param radius Must be positive. The radius of the circle for this gradient.
+ * @param colors The array of colors, to be distributed between the center and edge of the circle.
+ * @param positions May be empty. The relative position of each corresponding color in the colors
+ * array. If this is empty, the the colors are distributed evenly between the start and end point.
+ * If this is not empty, the values must begin with 0, end with 1.0, and intermediate values must
+ * be strictly increasing.
+ */
+ static std::shared_ptr MakeRadialGradient(const Point& center, float radius,
+ const std::vector& colors,
+ const std::vector& positions);
+
+ /**
+ * Returns a shader that generates a sweep gradient given a center.
+ * @param center The center of the circle for this gradient
+ * @param startAngle Start of the angular range, corresponding to pos == 0.
+ * @param endAngle End of the angular range, corresponding to pos == 1.
+ * @param colors The array of colors, to be distributed around the center, within the gradient
+ * angle range.
+ * @param positions May be empty. The relative position of each corresponding color in the colors
+ * array. If this is empty, the the colors are distributed evenly between the start and end point.
+ * If this is not empty, the values must begin with 0, end with 1.0, and intermediate values must
+ * be strictly increasing.
+ */
+ static std::shared_ptr MakeSweepGradient(const Point& center, float startAngle,
+ float endAngle, const std::vector& colors,
+ const std::vector& positions);
+
+ virtual ~Shader() = default;
+
+ /**
+ * Returns true if the shader is guaranteed to produce only opaque colors, subject to the Paint
+ * using the shader to apply an opaque alpha value. Subclasses should override this to allow some
+ * optimizations.
+ */
+ virtual bool isOpaque() const {
+ return false;
+ }
+
+ /**
+ * Returns a shader that will apply the specified localMatrix to this shader. The specified
+ * matrix will be applied before any matrix associated with this shader.
+ */
+ std::shared_ptr makeWithPreLocalMatrix(const Matrix& matrix) const {
+ return makeWithLocalMatrix(matrix, true);
+ }
+
+ /**
+ * Returns a shader that will apply the specified localMatrix to this shader. The specified
+ * matrix will be applied after any matrix associated with this shader.
+ */
+ std::shared_ptr makeWithPostLocalMatrix(const Matrix& matrix) const {
+ return makeWithLocalMatrix(matrix, false);
+ }
+
+ std::shared_ptr makeWithColorFilter(std::shared_ptr colorFilter) const;
+
+ virtual std::unique_ptr asFragmentProcessor(const FPArgs& args) const = 0;
+
+ protected:
+ virtual std::shared_ptr makeWithLocalMatrix(const Matrix& matrix, bool isPre) const;
+
+ std::weak_ptr weakThis;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Shape.h b/include/tgfx/core/Shape.h
new file mode 100644
index 00000000..e82c015e
--- /dev/null
+++ b/include/tgfx/core/Shape.h
@@ -0,0 +1,97 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Color.h"
+#include "tgfx/core/Path.h"
+#include "tgfx/core/Stroke.h"
+#include "tgfx/core/TextBlob.h"
+#include "tgfx/gpu/ResourceKey.h"
+#include "tgfx/gpu/SurfaceOptions.h"
+
+namespace tgfx {
+class DrawOp;
+
+class GpuPaint;
+
+/**
+ * Represents a geometric shape that can be used as a drawing mask. Shape is usually used to cache a
+ * complex Path or TextBlob for frequent drawing. Unlike Path or TextBlob, Shape's resolution is
+ * fixed after it is created unless it represents a simple rect or rrect. Therefore, drawing a Shape
+ * with scale factors greater than 1.0 may result in blurred output. Shape is thread safe.
+ */
+class Shape {
+ public:
+ /**
+ * Creates a Shape from the fills of the given path after being scaled by the resolutionScale.
+ * Returns nullptr if the path is empty or resolutionScale is less than 0.
+ */
+ static std::shared_ptr MakeFromFill(const Path& path, float resolutionScale = 1.0f);
+
+ /**
+ * Creates a Shape from the fills of the given textBlob after being scaled by the resolutionScale.
+ * Returns nullptr if textBlob contains color glyphs or resolutionScale is less than 0.
+ */
+ static std::shared_ptr MakeFromFill(std::shared_ptr textBlob,
+ float resolutionScale = 1.0f);
+
+ /**
+ * Creates a Shape from the strokes of the given path after being scaled by the resolutionScale.
+ * Returns nullptr if path is empty or resolutionScale is less than 0.
+ */
+ static std::shared_ptr MakeFromStroke(const Path& path, const Stroke& stroke,
+ float resolutionScale = 1.0f);
+
+ /**
+ * Creates a Shape from the strokes of the given textBlob after being scaled by the
+ * resolutionScale. Returns nullptr if textBlob contains color glyphs or resolutionScale is less
+ * than 0.
+ */
+ static std::shared_ptr MakeFromStroke(std::shared_ptr textBlob,
+ const Stroke& stroke, float resolutionScale = 1.0f);
+
+ virtual ~Shape() = default;
+
+ /**
+ * Returns the resolutionScale passed in when creating the Shape.
+ */
+ float resolutionScale() const {
+ return _resolutionScale;
+ }
+
+ /**
+ * Returns the bounds of the Shape after being applied the resolutionScale.
+ */
+ virtual Rect getBounds() const = 0;
+
+ protected:
+ UniqueKey uniqueKey = {};
+
+ explicit Shape(float resolutionScale);
+
+ private:
+ std::weak_ptr weakThis;
+ float _resolutionScale = 1.0f;
+
+ virtual std::unique_ptr makeOp(GpuPaint* paint, const Matrix& viewMatrix,
+ uint32_t surfaceFlags) const = 0;
+
+ friend class Canvas;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Size.h b/include/tgfx/core/Size.h
new file mode 100644
index 00000000..072ce868
--- /dev/null
+++ b/include/tgfx/core/Size.h
@@ -0,0 +1,176 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+
+namespace tgfx {
+/**
+ * ISize holds two 32-bit integer dimensions.
+ */
+struct ISize {
+ /**
+ * Span on the x-axis.
+ */
+ int width;
+
+ /**
+ * Span on the y-axis.
+ */
+ int height;
+
+ static ISize Make(int w, int h) {
+ return {w, h};
+ }
+
+ static ISize MakeEmpty() {
+ return {0, 0};
+ }
+
+ void set(int w, int h) {
+ *this = ISize{w, h};
+ }
+
+ /**
+ * Returns true if width == 0 && height == 0
+ */
+ bool isZero() const {
+ return 0 == width && 0 == height;
+ }
+
+ /**
+ * Returns true if either width or height are <= 0
+ */
+ bool isEmpty() const {
+ return width <= 0 || height <= 0;
+ }
+
+ /**
+ * Set the width and height to 0.
+ */
+ void setEmpty() {
+ *this = ISize{0, 0};
+ }
+
+ /**
+ * Returns true if a is equivalent to b.
+ */
+ friend bool operator==(const ISize& a, const ISize& b) {
+ return a.width == b.width && a.height == b.height;
+ }
+
+ /**
+ * Returns true if a is not equivalent to b.
+ */
+ friend bool operator!=(const ISize& a, const ISize& b) {
+ return a.width != b.width || a.height != b.height;
+ }
+};
+
+/**
+ * Size holds two 32-bit floating dimensions.
+ */
+struct Size {
+ /**
+ * Span on the x-axis.
+ */
+ float width;
+
+ /**
+ * Span on the y-axis.
+ */
+ float height;
+
+ static Size Make(float w, float h) {
+ return {w, h};
+ }
+
+ static Size Make(const ISize& src) {
+ return {static_cast(src.width), static_cast(src.height)};
+ }
+
+ Size& operator=(const ISize& src) {
+ return *this = Size{static_cast(src.width), static_cast(src.height)};
+ }
+
+ static Size MakeEmpty() {
+ return {0, 0};
+ }
+
+ void set(float w, float h) {
+ *this = Size{w, h};
+ }
+
+ /**
+ * Returns true if width == 0 && height == 0
+ */
+ bool isZero() const {
+ return 0 == width && 0 == height;
+ }
+
+ /**
+ * Returns true if either width or height are <= 0
+ */
+ bool isEmpty() const {
+ return width <= 0 || height <= 0;
+ }
+
+ /**
+ * Set the width and height to 0.
+ */
+ void setEmpty() {
+ *this = Size{0, 0};
+ }
+
+ /**
+ * Returns a ISize by rounding of width and height.
+ */
+ ISize toRound() {
+ return {static_cast(roundf(width)), static_cast(roundf(height))};
+ }
+
+ /**
+ * Returns a ISize by ceiling of width and height.
+ */
+ ISize toCeil() {
+ return {static_cast(ceilf(width)), static_cast(ceilf(height))};
+ }
+
+ /**
+ * Returns a ISize by flooring of width and height.
+ */
+ ISize toFloor() {
+ return {static_cast(floorf(width)), static_cast(floorf(height))};
+ }
+
+ /**
+ * Returns true if a is equivalent to b.
+ */
+ friend bool operator==(const Size& a, const Size& b) {
+ return a.width == b.width && a.height == b.height;
+ }
+
+ /**
+ * Returns true if a is not equivalent to b.
+ */
+ friend bool operator!=(const Size& a, const Size& b) {
+ return a.width != b.width || a.height != b.height;
+ }
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Stroke.h b/include/tgfx/core/Stroke.h
new file mode 100644
index 00000000..a8937bba
--- /dev/null
+++ b/include/tgfx/core/Stroke.h
@@ -0,0 +1,96 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Cap draws at the beginning and end of an open path contour.
+ */
+enum class LineCap {
+ /**
+ * No stroke extension.
+ */
+ Butt,
+ /**
+ * Adds circle
+ */
+ Round,
+ /**
+ * Adds square
+ */
+ Square
+};
+
+/**
+ * Join specifies how corners are drawn when a shape is stroked. Join affects the four corners
+ * of a stroked rectangle, and the connected segments in a stroked path. Choose miter join to draw
+ * sharp corners. Choose round join to draw a circle with a radius equal to the stroke width on
+ * top of the corner. Choose bevel join to minimally connect the thick strokes.
+ */
+enum class LineJoin {
+ /**
+ * Extends to miter limit.
+ */
+ Miter,
+ /**
+ * Adds circle.
+ */
+ Round,
+ /**
+ * Connects outside edges.
+ */
+ Bevel
+};
+
+/**
+ * Stroke controls options applied when stroking geometries (paths, glyphs).
+ */
+class Stroke {
+ public:
+ Stroke() = default;
+
+ /**
+ * Creates a new Stroke width specified options.
+ */
+ explicit Stroke(float width, LineCap cap = LineCap::Butt, LineJoin join = LineJoin::Miter,
+ float miterLimit = 4.0f)
+ : width(width), cap(cap), join(join), miterLimit(miterLimit) {
+ }
+
+ /**
+ * The thickness of the pen used to outline the paths or glyphs.
+ */
+ float width = 1.0;
+
+ /**
+ * The geometry drawn at the beginning and end of strokes.
+ */
+ LineCap cap = LineCap::Butt;
+
+ /**
+ * The geometry drawn at the corners of strokes.
+ */
+ LineJoin join = LineJoin::Miter;
+
+ /**
+ * The limit at which a sharp corner is drawn beveled.
+ */
+ float miterLimit = 4.0f;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/TextBlob.h b/include/tgfx/core/TextBlob.h
new file mode 100644
index 00000000..d79709e2
--- /dev/null
+++ b/include/tgfx/core/TextBlob.h
@@ -0,0 +1,57 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Font.h"
+#include "tgfx/core/Path.h"
+#include "tgfx/core/Stroke.h"
+
+namespace tgfx {
+/**
+ * TextBlob combines multiple glyphs, Font, and positions into an immutable container.
+ */
+class TextBlob {
+ public:
+ /**
+ * Creates a new TextBlob from the given glyphs, positions and text font.
+ */
+ static std::shared_ptr MakeFrom(const GlyphID glyphIDs[], const Point positions[],
+ size_t glyphCount, const Font& font);
+
+ virtual ~TextBlob() = default;
+
+ /**
+ * Returns true if this TextBlob has color glyphs, for example, color emojis.
+ */
+ virtual bool hasColor() const = 0;
+
+ /**
+ * Returns the bounds of the text blob's glyphs.
+ */
+ virtual Rect getBounds(const Stroke* stroke = nullptr) const = 0;
+
+ /**
+ * Creates a path corresponding to glyph shapes in the text blob. Copies the glyph fills to the
+ * path if the stroke is not passed in, otherwise copies the glyph outlines to the path. If text
+ * font is backed by bitmaps or cannot generate outlines, returns false and leaves the path
+ * unchanged.
+ */
+ virtual bool getPath(Path* path, const Stroke* stroke = nullptr) const = 0;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/TileMode.h b/include/tgfx/core/TileMode.h
new file mode 100644
index 00000000..59d05ee5
--- /dev/null
+++ b/include/tgfx/core/TileMode.h
@@ -0,0 +1,44 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+enum class TileMode {
+ /**
+ * Replicate the edge color if the shader draws outside of its original bounds.
+ */
+ Clamp,
+
+ /**
+ * Repeat the shader's image horizontally and vertically.
+ */
+ Repeat,
+
+ /**
+ * Repeat the shader's image horizontally and vertically, alternating mirror images so that
+ * adjacent images always seam.
+ */
+ Mirror,
+
+ /**
+ * Only draw within the original domain, return transparent-black everywhere else.
+ */
+ Decal
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/Typeface.h b/include/tgfx/core/Typeface.h
new file mode 100644
index 00000000..ed5c9fd3
--- /dev/null
+++ b/include/tgfx/core/Typeface.h
@@ -0,0 +1,154 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/core/Data.h"
+#include "tgfx/core/FontMetrics.h"
+#include "tgfx/core/ImageBuffer.h"
+#include "tgfx/core/Path.h"
+
+namespace tgfx {
+/**
+ * 16 bit unsigned integer to hold a glyph index
+ */
+typedef uint16_t GlyphID;
+
+typedef uint32_t FontTableTag;
+
+/**
+ * A set of character glyphs and layout information for drawing text.
+ */
+class Typeface {
+ public:
+ /**
+ * Returns the default typeface reference, which is never nullptr.
+ */
+ static std::shared_ptr MakeDefault();
+
+ /**
+ * Returns a typeface reference for the given font family and font style. If the family and
+ * style cannot be matched identically, a best match is found and returned, which is never
+ * nullptr.
+ */
+ static std::shared_ptr MakeFromName(const std::string& fontFamily,
+ const std::string& fontStyle);
+
+ /**
+ * Creates a new typeface for the given file path and ttc index. Returns nullptr if the typeface
+ * can't be created.
+ */
+ static std::shared_ptr MakeFromPath(const std::string& fontPath, int ttcIndex = 0);
+
+ /**
+ * Creates a new typeface for the given file bytes and ttc index. Returns nullptr if the typeface
+ * can't be created.
+ */
+ static std::shared_ptr MakeFromBytes(const void* data, size_t length, int ttcIndex = 0);
+
+ virtual ~Typeface() = default;
+
+ /**
+ * Returns the uniqueID for the specified typeface.
+ */
+ virtual uint32_t uniqueID() const = 0;
+
+ /**
+ * Returns the family name of this typeface.
+ */
+ virtual std::string fontFamily() const = 0;
+
+ /**
+ * Returns the style name of this typeface.
+ */
+ virtual std::string fontStyle() const = 0;
+
+ /**
+ * Return the number of glyphs in this typeface.
+ */
+ virtual int glyphsCount() const = 0;
+
+ /**
+ * Returns the number of glyph space units per em for this typeface.
+ */
+ virtual int unitsPerEm() const = 0;
+
+ /**
+ * Returns true if this typeface has color glyphs, for example, color emojis.
+ */
+ virtual bool hasColor() const = 0;
+
+ /**
+ * Returns the glyph ID corresponds to the specified glyph name. The glyph name must be in utf-8
+ * encoding. Returns 0 if the glyph name is not associated with this typeface.
+ */
+ virtual GlyphID getGlyphID(const std::string& name) const = 0;
+
+ virtual std::shared_ptr getBytes() const = 0;
+
+ /**
+ * Returns an immutable copy of the requested font table, or nullptr if that table was not found.
+ */
+ virtual std::shared_ptr copyTableData(FontTableTag tag) const = 0;
+
+ protected:
+ /**
+ * Returns the FontMetrics associated with this typeface.
+ */
+ virtual FontMetrics getMetrics(float size) const = 0;
+
+ /**
+ * Returns the bounding box of the specified glyph. The bounds is specified in glyph space
+ * units.
+ */
+ virtual Rect getBounds(GlyphID glyphID, float size, bool fauxBold,
+ bool fauxItalic) const = 0;
+
+ /**
+ * Returns the advance for specified glyph. The value is specified in glyph space units.
+ * @param glyphID The id of specified glyph.
+ * @param vertical The intended drawing orientation of the glyph.
+ */
+ virtual float getAdvance(GlyphID glyphID, float size, bool fauxBold, bool fauxItalic,
+ bool verticalText) const = 0;
+
+ /**
+ * Creates a path corresponding to glyph outline. If glyph has an outline, copies outline to path
+ * and returns true. If glyph is described by a bitmap, returns false and ignores path parameter.
+ * The points in path are specified in glyph space units.
+ */
+ virtual bool getPath(GlyphID glyphID, float size, bool fauxBold, bool fauxItalic,
+ Path* path) const = 0;
+
+ /**
+ * Creates an image buffer capturing the content of the specified glyph. The returned matrix
+ * should apply to the glyph image when drawing.
+ */
+ virtual std::shared_ptr getGlyphImage(GlyphID glyphID, float size, bool fauxBold,
+ bool fauxItalic, Matrix* matrix) const = 0;
+
+ /**
+ * Calculates the offset from the default (horizontal) origin to the vertical origin for specified
+ * glyph. The offset is specified in glyph space units.
+ */
+ virtual Point getVerticalOffset(GlyphID glyphID, float size, bool fauxBold,
+ bool fauxItalic) const = 0;
+
+ friend class Font;
+};
+} // namespace tgfx
diff --git a/include/tgfx/core/YUVColorSpace.h b/include/tgfx/core/YUVColorSpace.h
new file mode 100644
index 00000000..9ea381ad
--- /dev/null
+++ b/include/tgfx/core/YUVColorSpace.h
@@ -0,0 +1,62 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Describes color range of YUV pixels. The color mapping from YUV to RGB varies depending on the
+ * source. YUV pixels may be generated by JPEG images, standard video streams, or high-definition
+ * video streams. Each has its own mapping from YUV to RGB. JPEG YUV values encode the full range of
+ * 0 to 255 for all three components. Video YUV values often range from 16 to 235 for Y and from 16
+ * to 240 for U and V (limited). Details of encoding and conversion to RGB are described in YCbCr
+ * color space.
+ */
+enum class YUVColorSpace {
+ /**
+ * Describes SDTV limited range.
+ */
+ BT601_LIMITED,
+ /**
+ * Describes SDTV full range.
+ */
+ BT601_FULL,
+ /**
+ * Describes HDTV limited range.
+ */
+ BT709_LIMITED,
+ /**
+ * Describes HDTV full range.
+ */
+ BT709_FULL,
+ /**
+ * Describes UHDTV limited range.
+ */
+ BT2020_LIMITED,
+ /**
+ * Describes UHDTV full range.
+ */
+ BT2020_FULL,
+ /**
+ * Describes full range.
+ */
+ JPEG_FULL
+};
+
+bool IsLimitedYUVColorRange(YUVColorSpace colorSpace);
+} // namespace tgfx
diff --git a/include/tgfx/core/YUVData.h b/include/tgfx/core/YUVData.h
new file mode 100644
index 00000000..e891e47a
--- /dev/null
+++ b/include/tgfx/core/YUVData.h
@@ -0,0 +1,92 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+
+namespace tgfx {
+/**
+ * YUVData represents an array of yuv pixels located in the CPU memory. YUVData holds several planes
+ * of immutable buffers. Not only is the YUVData immutable, but the internal buffers are guaranteed
+ * to always be the same for the life of this instance.
+ */
+class YUVData {
+ public:
+ /**
+ * The number of planes required by the I420 format.
+ */
+ static constexpr size_t I420_PLANE_COUNT = 3;
+
+ /**
+ * The number of planes required by the NV12 format.
+ */
+ static constexpr size_t NV12_PLANE_COUNT = 2;
+
+ /**
+ * Function that, if provided, will be called when the YUVData goes out of scope, allowing for
+ * custom freeing of the YUVData's contents.
+ */
+ typedef void (*ReleaseProc)(void* context, const void** data, size_t planeCount);
+
+ /**
+ * Creates a YUVData object, taking ownership of the specified data, and using the releaseProc
+ * to free it. If the releaseProc is nullptr, the caller must ensure that data are valid for the
+ * lifetime of the returned YUVData.
+ * @param width The width of the yuv pixels
+ * @param height The height of the yuv pixels.
+ * @param data The array of base addresses for the planes.
+ * @param rowBytes The array of bytes-per-row values for the planes.
+ * @param planeCount The number of planes.
+ * @param releaseProc The callback function that gets called when the YUVData is destroyed.
+ * @param context A pointer to user data identifying the YUVData. This value is passed to your
+ * release callback function.
+ */
+ static std::shared_ptr MakeFrom(int width, int height, const void** data,
+ const size_t* rowBytes, size_t planeCount,
+ ReleaseProc releaseProc = nullptr,
+ void* context = nullptr);
+
+ virtual ~YUVData() = default;
+
+ /**
+ * Returns the width of the yuv pixels.
+ */
+ virtual int width() const = 0;
+
+ /**
+ * Returns the height of the yuv pixels.
+ */
+ virtual int height() const = 0;
+
+ /**
+ * Returns number of planes in this yuv data.
+ */
+ virtual size_t planeCount() const = 0;
+
+ /**
+ * Returns the base address of the plane at the specified plane index.
+ */
+ virtual const void* getBaseAddressAt(int planeIndex) const = 0;
+
+ /**
+ * Returns the number of bytes per row for a plane at the specified plane index.
+ */
+ virtual size_t getRowBytesAt(int planeIndex) const = 0;
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/Backend.h b/include/tgfx/gpu/Backend.h
new file mode 100644
index 00000000..527beac0
--- /dev/null
+++ b/include/tgfx/gpu/Backend.h
@@ -0,0 +1,212 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/metal/MtlTypes.h"
+#include "tgfx/opengl/GLTypes.h"
+
+namespace tgfx {
+/**
+ * Possible GPU backend APIs that may be used by TGFX.
+ */
+enum class Backend {
+ /**
+ * Mock is a backend that does not draw anything. It is used for unit tests and to measure CPU
+ * overhead.
+ */
+ MOCK,
+ OPENGL,
+ METAL,
+ VULKAN,
+};
+
+/**
+ * Wrapper class for passing into and receiving data from TGFX about a backend texture object.
+ */
+class BackendTexture {
+ public:
+ /**
+ * Creates an invalid backend texture.
+ */
+ BackendTexture() : _width(0), _height(0) {
+ }
+
+ /**
+ * Creates an OpenGL backend texture.
+ */
+ BackendTexture(const GLTextureInfo& glInfo, int width, int height);
+
+ /**
+ * Creates a Metal backend texture.
+ */
+ BackendTexture(const MtlTextureInfo& mtlInfo, int width, int height);
+
+ BackendTexture(const BackendTexture& that);
+
+ BackendTexture& operator=(const BackendTexture& that);
+
+ /**
+ * Returns true if the backend texture has been initialized.
+ */
+ bool isValid() const {
+ return _width > 0 && _height > 0;
+ }
+
+ /**
+ * Returns the width of the texture.
+ */
+ int width() const {
+ return _width;
+ }
+
+ /**
+ * Returns the height of the texture.
+ */
+ int height() const {
+ return _height;
+ }
+
+ /**
+ * Returns the backend API of this texture.
+ */
+ Backend backend() const {
+ return _backend;
+ }
+
+ /**
+ * If the backend API is GL, copies a snapshot of the GLTextureInfo struct into the passed in
+ * pointer and returns true. Otherwise, returns false if the backend API is not GL.
+ */
+ bool getGLTextureInfo(GLTextureInfo* glTextureInfo) const;
+
+ /**
+ * If the backend API is Metal, copies a snapshot of the GrMtlTextureInfo struct into the passed
+ * in pointer and returns true. Otherwise, returns false if the backend API is not Metal.
+ */
+ bool getMtlTextureInfo(MtlTextureInfo* mtlTextureInfo) const;
+
+ private:
+ Backend _backend = Backend::MOCK;
+ int _width = 0;
+ int _height = 0;
+
+ union {
+ GLTextureInfo glInfo;
+ MtlTextureInfo mtlInfo;
+ };
+};
+
+/**
+ * Wrapper class for passing into and receiving data from TGFX about a backend render target object.
+ */
+class BackendRenderTarget {
+ public:
+ /**
+ * Creates an invalid backend render target.
+ */
+ BackendRenderTarget() : _width(0), _height(0) {
+ }
+
+ /**
+ * Creates an OpenGL backend render target.
+ */
+ BackendRenderTarget(const GLFrameBufferInfo& glInfo, int width, int height);
+
+ /**
+ * Creates an Metal backend render target.
+ */
+ BackendRenderTarget(const MtlTextureInfo& mtlInfo, int width, int height);
+
+ BackendRenderTarget(const BackendRenderTarget& that);
+
+ BackendRenderTarget& operator=(const BackendRenderTarget&);
+
+ /**
+ * Returns true if the backend texture has been initialized.
+ */
+ bool isValid() const {
+ return _width > 0 && _height > 0;
+ }
+
+ /**
+ * Returns the width of this render target.
+ */
+ int width() const {
+ return _width;
+ }
+
+ /**
+ * Returns the height of this render target.
+ */
+ int height() const {
+ return _height;
+ }
+
+ /**
+ * Returns the backend API of this render target.
+ */
+ Backend backend() const {
+ return _backend;
+ }
+
+ /**
+ * If the backend API is GL, copies a snapshot of the GLFramebufferInfo struct into the passed
+ * in pointer and returns true. Otherwise, returns false if the backend API is not GL.
+ */
+ bool getGLFramebufferInfo(GLFrameBufferInfo* glFrameBufferInfo) const;
+
+ /**
+ * If the backend API is Metal, copies a snapshot of the MtlTextureInfo struct into the passed
+ * in pointer and returns true. Otherwise, returns false if the backend API is not Metal.
+ */
+ bool getMtlTextureInfo(MtlTextureInfo* mtlTextureInfo) const;
+
+ private:
+ Backend _backend = Backend::MOCK;
+ int _width = 0;
+ int _height = 0;
+ union {
+ GLFrameBufferInfo glInfo;
+ MtlTextureInfo mtlInfo;
+ };
+};
+
+/**
+ * Wrapper class for passing into and receiving data from TGFX about a backend semaphore object.
+ */
+class BackendSemaphore {
+ public:
+ BackendSemaphore();
+
+ bool isInitialized() const {
+ return _isInitialized;
+ }
+
+ void initGL(void* sync);
+
+ void* glSync() const;
+
+ private:
+ Backend _backend = Backend::MOCK;
+ union {
+ void* _glSync;
+ };
+ bool _isInitialized;
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/Caps.h b/include/tgfx/gpu/Caps.h
new file mode 100644
index 00000000..d74c4e22
--- /dev/null
+++ b/include/tgfx/gpu/Caps.h
@@ -0,0 +1,52 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/gpu/PixelFormat.h"
+
+namespace tgfx {
+class Swizzle;
+
+class Caps {
+ public:
+ virtual ~Caps() = default;
+
+ virtual const Swizzle& getWriteSwizzle(PixelFormat pixelFormat) const = 0;
+
+ virtual bool isFormatRenderable(PixelFormat pixelFormat) const = 0;
+
+ virtual int getSampleCount(int requestedCount, PixelFormat pixelFormat) const = 0;
+
+ virtual int getMaxMipmapLevel(int width, int height) const = 0;
+
+ bool floatIs32Bits = true;
+ int maxTextureSize = 0;
+ bool semaphoreSupport = false;
+ bool multisampleDisableSupport = false;
+ /**
+ * The CLAMP_TO_BORDER wrap mode for texture coordinates was added to desktop GL in 1.3, and
+ * GLES 3.2, but is also available in extensions. Vulkan and Metal always have support.
+ */
+ bool clampToBorderSupport = true;
+ bool npotTextureTileSupport = true; // Vulkan and Metal always have support.
+ bool mipMapSupport = true;
+ bool textureBarrierSupport = false;
+ bool frameBufferFetchSupport = false;
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/Context.h b/include/tgfx/gpu/Context.h
new file mode 100644
index 00000000..d145cdf3
--- /dev/null
+++ b/include/tgfx/gpu/Context.h
@@ -0,0 +1,195 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/utils/BytesKey.h"
+#include "tgfx/core/Color.h"
+#include "tgfx/gpu/Backend.h"
+#include "tgfx/gpu/Caps.h"
+#include "tgfx/gpu/Device.h"
+
+namespace tgfx {
+class ProgramCache;
+class ResourceCache;
+class DrawingManager;
+class Gpu;
+class ResourceProvider;
+class ProxyProvider;
+
+class Context {
+ public:
+ virtual ~Context();
+
+ /**
+ * Returns the associated device.
+ */
+ Device* device() const {
+ return _device;
+ }
+
+ /**
+ * Returns the associated cache that manages the lifetime of all Program instances.
+ */
+ ProgramCache* programCache() const {
+ return _programCache;
+ }
+
+ /**
+ * Returns the associated cache that manages the lifetime of all Resource instances.
+ */
+ ResourceCache* resourceCache() const {
+ return _resourceCache;
+ }
+
+ DrawingManager* drawingManager() const {
+ return _drawingManager;
+ }
+
+ ResourceProvider* resourceProvider() const {
+ return _resourceProvider;
+ }
+
+ ProxyProvider* proxyProvider() const {
+ return _proxyProvider;
+ }
+
+ /**
+ * Returns the number of bytes consumed by internal gpu caches.
+ */
+ size_t memoryUsage() const;
+
+ /**
+ * Returns the number of bytes held by purgeable resources.
+ */
+ size_t purgeableBytes() const;
+
+ /**
+ * Returns current cache limits of max gpu memory byte size.
+ */
+ size_t getCacheLimit() const;
+
+ /**
+ * Sets the cache limit of max gpu memory byte size.
+ */
+ void setCacheLimit(size_t bytesLimit);
+
+ /**
+ * Purges GPU resources that haven't been used the passed in time.
+ * @param purgeTime A timestamp previously returned by Clock::Now().
+ * @param scratchResourcesOnly If true, the purgeable resources containing unique keys are spared.
+ * If false, then all purgeable resources will be deleted.
+ */
+ void purgeResourcesNotUsedSince(int64_t purgeTime, bool scratchResourcesOnly = false);
+
+ /**
+ * Purge unreferenced resources from the cache until the provided bytesLimit has been reached, or
+ * we have purged all unreferenced resources. Returns true if the total resource bytes is not over
+ * the specified bytesLimit after purging.
+ * @param bytesLimit The desired number of bytes after puring.
+ * @param scratchResourcesOnly If true, the purgeable resources containing unique keys are spared.
+ * If false, then all purgeable resources will be deleted.
+ */
+ bool purgeResourcesUntilMemoryTo(size_t bytesLimit, bool scratchResourcesOnly = false);
+
+ /**
+ * Inserts a GPU semaphore that the current GPU-backed API must wait on before executing any more
+ * commands on the GPU for this surface. Surface will take ownership of the underlying semaphore
+ * and delete it once it has been signaled and waited on. If this call returns false, then the
+ * GPU back-end will not wait on the passed semaphore, and the client will still own the
+ * semaphore. Returns true if GPU is waiting on the semaphore.
+ */
+ bool wait(const BackendSemaphore& waitSemaphore);
+
+ /**
+ * Apply all pending changes to the render target immediately. After issuing all commands, the
+ * semaphore will be signaled by the GPU. If the signalSemaphore is not null and uninitialized,
+ * a new semaphore is created and initializes BackendSemaphore. The caller must delete the
+ * semaphore returned in signalSemaphore. BackendSemaphore can be deleted as soon as this function
+ * returns. If the back-end API is OpenGL, only uninitialized backend semaphores are supported.
+ * If false is returned, the GPU back-end did not create or add a semaphore to signal on the GPU;
+ * the caller should not instruct the GPU to wait on the semaphore.
+ */
+ bool flush(BackendSemaphore* signalSemaphore = nullptr);
+
+ /**
+ * Submit outstanding work to the gpu from all previously un-submitted flushes. The return
+ * value of the submit method will indicate whether the submission to the GPU was successful.
+ *
+ * If the call returns true, all previously passed in semaphores in flush calls will have been
+ * submitted to the GPU and they can safely be waited on. The caller should wait on those
+ * semaphores or perform some other global synchronization before deleting the semaphores.
+ *
+ * If it returns false, then those same semaphores will not have been submitted, and we will not
+ * try to submit them again. The caller is free to delete the semaphores at any time.
+ *
+ * If the syncCpu flag is true, this function will return once the gpu has finished with all
+ * submitted work.
+ */
+ bool submit(bool syncCpu = false);
+
+ /**
+ * Call to ensure all drawing to the context has been flushed and submitted to the underlying 3D
+ * API. This is equivalent to calling Context::flush() followed by Context::submit(syncCpu).
+ */
+ void flushAndSubmit(bool syncCpu = false);
+
+ /**
+ * Returns the GPU backend of this context.
+ */
+ virtual Backend backend() const = 0;
+
+ /**
+ * Returns the capability info of this context.
+ */
+ virtual const Caps* caps() const = 0;
+
+ /**
+ * The Context normally assumes that no outsider is setting state within the underlying GPU API's
+ * context/device/whatever. This call informs the context that the state was modified and it
+ * should resend. Shouldn't be called frequently for good performance.
+ */
+ virtual void resetState() = 0;
+
+ Gpu* gpu() {
+ return _gpu;
+ }
+
+ protected:
+ explicit Context(Device* device);
+
+ Gpu* _gpu = nullptr;
+
+ private:
+ Device* _device = nullptr;
+ ProgramCache* _programCache = nullptr;
+ ResourceCache* _resourceCache = nullptr;
+ DrawingManager* _drawingManager = nullptr;
+ ResourceProvider* _resourceProvider = nullptr;
+ ProxyProvider* _proxyProvider = nullptr;
+
+ void releaseAll(bool releaseGPU);
+ void onLocked();
+ void onUnlocked();
+
+ friend class Device;
+
+ friend class Resource;
+};
+
+} // namespace tgfx
diff --git a/include/tgfx/gpu/Device.h b/include/tgfx/gpu/Device.h
new file mode 100644
index 00000000..268ba86f
--- /dev/null
+++ b/include/tgfx/gpu/Device.h
@@ -0,0 +1,70 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/core/Matrix.h"
+
+namespace tgfx {
+class Context;
+/**
+ * The GPU interface for drawing graphics.
+ */
+class Device {
+ public:
+ virtual ~Device();
+
+ /**
+ * Returns a global unique ID for this device.
+ */
+ uint32_t uniqueID() const {
+ return _uniqueID;
+ }
+
+ /**
+ * Locks the rendering context associated with this device, if another thread has already locked
+ * the device by lockContext(), a call to lockContext() will block execution until the device
+ * is available. The returned context can be used to draw graphics. A nullptr is returned If the
+ * context can not be locked on the calling thread, and leaves the device unlocked.
+ */
+ Context* lockContext();
+
+ /**
+ * Unlocks the device. After this method is called all subsequent calls on the previously returned
+ * context will be invalid and may lead to runtime crash.
+ */
+ void unlock();
+
+ protected:
+ std::mutex locker = {};
+ Context* context = nullptr;
+ std::weak_ptr weakThis;
+
+ Device();
+ void releaseAll();
+ virtual bool onLockContext();
+ virtual void onUnlockContext();
+
+ private:
+ uint32_t _uniqueID = 0;
+ bool contextLocked = false;
+
+ friend class ResourceCache;
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/DoubleBufferedWindow.h b/include/tgfx/gpu/DoubleBufferedWindow.h
new file mode 100644
index 00000000..fddba2b0
--- /dev/null
+++ b/include/tgfx/gpu/DoubleBufferedWindow.h
@@ -0,0 +1,58 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include "tgfx/gpu/Window.h"
+
+namespace tgfx {
+class DoubleBufferedWindow : public Window {
+ public:
+ static std::shared_ptr Make(std::shared_ptr device,
+ const BackendTexture& frontBackendTexture,
+ const BackendTexture& backBackendTexture);
+
+ static std::shared_ptr Make(std::shared_ptr device,
+ HardwareBufferRef frontBuffer,
+ HardwareBufferRef backBuffer);
+
+ std::shared_ptr getBackSurface() const {
+ return backSurface;
+ }
+
+ virtual bool isFront(const BackendTexture&) const {
+ return false;
+ }
+
+ virtual bool isFront(HardwareBufferRef) const {
+ return false;
+ }
+
+ ~DoubleBufferedWindow() override;
+
+ protected:
+ explicit DoubleBufferedWindow(std::shared_ptr device);
+
+ void onPresent(Context* context, int64_t presentationTime) override;
+
+ virtual void onSwapSurfaces(Context*) = 0;
+
+ std::shared_ptr frontSurface;
+ std::shared_ptr backSurface;
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/ImageOrigin.h b/include/tgfx/gpu/ImageOrigin.h
new file mode 100644
index 00000000..780c271f
--- /dev/null
+++ b/include/tgfx/gpu/ImageOrigin.h
@@ -0,0 +1,41 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Textures and Surfaces can be stored such that (0, 0) in texture space may correspond to
+ * either the top-left or bottom-left content pixel.
+ */
+enum class ImageOrigin {
+ /**
+ * The default origin of the native coordinate system in the GPU backend. For example, the
+ * SurfaceOrigin::TopLeft is actually the bottom-left origin in the OpenGL coordinate system for
+ * textures. Textures newly created by the backend API for off-screen rendering usually have a
+ * SurfaceOrigin::TopLeft origin.
+ */
+ TopLeft,
+
+ /**
+ * Use this origin to flip the content on the y-axis if the GPU backend has a different origin to
+ * your system views. It is usually used for on-screen rendering.
+ */
+ BottomLeft
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/PixelFormat.h b/include/tgfx/gpu/PixelFormat.h
new file mode 100644
index 00000000..4702e32c
--- /dev/null
+++ b/include/tgfx/gpu/PixelFormat.h
@@ -0,0 +1,56 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+namespace tgfx {
+/**
+ * Describes the possible pixel formats of a TextureSampler.
+ */
+enum class PixelFormat {
+ /**
+ * uninitialized.
+ */
+ Unknown,
+
+ /**
+ * Pixel with 8 bits for alpha. Each pixel is stored on 1 byte.
+ */
+ ALPHA_8,
+
+ /**
+ * Pixel with 8 bits for grayscale. Each pixel is stored on 1 byte.
+ */
+ GRAY_8,
+
+ /**
+ * Pixel with 8 bits for red, green. Each pixel is stored on 2 bytes.
+ */
+ RG_88,
+
+ /**
+ * Pixel with 8 bits for red, green, blue, alpha. Each pixel is stored on 4 bytes.
+ */
+ RGBA_8888,
+
+ /**
+ * Pixel with 8 bits for blue, green, red, alpha. Each pixel is stored on 4 bytes.
+ */
+ BGRA_8888
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/Resource.h b/include/tgfx/gpu/Resource.h
new file mode 100644
index 00000000..69d5159c
--- /dev/null
+++ b/include/tgfx/gpu/Resource.h
@@ -0,0 +1,111 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include "tgfx/gpu/ResourceCache.h"
+#include "tgfx/gpu/ResourceKey.h"
+
+namespace tgfx {
+/**
+ * The base class for GPU resource. Overrides the onReleaseGPU() method to free all GPU resources.
+ * No backend API calls should be made during destructuring since there may be no GPU context which
+ * is current on the calling thread. Note: Resource is not thread safe, do not access any properties
+ * of a Resource unless its associated device is locked.
+ */
+class Resource {
+ public:
+ template
+ static std::shared_ptr Wrap(Context* context, T* resource) {
+ resource->context = context;
+ static_cast(resource)->computeScratchKey(&resource->scratchKey);
+ return std::static_pointer_cast(context->resourceCache()->addResource(resource));
+ }
+
+ virtual ~Resource() = default;
+
+ /**
+ * Retrieves the context associated with this Resource.
+ */
+ Context* getContext() const {
+ return context;
+ }
+
+ /**
+ * Retrieves the amount of GPU memory used by this resource in bytes.
+ */
+ virtual size_t memoryUsage() const = 0;
+
+ /**
+ * Assigns a UniqueKey to the resource. The resource will be findable via this UniqueKey using
+ * ResourceCache.findUniqueResource(). This method is not thread safe, call it only when the
+ * associated context is locked.
+ */
+ void assignUniqueKey(const UniqueKey& newKey);
+
+ /*
+ * Removes the UniqueKey from the resource. This method is not thread safe, call it only when
+ * the associated context is locked.
+ */
+ void removeUniqueKey();
+
+ /**
+ * Marks the associated UniqueKey as expired. This method is thread safe.
+ */
+ void markUniqueKeyExpired();
+
+ /**
+ * Returns true if the Resource has the same UniqueKey to the newKey and not expired. This method
+ * is thread safe.
+ */
+ bool hasUniqueKey(const UniqueKey& newKey) const;
+
+ protected:
+ Context* context = nullptr;
+
+ /**
+ * Overridden to compute a scratchKey to make this Resource reusable.
+ */
+ virtual void computeScratchKey(BytesKey*) const {
+ }
+
+ private:
+ std::weak_ptr weakThis;
+ ScratchKey scratchKey = {};
+ UniqueKey uniqueKey = {};
+ std::atomic_uint32_t uniqueKeyGeneration = 0;
+ std::list::iterator cachedPosition;
+ int64_t lastUsedTime = 0;
+
+ bool isPurgeable() const {
+ return weakThis.expired();
+ }
+
+ bool hasValidUniqueKey() const {
+ return !uniqueKey.empty() && !uniqueKey.unique() && uniqueKey.uniqueID() == uniqueKeyGeneration;
+ }
+
+ /**
+ * Overridden to free GPU resources in the backend API.
+ */
+ virtual void onReleaseGPU() = 0;
+
+ friend class ResourceCache;
+};
+} // namespace tgfx
diff --git a/include/tgfx/gpu/ResourceCache.h b/include/tgfx/gpu/ResourceCache.h
new file mode 100644
index 00000000..81706f7c
--- /dev/null
+++ b/include/tgfx/gpu/ResourceCache.h
@@ -0,0 +1,137 @@
+/////////////////////////////////////////////////////////////////////////////////////////////////
+//
+// Tencent is pleased to support the open source community by making tgfx available.
+//
+// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
+//
+// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// https://opensource.org/licenses/BSD-3-Clause
+//
+// unless required by applicable law or agreed to in writing, software distributed under the
+// license is distributed on an "as is" basis, without warranties or conditions of any kind,
+// either express or implied. see the license for the specific language governing permissions
+// and limitations under the license.
+//
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#pragma once
+
+#include
+#include
+#include
+#include "tgfx/gpu/Context.h"
+#include "tgfx/gpu/ResourceKey.h"
+
+namespace tgfx {
+class Resource;
+
+/**
+ * Manages the lifetime of all Resource instances.
+ */
+class ResourceCache {
+ public:
+ explicit ResourceCache(Context* context);
+
+ /**
+ * Returns true if there is no cache at all.
+ */
+ bool empty() const;
+
+ /**
+ * Returns the number of bytes consumed by resources.
+ */
+ size_t getResourceBytes() const {
+ return totalBytes;
+ }
+
+ /**
+ * Returns the number of bytes held by purgeable resources.
+ */
+ size_t getPurgeableBytes() const {
+ return purgeableBytes;
+ }
+
+ /**
+ * Returns current cache limits of max gpu memory byte size.
+ */
+ size_t getCacheLimit() const {
+ return maxBytes;
+ }
+
+ /**
+ * Sets the cache limits of max gpu memory byte size.
+ */
+ void setCacheLimit(size_t bytesLimit);
+
+ /**
+ * Returns a scratch resource in the cache by the specified ScratchKey.
+ */
+ std::shared_ptr findScratchResource(const ScratchKey& scratchKey);
+
+ /**
+ * Returns a unique resource in the cache by the specified UniqueKey.
+ */
+ std::shared_ptr findUniqueResource(const UniqueKey& uniqueKey);
+
+ /**
+ * Returns true if there is a corresponding unique resource for the specified UniqueKey.
+ */
+ bool hasUniqueResource(const UniqueKey& uniqueKey);
+
+ /**
+ * Purges GPU resources that haven't been used the passed in time.
+ * @param purgeTime A timestamp previously returned by Clock::Now().
+ * @param scratchResourcesOnly If true, the purgeable resources containing unique keys are spared.
+ * If false, then all purgeable resources will be deleted.
+ */
+ void purgeNotUsedSince(int64_t purgeTime, bool scratchResourcesOnly = false);
+
+ /**
+ * Purge unreferenced resources from the cache until the the provided bytesLimit has been reached
+ * or we have purged all unreferenced resources. Returns true if the total resource bytes is not
+ * over the specified bytesLimit after purging.
+ * @param bytesLimit The desired number of bytes after puring.
+ * @param scratchResourcesOnly If true, the purgeable resources containing unique keys are spared.
+ * If false, then all purgeable resources will be deleted.
+ */
+ bool purgeUntilMemoryTo(size_t bytesLimit, bool scratchResourcesOnly = false);
+
+ private:
+ Context* context = nullptr;
+ size_t maxBytes = 0;
+ size_t totalBytes = 0;
+ size_t purgeableBytes = 0;
+ bool purgingResource = false;
+ std::vector> strongReferences = {};
+ std::list nonpurgeableResources = {};
+ std::list purgeableResources = {};
+ ScratchKeyMap> scratchKeyMap = {};
+ std::unordered_map uniqueKeyMap = {};
+ std::mutex removeLocker = {};
+ std::vector pendingPurgeableResources = {};
+
+ static void AddToList(std::list& list, Resource* resource);
+ static void RemoveFromList(std::list& list, Resource* resource);
+ static void NotifyReferenceReachedZero(Resource* resource);
+
+ void attachToCurrentThread();
+ void detachFromCurrentThread();
+ void releaseAll(bool releaseGPU);
+ void processUnreferencedResource(Resource* resource);
+ std::shared_ptr wrapResource(Resource* resource);
+ std::shared_ptr addResource(Resource* resource);
+ void removeResource(Resource* resource);
+ void purgeResourcesByLRU(bool scratchResourcesOnly,
+ const std::function