Update to Harfbuzz 2.6.4
Quite a big change since it has been several years since the last update. This drops the Harfbuzz source on top of the existing code in Qt, and does the following additional changes: 1. Deletes old source files that have been removed upstream (everything named foo-private.hh is now renamed to just foo.hh for instance). 2. Added a header guard to config.h because it may be double-included. 3. Implement a memory barrier needed by hb-atomic.hh. 4. Changed the signature of hb_atomic_int_impl_add() to take a pointer to match new upstream. 5. Updated .pro file to include new files and removed old. 6. Updated qt_attribution.json 7. No longer disable deprecated APIs since hb_ot_tags_from_script() is now deprecated and is used from Qt code. 8. Updated and applied the patch in patches/ for CoreText. 9. Updated tst_qtextscriptengine::thaiWithZWJ() according to changes in Harfbuzz and disabled it for system-harfbuzz, since this may be an older version of harfbuzz depending on the system. Fixes: QTBUG-79606 Change-Id: I3f057a43ff44ee416628b75ef12fb1a221f31910 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Lars Knoll <lars.knoll@qt.io>bb10
parent
4724dfff62
commit
fb2f42b604
|
|
@ -7,59 +7,50 @@
|
|||
qt_add_3rdparty_library(BundledHarfbuzz
|
||||
STATIC
|
||||
SOURCES
|
||||
hb-dummy.cc
|
||||
src/hb.h
|
||||
src/hb-atomic-private.hh
|
||||
src/hb-aat-layout.cc
|
||||
src/hb-aat-map.cc
|
||||
src/hb-algs.hh
|
||||
src/hb-atomic.hh
|
||||
src/hb-blob.cc src/hb-blob.h
|
||||
src/hb-buffer.cc src/hb-buffer.h
|
||||
src/hb-buffer.cc src/hb-buffer.h src/hb-buffer.hh
|
||||
src/hb-buffer-deserialize-json.hh
|
||||
src/hb-buffer-deserialize-text.hh
|
||||
src/hb-buffer-private.hh
|
||||
src/hb-buffer-serialize.cc
|
||||
src/hb-cache-private.hh
|
||||
src/hb-common.cc src/hb-common.h
|
||||
src/hb-cache.hh
|
||||
src/hb-common.h
|
||||
src/hb-debug.hh
|
||||
src/hb-deprecated.h
|
||||
src/hb-dsalgs.hh
|
||||
src/hb-face.cc src/hb-face.h
|
||||
src/hb-face-private.hh
|
||||
src/hb-font.cc src/hb-font.h
|
||||
src/hb-font-private.hh
|
||||
src/hb-mutex-private.hh
|
||||
src/hb-object-private.hh
|
||||
src/hb-open-file-private.hh
|
||||
src/hb-open-type-private.hh
|
||||
src/hb-ot-cbdt-table.hh
|
||||
src/hb-ot-cmap-table.hh
|
||||
src/hb-ot-glyf-table.hh
|
||||
src/hb-ot-head-table.hh
|
||||
src/hb-ot-hhea-table.hh
|
||||
src/hb-ot-hmtx-table.hh
|
||||
src/hb-ot-maxp-table.hh
|
||||
src/hb-ot-name-table.hh
|
||||
src/hb-ot-os2-table.hh
|
||||
src/hb-ot-post-table.hh
|
||||
src/hb-ot-tag.cc
|
||||
src/hb-private.hh
|
||||
src/hb-set.cc src/hb-set.h
|
||||
src/hb-set-digest-private.hh
|
||||
src/hb-set-private.hh
|
||||
src/hb-face.cc src/hb-face.h src/hb-face.hh
|
||||
src/hb-fallback-shape.cc
|
||||
src/hb-font.cc src/hb-font.h src/hb-font.hh
|
||||
src/hb-map.cc
|
||||
src/hb-mutex.hh
|
||||
src/hb-number.cc
|
||||
src/hb-object.hh
|
||||
src/hb-open-file.hh
|
||||
src/hb-open-type.hh
|
||||
src/hb-set.cc src/hb-set.h src/hb-set.hh
|
||||
src/hb-set-digest.hh
|
||||
src/hb-shape.cc src/hb-shape.h
|
||||
src/hb-shape-plan.cc src/hb-shape-plan.h
|
||||
src/hb-shape-plan-private.hh
|
||||
src/hb-shaper.cc
|
||||
src/hb-shaper-impl-private.hh
|
||||
src/hb-shape-plan.cc src/hb-shape-plan.h src/hb-shape-plan.hh
|
||||
src/hb-shaper.cc src/hb-shaper.hh
|
||||
src/hb-shaper-impl.hh
|
||||
src/hb-shaper-list.hh
|
||||
src/hb-shaper-private.hh
|
||||
src/hb-string-array.hh
|
||||
src/hb-unicode.cc src/hb-unicode.h
|
||||
src/hb-unicode-private.hh
|
||||
src/hb-utf-private.hh
|
||||
src/hb-subset.cc
|
||||
src/hb-subset-cff-common.cc
|
||||
src/hb-subset-cff1.cc
|
||||
src/hb-subset-cff2.cc
|
||||
src/hb-subset-input.cc
|
||||
src/hb-subset-plan.cc
|
||||
src/hb-unicode.cc src/hb-unicode.h src/hb-unicode.hh
|
||||
src/hb-utf.hh
|
||||
src/hb-version.h
|
||||
src/hb-warning.cc
|
||||
DEFINES
|
||||
HAVE_ATEXIT
|
||||
HAVE_CONFIG_H
|
||||
HB_DISABLE_DEPRECATED
|
||||
HB_EXTERN=
|
||||
HB_NDEBUG
|
||||
HB_NO_UNICODE_FUNCS
|
||||
|
|
@ -73,6 +64,7 @@ qt_disable_warnings(BundledHarfbuzz)
|
|||
qt_set_symbol_visibility_hidden(BundledHarfbuzz)
|
||||
|
||||
#### Keys ignored in scope 1:.:.:harfbuzz-ng.pro:<TRUE>:
|
||||
# OTHER_FILES = "$$PWD/src/harfbuzz.cc"
|
||||
# SHAPERS = "opentype"
|
||||
|
||||
## Scopes:
|
||||
|
|
@ -108,49 +100,55 @@ qt_extend_target(BundledHarfbuzz CONDITION ANDROID
|
|||
qt_extend_target(BundledHarfbuzz CONDITION SHAPERS___contains___opentype
|
||||
SOURCES
|
||||
src/hb-ot.h
|
||||
src/hb-ot-cff1-table.cc
|
||||
src/hb-ot-cff2-table.cc
|
||||
src/hb-ot-cmap-table.hh
|
||||
src/hb-ot-color.cc
|
||||
src/hb-ot-color-cbdt-table.hh
|
||||
src/hb-ot-face.cc
|
||||
src/hb-ot-font.cc src/hb-ot-font.h
|
||||
src/hb-ot-glyf-table.hh
|
||||
src/hb-ot-head-table.hh
|
||||
src/hb-ot-hhea-table.hh
|
||||
src/hb-ot-hmtx-table.hh
|
||||
src/hb-ot-kern-table.hh
|
||||
src/hb-ot-layout.cc src/hb-ot-layout.h
|
||||
src/hb-ot-layout-common-private.hh
|
||||
src/hb-ot-layout.cc src/hb-ot-layout.h src/hb-ot-layout.hh
|
||||
src/hb-ot-layout-gdef-table.hh
|
||||
src/hb-ot-layout-gpos-table.hh
|
||||
src/hb-ot-layout-gsub-table.hh
|
||||
src/hb-ot-layout-gsubgpos-private.hh
|
||||
src/hb-ot-layout-jstf-table.hh
|
||||
src/hb-ot-layout-math-table.hh
|
||||
src/hb-ot-layout-private.hh
|
||||
src/hb-ot-map.cc
|
||||
src/hb-ot-map-private.hh
|
||||
src/hb-ot-map.cc src/hb-ot-map.hh
|
||||
src/hb-ot-math.cc src/hb-ot-math.h
|
||||
src/hb-ot-math-table.hh
|
||||
src/hb-ot-maxp-table.hh
|
||||
src/hb-ot-meta.cc
|
||||
src/hb-ot-metrics.cc
|
||||
src/hb-ot-name.cc
|
||||
src/hb-ot-name-table.hh
|
||||
src/hb-ot-os2-table.hh
|
||||
src/hb-ot-post-macroman.hh
|
||||
src/hb-ot-shape.cc src/hb-ot-shape.h
|
||||
src/hb-ot-shape-complex-arabic.cc
|
||||
src/hb-ot-post-table.hh
|
||||
src/hb-ot-shape.cc src/hb-ot-shape.h src/hb-ot-shape.hh
|
||||
src/hb-ot-shape-complex-arabic.cc src/hb-ot-shape-complex-arabic.hh
|
||||
src/hb-ot-shape-complex-arabic-fallback.hh
|
||||
src/hb-ot-shape-complex-arabic-private.hh
|
||||
src/hb-ot-shape-complex-arabic-table.hh
|
||||
src/hb-ot-shape-complex-default.cc
|
||||
src/hb-ot-shape-complex-hangul.cc
|
||||
src/hb-ot-shape-complex-hebrew.cc
|
||||
src/hb-ot-shape-complex-indic.cc
|
||||
src/hb-ot-shape-complex-indic.cc src/hb-ot-shape-complex-indic.hh
|
||||
src/hb-ot-shape-complex-indic-machine.hh
|
||||
src/hb-ot-shape-complex-indic-private.hh
|
||||
src/hb-ot-shape-complex-indic-table.cc
|
||||
src/hb-ot-shape-complex-khmer.cc
|
||||
src/hb-ot-shape-complex-myanmar.cc
|
||||
src/hb-ot-shape-complex-myanmar-machine.hh
|
||||
src/hb-ot-shape-complex-private.hh
|
||||
src/hb-ot-shape-complex-thai.cc
|
||||
src/hb-ot-shape-complex-tibetan.cc
|
||||
src/hb-ot-shape-complex-use.cc
|
||||
src/hb-ot-shape-complex-use.cc src/hb-ot-shape-complex-use.hh
|
||||
src/hb-ot-shape-complex-use-machine.hh
|
||||
src/hb-ot-shape-complex-use-private.hh
|
||||
src/hb-ot-shape-complex-use-table.cc
|
||||
src/hb-ot-shape-fallback.cc
|
||||
src/hb-ot-shape-fallback-private.hh
|
||||
src/hb-ot-shape-normalize.cc
|
||||
src/hb-ot-shape-normalize-private.hh
|
||||
src/hb-ot-shape-private.hh
|
||||
src/hb-ot-tag.h
|
||||
src/hb-ot-shape-complex-vowel-constraints.cc
|
||||
src/hb-ot-shape-fallback.cc src/hb-ot-shape-fallback.hh
|
||||
src/hb-ot-shape-normalize.cc src/hb-ot-shape-normalize.hh
|
||||
src/hb-ot-tag.cc
|
||||
src/hb-ot-var.cc src/hb-ot-var.h
|
||||
src/hb-ot-var-avar-table.hh
|
||||
src/hb-ot-var-fvar-table.hh
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
Behdad Esfahbod
|
||||
Simon Hausmann
|
||||
Martin Hosken
|
||||
Jonathan Kew
|
||||
Lars Knoll
|
||||
Werner Lemberg
|
||||
Roozbeh Pournader
|
||||
Owen Taylor
|
||||
David Corbett
|
||||
David Turner
|
||||
Ebrahim Byagowi
|
||||
Garret Rieger
|
||||
Jonathan Kew
|
||||
Khaled Hosny
|
||||
Lars Knoll
|
||||
Martin Hosken
|
||||
Owen Taylor
|
||||
Roderick Sheeter
|
||||
Roozbeh Pournader
|
||||
Simon Hausmann
|
||||
Werner Lemberg
|
||||
|
|
|
|||
|
|
@ -7,59 +7,50 @@
|
|||
qt_add_3rdparty_library(BundledHarfbuzz
|
||||
STATIC
|
||||
SOURCES
|
||||
hb-dummy.cc
|
||||
src/hb.h
|
||||
src/hb-atomic-private.hh
|
||||
src/hb-aat-layout.cc
|
||||
src/hb-aat-map.cc
|
||||
src/hb-algs.hh
|
||||
src/hb-atomic.hh
|
||||
src/hb-blob.cc src/hb-blob.h
|
||||
src/hb-buffer.cc src/hb-buffer.h
|
||||
src/hb-buffer.cc src/hb-buffer.h src/hb-buffer.hh
|
||||
src/hb-buffer-deserialize-json.hh
|
||||
src/hb-buffer-deserialize-text.hh
|
||||
src/hb-buffer-private.hh
|
||||
src/hb-buffer-serialize.cc
|
||||
src/hb-cache-private.hh
|
||||
src/hb-common.cc src/hb-common.h
|
||||
src/hb-cache.hh
|
||||
src/hb-common.h
|
||||
src/hb-debug.hh
|
||||
src/hb-deprecated.h
|
||||
src/hb-dsalgs.hh
|
||||
src/hb-face.cc src/hb-face.h
|
||||
src/hb-face-private.hh
|
||||
src/hb-font.cc src/hb-font.h
|
||||
src/hb-font-private.hh
|
||||
src/hb-mutex-private.hh
|
||||
src/hb-object-private.hh
|
||||
src/hb-open-file-private.hh
|
||||
src/hb-open-type-private.hh
|
||||
src/hb-ot-cbdt-table.hh
|
||||
src/hb-ot-cmap-table.hh
|
||||
src/hb-ot-glyf-table.hh
|
||||
src/hb-ot-head-table.hh
|
||||
src/hb-ot-hhea-table.hh
|
||||
src/hb-ot-hmtx-table.hh
|
||||
src/hb-ot-maxp-table.hh
|
||||
src/hb-ot-name-table.hh
|
||||
src/hb-ot-os2-table.hh
|
||||
src/hb-ot-post-table.hh
|
||||
src/hb-ot-tag.cc
|
||||
src/hb-private.hh
|
||||
src/hb-set.cc src/hb-set.h
|
||||
src/hb-set-digest-private.hh
|
||||
src/hb-set-private.hh
|
||||
src/hb-face.cc src/hb-face.h src/hb-face.hh
|
||||
src/hb-fallback-shape.cc
|
||||
src/hb-font.cc src/hb-font.h src/hb-font.hh
|
||||
src/hb-map.cc
|
||||
src/hb-mutex.hh
|
||||
src/hb-number.cc
|
||||
src/hb-object.hh
|
||||
src/hb-open-file.hh
|
||||
src/hb-open-type.hh
|
||||
src/hb-set.cc src/hb-set.h src/hb-set.hh
|
||||
src/hb-set-digest.hh
|
||||
src/hb-shape.cc src/hb-shape.h
|
||||
src/hb-shape-plan.cc src/hb-shape-plan.h
|
||||
src/hb-shape-plan-private.hh
|
||||
src/hb-shaper.cc
|
||||
src/hb-shaper-impl-private.hh
|
||||
src/hb-shape-plan.cc src/hb-shape-plan.h src/hb-shape-plan.hh
|
||||
src/hb-shaper.cc src/hb-shaper.hh
|
||||
src/hb-shaper-impl.hh
|
||||
src/hb-shaper-list.hh
|
||||
src/hb-shaper-private.hh
|
||||
src/hb-string-array.hh
|
||||
src/hb-unicode.cc src/hb-unicode.h
|
||||
src/hb-unicode-private.hh
|
||||
src/hb-utf-private.hh
|
||||
src/hb-subset.cc
|
||||
src/hb-subset-cff-common.cc
|
||||
src/hb-subset-cff1.cc
|
||||
src/hb-subset-cff2.cc
|
||||
src/hb-subset-input.cc
|
||||
src/hb-subset-plan.cc
|
||||
src/hb-unicode.cc src/hb-unicode.h src/hb-unicode.hh
|
||||
src/hb-utf.hh
|
||||
src/hb-version.h
|
||||
src/hb-warning.cc
|
||||
DEFINES
|
||||
HAVE_ATEXIT
|
||||
HAVE_CONFIG_H
|
||||
HB_DISABLE_DEPRECATED
|
||||
HB_EXTERN=
|
||||
HB_NDEBUG
|
||||
HB_NO_UNICODE_FUNCS
|
||||
|
|
@ -74,6 +65,7 @@ qt_disable_warnings(BundledHarfbuzz)
|
|||
qt_set_symbol_visibility_hidden(BundledHarfbuzz)
|
||||
|
||||
#### Keys ignored in scope 1:.:.:harfbuzz-ng.pro:<TRUE>:
|
||||
# OTHER_FILES = "$$PWD/src/harfbuzz.cc"
|
||||
# SHAPERS = "opentype"
|
||||
|
||||
## Scopes:
|
||||
|
|
@ -109,49 +101,55 @@ qt_extend_target(BundledHarfbuzz CONDITION ANDROID
|
|||
qt_extend_target(BundledHarfbuzz CONDITION TRUE # special case
|
||||
SOURCES
|
||||
src/hb-ot.h
|
||||
src/hb-ot-cff1-table.cc
|
||||
src/hb-ot-cff2-table.cc
|
||||
src/hb-ot-cmap-table.hh
|
||||
src/hb-ot-color.cc
|
||||
src/hb-ot-color-cbdt-table.hh
|
||||
src/hb-ot-face.cc
|
||||
src/hb-ot-font.cc src/hb-ot-font.h
|
||||
src/hb-ot-glyf-table.hh
|
||||
src/hb-ot-head-table.hh
|
||||
src/hb-ot-hhea-table.hh
|
||||
src/hb-ot-hmtx-table.hh
|
||||
src/hb-ot-kern-table.hh
|
||||
src/hb-ot-layout.cc src/hb-ot-layout.h
|
||||
src/hb-ot-layout-common-private.hh
|
||||
src/hb-ot-layout.cc src/hb-ot-layout.h src/hb-ot-layout.hh
|
||||
src/hb-ot-layout-gdef-table.hh
|
||||
src/hb-ot-layout-gpos-table.hh
|
||||
src/hb-ot-layout-gsub-table.hh
|
||||
src/hb-ot-layout-gsubgpos-private.hh
|
||||
src/hb-ot-layout-jstf-table.hh
|
||||
src/hb-ot-layout-math-table.hh
|
||||
src/hb-ot-layout-private.hh
|
||||
src/hb-ot-map.cc
|
||||
src/hb-ot-map-private.hh
|
||||
src/hb-ot-map.cc src/hb-ot-map.hh
|
||||
src/hb-ot-math.cc src/hb-ot-math.h
|
||||
src/hb-ot-math-table.hh
|
||||
src/hb-ot-maxp-table.hh
|
||||
src/hb-ot-meta.cc
|
||||
src/hb-ot-metrics.cc
|
||||
src/hb-ot-name.cc
|
||||
src/hb-ot-name-table.hh
|
||||
src/hb-ot-os2-table.hh
|
||||
src/hb-ot-post-macroman.hh
|
||||
src/hb-ot-shape.cc src/hb-ot-shape.h
|
||||
src/hb-ot-shape-complex-arabic.cc
|
||||
src/hb-ot-post-table.hh
|
||||
src/hb-ot-shape.cc src/hb-ot-shape.h src/hb-ot-shape.hh
|
||||
src/hb-ot-shape-complex-arabic.cc src/hb-ot-shape-complex-arabic.hh
|
||||
src/hb-ot-shape-complex-arabic-fallback.hh
|
||||
src/hb-ot-shape-complex-arabic-private.hh
|
||||
src/hb-ot-shape-complex-arabic-table.hh
|
||||
src/hb-ot-shape-complex-default.cc
|
||||
src/hb-ot-shape-complex-hangul.cc
|
||||
src/hb-ot-shape-complex-hebrew.cc
|
||||
src/hb-ot-shape-complex-indic.cc
|
||||
src/hb-ot-shape-complex-indic.cc src/hb-ot-shape-complex-indic.hh
|
||||
src/hb-ot-shape-complex-indic-machine.hh
|
||||
src/hb-ot-shape-complex-indic-private.hh
|
||||
src/hb-ot-shape-complex-indic-table.cc
|
||||
src/hb-ot-shape-complex-khmer.cc
|
||||
src/hb-ot-shape-complex-myanmar.cc
|
||||
src/hb-ot-shape-complex-myanmar-machine.hh
|
||||
src/hb-ot-shape-complex-private.hh
|
||||
src/hb-ot-shape-complex-thai.cc
|
||||
src/hb-ot-shape-complex-tibetan.cc
|
||||
src/hb-ot-shape-complex-use.cc
|
||||
src/hb-ot-shape-complex-use.cc src/hb-ot-shape-complex-use.hh
|
||||
src/hb-ot-shape-complex-use-machine.hh
|
||||
src/hb-ot-shape-complex-use-private.hh
|
||||
src/hb-ot-shape-complex-use-table.cc
|
||||
src/hb-ot-shape-fallback.cc
|
||||
src/hb-ot-shape-fallback-private.hh
|
||||
src/hb-ot-shape-normalize.cc
|
||||
src/hb-ot-shape-normalize-private.hh
|
||||
src/hb-ot-shape-private.hh
|
||||
src/hb-ot-tag.h
|
||||
src/hb-ot-shape-complex-vowel-constraints.cc
|
||||
src/hb-ot-shape-fallback.cc src/hb-ot-shape-fallback.hh
|
||||
src/hb-ot-shape-normalize.cc src/hb-ot-shape-normalize.hh
|
||||
src/hb-ot-tag.cc
|
||||
src/hb-ot-var.cc src/hb-ot-var.h
|
||||
src/hb-ot-var-avar-table.hh
|
||||
src/hb-ot-var-fvar-table.hh
|
||||
|
|
@ -177,4 +175,4 @@ qt_extend_target(BundledHarfbuzz CONDITION SHAPERS_ISEMPTY OR SHAPERS___contains
|
|||
src/hb-fallback-shape.cc
|
||||
DEFINES
|
||||
HAVE_FALLBACK
|
||||
)
|
||||
)
|
||||
|
|
@ -2,7 +2,8 @@ HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
|||
For parts of HarfBuzz that are licensed under different licenses see individual
|
||||
files names COPYING in subdirectories where applicable.
|
||||
|
||||
Copyright © 2010,2011,2012 Google, Inc.
|
||||
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Google, Inc.
|
||||
Copyright © 2019 Facebook, Inc.
|
||||
Copyright © 2012 Mozilla Foundation
|
||||
Copyright © 2011 Codethink Limited
|
||||
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,526 @@
|
|||
Overview of changes leading to 2.6.4
|
||||
Monday, October 29, 2019
|
||||
====================================
|
||||
- Small bug fix.
|
||||
- Build fixes.
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.3
|
||||
Monday, October 28, 2019
|
||||
====================================
|
||||
- Misc small fixes, mostly to build-related issues.
|
||||
- New API:
|
||||
+hb_font_get_nominal_glyphs()
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.2
|
||||
Monday, September 30, 2019
|
||||
====================================
|
||||
- Misc small fixes, mostly to build-related issues.
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.1
|
||||
Thursday, August 22, 2019
|
||||
====================================
|
||||
- Fix regression with hb_font_create_sub_font scaling introduced in 2.6.0.
|
||||
- Change interpretation of font PTEM size / CoreText font size handling.
|
||||
See https://github.com/harfbuzz/harfbuzz/pull/1484
|
||||
- hb-ot-font: Prefer symbol cmap subtable if present.
|
||||
- Apply 'dist'/'abvm'/'blwm' features to all scripts.
|
||||
- Drop experimental DirectWrite API.
|
||||
|
||||
|
||||
Overview of changes leading to 2.6.0
|
||||
Tuesday, August 13, 2019
|
||||
====================================
|
||||
- New OpenType metrics, baseline, and metadata table access APIs.
|
||||
- New API to set font variations to a named-instance.
|
||||
- New hb-gdi.h header and API for creating hb_face_t from HFONT.
|
||||
- Amalgam: Provide a single-file harfbuzz.cc file for easier alternate building.
|
||||
- More size-reduction configurable options, enabled by HB_TINY.
|
||||
- New API:
|
||||
+hb_font_set_var_named_instance()
|
||||
+hb_gdi_face_create()
|
||||
+hb_ot_layout_baseline_tag_t
|
||||
+hb_ot_layout_get_baseline()
|
||||
+hb_ot_meta_tag_t
|
||||
+hb_ot_meta_get_entry_tags()
|
||||
+hb_ot_meta_reference_entry()
|
||||
+hb_ot_metrics_tag_t
|
||||
+hb_ot_metrics_get_position()
|
||||
+hb_ot_metrics_get_variation()
|
||||
+hb_ot_metrics_get_x_variation()
|
||||
+hb_ot_metrics_get_y_variation()
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.3
|
||||
Wednesday, June 26, 2019
|
||||
====================================
|
||||
- Fix UCD script data for Unicode 10+ scripts. This was broken since 2.5.0.
|
||||
- More optimizations for HB_TINY.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.2
|
||||
Thursday, June 20, 2019
|
||||
====================================
|
||||
- More hb-config.hh facilities to shrink library size, namely when built as
|
||||
HB_TINY.
|
||||
- New documentation of custom configurations in CONFIG.md.
|
||||
- Fix build on gcc 4.8. That's supported again.
|
||||
- Universal Shaping Engine improvements thanks to David Corbett.
|
||||
- API Changes: Undeprecate some horizontal-kerning API and re-enable in hb-ft,
|
||||
such that Type1 fonts will continue kerning.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.1
|
||||
Friday, May 31, 2019
|
||||
====================================
|
||||
- Fix build with various versions of Visual Studio.
|
||||
- Improved documentation, thanks to Nathan Willis.
|
||||
- Bugfix in subsetting glyf table.
|
||||
- Improved scripts for cross-compiling for Windows using mingw.
|
||||
- Rename HB_MATH_GLYPH_PART_FLAG_EXTENDER to HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER.
|
||||
A deprecated macro is added for backwards-compatibility.
|
||||
|
||||
|
||||
Overview of changes leading to 2.5.0
|
||||
Friday, May 24, 2019
|
||||
====================================
|
||||
- This release does not include much functional changes, but includes major internal
|
||||
code-base changes. We now require C++11. Support for gcc 4.8 and earlier has been
|
||||
dropped.
|
||||
- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
|
||||
- New Unicode Character Databse implementation that is half the size of previously-used
|
||||
UCDN.
|
||||
- Subsetter improvements.
|
||||
- Improved documentation, thanks to Nathan Willis.
|
||||
- Misc shaping fixes.
|
||||
|
||||
|
||||
Overview of changes leading to 2.4.0
|
||||
Monday, March 25, 2019
|
||||
====================================
|
||||
- Unicode 12.
|
||||
- Misc fixes.
|
||||
- Subsetter improvements.
|
||||
- New API:
|
||||
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE
|
||||
hb_directwrite_face_create()
|
||||
|
||||
|
||||
Overview of changes leading to 2.3.1
|
||||
Wednesday, January 30, 2019
|
||||
====================================
|
||||
- AAT bug fixes.
|
||||
- Misc internal housekeeping cleanup.
|
||||
|
||||
|
||||
Overview of changes leading to 2.3.0
|
||||
Thursday, December 20, 2018
|
||||
====================================
|
||||
- Fix regression on big-endian architectures. Ouch!
|
||||
- Misc bug and build fixes.
|
||||
- Fix subsetting of simple GSUB/GDEF.
|
||||
- Merge CFF / CFF2 support contributed by Adobe. This mostly involves
|
||||
the subsetter, but also get_glyph_extents on CFF fonts.
|
||||
|
||||
New API in hb-aat.h:
|
||||
+hb_aat_layout_has_substitution()
|
||||
+hb_aat_layout_has_positioning()
|
||||
+hb_aat_layout_has_tracking()
|
||||
|
||||
|
||||
Overview of changes leading to 2.2.0
|
||||
Thursday, November 29, 2018
|
||||
====================================
|
||||
- Misc shaping bug fixes.
|
||||
- Add font variations named-instance API.
|
||||
- Deprecate font variations axis enumeration API and add replacement.
|
||||
- AAT shaping improvements:
|
||||
o Fixed 'kern' table Format 2 implementation.
|
||||
o Implement 'feat' table API for feature detection.
|
||||
o Blacklist 'GSUB' table of fonts from 'MUTF' foundry that also have 'morx'.
|
||||
|
||||
New API:
|
||||
+hb_aat_layout_feature_type_t
|
||||
+hb_aat_layout_feature_selector_t
|
||||
+hb_aat_layout_get_feature_types()
|
||||
+hb_aat_layout_feature_type_get_name_id
|
||||
+hb_aat_layout_feature_selector_info_t
|
||||
+HB_AAT_LAYOUT_NO_SELECTOR_INDEX
|
||||
+hb_aat_layout_feature_type_get_selector_infos()
|
||||
+hb_ot_var_axis_flags_t
|
||||
+hb_ot_var_axis_info_t
|
||||
+hb_ot_var_get_axis_infos()
|
||||
+hb_ot_var_find_axis_info()
|
||||
+hb_ot_var_get_named_instance_count()
|
||||
+hb_ot_var_named_instance_get_subfamily_name_id()
|
||||
+hb_ot_var_named_instance_get_postscript_name_id()
|
||||
+hb_ot_var_named_instance_get_design_coords()
|
||||
|
||||
Deprecated API:
|
||||
+HB_OT_VAR_NO_AXIS_INDEX
|
||||
+hb_ot_var_axis_t
|
||||
+hb_ot_var_get_axes()
|
||||
+hb_ot_var_find_axis()
|
||||
|
||||
|
||||
Overview of changes leading to 2.1.3
|
||||
Friday, November 16, 2018
|
||||
====================================
|
||||
- Fix AAT 'mort' shaping, which was broken in 2.1.2
|
||||
|
||||
|
||||
Overview of changes leading to 2.1.2
|
||||
Friday, November 16, 2018
|
||||
====================================
|
||||
- Various internal changes.
|
||||
- AAT shaping improvements:
|
||||
o Implement kern table Format 1 state-machine-based kerning.
|
||||
o Implement cross-stream kerning (cursive positioning, etc).
|
||||
o Ignore emptyish GSUB tables (zero scripts) if morx present.
|
||||
o Don't apply GPOS if morx is being applied. Matches Apple.
|
||||
|
||||
|
||||
-Overview of changes leading to 2.1.1
|
||||
Monday, November 5, 2018
|
||||
====================================
|
||||
- AAT improvements:
|
||||
o Implement 'mort' table.
|
||||
o Implement 'kern' subtables Format 1 and Format 3.
|
||||
|
||||
|
||||
Overview of changes leading to 2.1.0
|
||||
Tuesday, October 30, 2018
|
||||
====================================
|
||||
- AAT shaping improvements:
|
||||
o Allow user controlling AAT features, for whole buffer only currently.
|
||||
o Several 'morx' fixes.
|
||||
o Implement tuple-kerns in 'kerx'; Fixes kerning with Apple default
|
||||
San Francisco fonts.
|
||||
- Support for color fonts:
|
||||
o COLR/CPAL API to fetch color layers.
|
||||
o SVG table to fetch SVG documents.
|
||||
o CBDT/sbix API to fetch PNG images.
|
||||
- New 'name' table API.
|
||||
- hb-ot-font now uses 'VORG' table to correctly position CFF glyphs
|
||||
in vertical layout.
|
||||
- Various fuzzer-found bug fixes.
|
||||
|
||||
Changed API:
|
||||
|
||||
A type and a macro added in 2.0.0 were renamed:
|
||||
|
||||
hb_name_id_t -> hb_ot_name_id_t
|
||||
HB_NAME_ID_INVALID -> HB_OT_NAME_ID_INVALID
|
||||
|
||||
New API:
|
||||
|
||||
+hb_color_t
|
||||
+HB_COLOR
|
||||
+hb_color_get_alpha()
|
||||
+hb_color_get_red()
|
||||
+hb_color_get_green()
|
||||
+hb_color_get_blue()
|
||||
+hb_ot_color_has_palettes()
|
||||
+hb_ot_color_palette_get_count()
|
||||
+hb_ot_color_palette_get_name_id()
|
||||
+hb_ot_color_palette_color_get_name_id()
|
||||
+hb_ot_color_palette_flags_t
|
||||
+hb_ot_color_palette_get_flags()
|
||||
+hb_ot_color_palette_get_colors()
|
||||
+hb_ot_color_has_layers()
|
||||
+hb_ot_color_layer_t
|
||||
+hb_ot_color_glyph_get_layers()
|
||||
+hb_ot_color_has_svg()
|
||||
+hb_ot_color_glyph_reference_svg()
|
||||
+hb_ot_color_has_png()
|
||||
+hb_ot_color_glyph_reference_png()
|
||||
|
||||
+hb_ot_name_id_t
|
||||
+HB_OT_NAME_ID_INVALID
|
||||
+HB_OT_NAME_ID_COPYRIGHT
|
||||
+HB_OT_NAME_ID_FONT_FAMILY
|
||||
+HB_OT_NAME_ID_FONT_SUBFAMILY
|
||||
+HB_OT_NAME_ID_UNIQUE_ID
|
||||
+HB_OT_NAME_ID_FULL_NAME
|
||||
+HB_OT_NAME_ID_VERSION_STRING
|
||||
+HB_OT_NAME_ID_POSTSCRIPT_NAME
|
||||
+HB_OT_NAME_ID_TRADEMARK
|
||||
+HB_OT_NAME_ID_MANUFACTURER
|
||||
+HB_OT_NAME_ID_DESIGNER
|
||||
+HB_OT_NAME_ID_DESCRIPTION
|
||||
+HB_OT_NAME_ID_VENDOR_URL
|
||||
+HB_OT_NAME_ID_DESIGNER_URL
|
||||
+HB_OT_NAME_ID_LICENSE
|
||||
+HB_OT_NAME_ID_LICENSE_URL
|
||||
+HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY
|
||||
+HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY
|
||||
+HB_OT_NAME_ID_MAC_FULL_NAME
|
||||
+HB_OT_NAME_ID_SAMPLE_TEXT
|
||||
+HB_OT_NAME_ID_CID_FINDFONT_NAME
|
||||
+HB_OT_NAME_ID_WWS_FAMILY
|
||||
+HB_OT_NAME_ID_WWS_SUBFAMILY
|
||||
+HB_OT_NAME_ID_LIGHT_BACKGROUND
|
||||
+HB_OT_NAME_ID_DARK_BACKGROUND
|
||||
+HB_OT_NAME_ID_VARIATIONS_PS_PREFIX
|
||||
+hb_ot_name_entry_t
|
||||
+hb_ot_name_list_names()
|
||||
+hb_ot_name_get_utf8()
|
||||
+hb_ot_name_get_utf16()
|
||||
+hb_ot_name_get_utf32()
|
||||
|
||||
|
||||
Overview of changes leading to 2.0.2
|
||||
Saturday, October 20, 2018
|
||||
====================================
|
||||
- Fix two minor memory access issues in AAT tables.
|
||||
|
||||
|
||||
Overview of changes leading to 2.0.1
|
||||
Friday, October 19, 2018
|
||||
====================================
|
||||
- Fix hb-version.h reported release version that went wrong (1.8.0)
|
||||
with previous release.
|
||||
- Fix extrapolation in 'trak' table.
|
||||
- Fix hb-font infinite-recursion issue with some font funcs and
|
||||
subclassed fonts.
|
||||
- Implement variation-kerning format in kerx table, although without
|
||||
variation.
|
||||
- Fix return value of hb_map_is_empty().
|
||||
|
||||
|
||||
Overview of changes leading to 2.0.0
|
||||
Thursday, October 18, 2018
|
||||
====================================
|
||||
- Added AAT shaping support (morx/kerx/trak).
|
||||
Automatically used if GSUB/GPOS are not available respectively.
|
||||
Set HB_OPTIONS=aat env var to have morx/kerx preferred over
|
||||
GSUB/GPOS.
|
||||
- Apply TrueType kern table internally, instead of relying on
|
||||
hb_font_t callbacks.
|
||||
- Khmer shaper significantly rewritten to better match Uniscribe.
|
||||
- Indic3 tags ('dev3', etc) are passed to USE shaper.
|
||||
- .dfont Mac font containers implemented.
|
||||
- Script- and language-mapping revamped to better use BCP 47.
|
||||
- Misc USE and Indic fixes.
|
||||
- Misc everything fixes.
|
||||
- Too many things to list. Biggest release since 0.9.1, with
|
||||
over 500 commits in just over 5 weeks! Didn't intend it to
|
||||
be a big release. Just happened to become.
|
||||
- hb-ft now locks underlying FT_Face during use.
|
||||
|
||||
API changes:
|
||||
|
||||
- Newly-created hb_font_t's now have our internal "hb-ot-font"
|
||||
callbacks set on them, so they should work out of the box
|
||||
without any callbacks set. If callbacks are set, everything
|
||||
is back to what it was before, the fallback callbacks are
|
||||
null. If you to get the internal implementation modified,
|
||||
sub_font it.
|
||||
|
||||
- New hb_font_funcs_set_nominal_glyphs_func() allows speeding
|
||||
up character to glyph mapping.
|
||||
|
||||
New API:
|
||||
+HB_FEATURE_GLOBAL_START
|
||||
+HB_FEATURE_GLOBAL_END
|
||||
+hb_buffer_set_invisible_glyph()
|
||||
+hb_buffer_get_invisible_glyph()
|
||||
+hb_font_funcs_set_nominal_glyphs_func()
|
||||
+hb_ot_layout_table_select_script()
|
||||
+hb_ot_layout_script_select_language()
|
||||
+hb_ot_layout_feature_get_name_ids()
|
||||
+hb_ot_layout_feature_get_characters()
|
||||
+hb_name_id_t
|
||||
+HB_NAME_ID_INVALID
|
||||
+HB_OT_MAX_TAGS_PER_SCRIPT
|
||||
+hb_ot_tags_from_script_and_language()
|
||||
+hb_ot_tags_to_script_and_language()
|
||||
|
||||
Deprecated API:
|
||||
-hb_font_funcs_set_glyph_func()
|
||||
-hb_unicode_eastasian_width_func_t
|
||||
-hb_unicode_funcs_set_eastasian_width_func()
|
||||
-hb_unicode_eastasian_width()
|
||||
-hb_unicode_decompose_compatibility_func_t
|
||||
-HB_UNICODE_MAX_DECOMPOSITION_LEN
|
||||
-hb_unicode_funcs_set_decompose_compatibility_func()
|
||||
-hb_unicode_decompose_compatibility()
|
||||
-hb_font_funcs_set_glyph_h_kerning_func()
|
||||
-hb_font_funcs_set_glyph_v_kerning_func()
|
||||
-hb_font_get_glyph_h_kerning()
|
||||
-hb_font_get_glyph_v_kerning()
|
||||
-hb_font_get_glyph_kerning_for_direction()
|
||||
-hb_ot_layout_table_choose_script()
|
||||
-hb_ot_layout_script_find_language()
|
||||
-hb_ot_tags_from_script()
|
||||
-hb_ot_tag_from_language()
|
||||
|
||||
|
||||
Overview of changes leading to 1.9.0
|
||||
Monday, September 10, 2018
|
||||
====================================
|
||||
- Added 'cmap' API to hb_face_t.
|
||||
- Face-builder API.
|
||||
- hb-ot-font re-creation should be much leaner now, as the
|
||||
font tables it uses are cached on hb_face_t now.
|
||||
- Internal source header file name changes:
|
||||
hb-*-private.hh is renamed to hb-*.hh.
|
||||
|
||||
New API:
|
||||
+HB_UNICODE_MAX
|
||||
+hb_face_collect_unicodes()
|
||||
+hb_face_collect_variation_selectors()
|
||||
+hb_face_collect_variation_unicodes()
|
||||
+hb_face_builder_create()
|
||||
+hb_face_builder_add_table()
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.8
|
||||
Tuesday, August 14, 2018
|
||||
====================================
|
||||
- Fix hb-icu crash on architectures where compare_exchange_weak() can
|
||||
fail falsely. This bug was introduced in 1.8.4.
|
||||
https://bugs.chromium.org/p/chromium/issues/detail?id=873568
|
||||
- More internal refactoring of atomic operations and singletons.
|
||||
- API changes:
|
||||
The following functions do NOT reference their return value before
|
||||
returning:
|
||||
* hb_unicode_funcs_get_default()
|
||||
* hb_glib_get_unicode_funcs()
|
||||
* hb_icu_get_unicode_funcs()
|
||||
This is consistent with their naming ("get", instead of "reference")
|
||||
as well as how they are used in the wild (ie. no one calls destroy()
|
||||
on their return value.)
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.7
|
||||
Wednesday, August 8, 2018
|
||||
====================================
|
||||
- Fix assertion failure with GDEF-blacklisted fonts.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.6
|
||||
Tuesday, August 7, 2018
|
||||
====================================
|
||||
- Internal code shuffling.
|
||||
- New API to speed up getting advance widths for implementations
|
||||
that have heavy overhead in get_h_advance callback:
|
||||
+hb_font_funcs_set_glyph_h_advances_func
|
||||
+hb_font_funcs_set_glyph_v_advances_func
|
||||
+hb_font_get_glyph_advances_for_direction
|
||||
+hb_font_get_glyph_h_advances
|
||||
+hb_font_get_glyph_h_advances_func_t
|
||||
+hb_font_get_glyph_v_advances
|
||||
+hb_font_get_glyph_v_advances_func_t
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.5
|
||||
Wednesday, August 1, 2018
|
||||
====================================
|
||||
- Major Khmer shaper improvements to better match Microsoft.
|
||||
- Indic bug fixes.
|
||||
- Internal improvements to atomic operations.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.4
|
||||
Tuesday, July 17, 2018
|
||||
====================================
|
||||
- Fix build on non-C++11.
|
||||
- Use C++-style GCC atomics and C++11 atomics.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.3
|
||||
Wednesday, July 11, 2018
|
||||
====================================
|
||||
- A couple of Indic / USE bug fixes.
|
||||
- Disable vectorization, as it was causing unaligned access bus error on
|
||||
certain 32bit architectures.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.2
|
||||
Tuesday, July 3, 2018
|
||||
====================================
|
||||
- Fix infinite loop in Khmer shaper.
|
||||
- Improve hb_blob_create_from_file() for streams.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.1
|
||||
Tuesday, June 12, 2018
|
||||
====================================
|
||||
- Fix hb-version.h file generation; last two releases went out with wrong ones.
|
||||
- Add correctness bug in hb_set_t operations, introduced in 1.7.7.
|
||||
- Remove HB_SUBSET_BUILTIN build option. Not necessary.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.0
|
||||
Tuesday, June 5, 2018
|
||||
====================================
|
||||
- Update to Unicode 11.0.0.
|
||||
|
||||
|
||||
Overview of changes leading to 1.7.7
|
||||
Tuesday, June 5, 2018
|
||||
====================================
|
||||
- Lots of internal changes, but not yet exposed externally.
|
||||
- All HarfBuzz objects are significantly smaller in size now.
|
||||
- Sinhala: Position repha on top of post-consonant, not base.
|
||||
This better matches Windows 10 behavior, which was changed
|
||||
from previous Windows versions.
|
||||
- New build options:
|
||||
o New cpp macro HB_NO_ATEXIT
|
||||
o New cpp macro HB_SUBSET_BUILTIN
|
||||
- Significant libharfbuzz-subset changes. API subject to change.
|
||||
- New API in libharfbuzz:
|
||||
|
||||
+hb_blob_create_from_file()
|
||||
+hb_face_count()
|
||||
|
||||
A hashmap implementation:
|
||||
+hb-map.h
|
||||
+HB_MAP_VALUE_INVALID
|
||||
+hb_map_t
|
||||
+hb_map_create()
|
||||
+hb_map_get_empty()
|
||||
+hb_map_reference()
|
||||
+hb_map_destroy()
|
||||
+hb_map_set_user_data()
|
||||
+hb_map_get_user_data()
|
||||
+hb_map_allocation_successful()
|
||||
+hb_map_clear()
|
||||
+hb_map_is_empty()
|
||||
+hb_map_get_population()
|
||||
+hb_map_set()
|
||||
+hb_map_get()
|
||||
+hb_map_del()
|
||||
+hb_map_has()
|
||||
|
||||
|
||||
Overview of changes leading to 1.7.6
|
||||
Wednesday, March 7, 2018
|
||||
====================================
|
||||
|
||||
- Fix to hb_set_t binary operations. Ouch.
|
||||
- New experimental harfbuzz-subset library. All of hb-subset.h
|
||||
is experimental right now and API WILL change.
|
||||
|
||||
- New API:
|
||||
hb_blob_copy_writable_or_fail()
|
||||
HB_OT_TAG_BASE
|
||||
hb_set_previous()
|
||||
hb_set_previous_range()
|
||||
|
||||
|
||||
Overview of changes leading to 1.7.5
|
||||
Tuesday, January 30, 2018
|
||||
====================================
|
||||
|
||||
- Separate Khmer shaper from Indic.
|
||||
- First stab at AAT morx. Not hooked up.
|
||||
- Misc bug fixes.
|
||||
|
||||
|
||||
Overview of changes leading to 1.7.4
|
||||
Wednesday, December 20, 2017
|
||||
====================================
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
[](https://travis-ci.org/harfbuzz/harfbuzz)
|
||||
[](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
|
||||
[](https://circleci.com/gh/harfbuzz/harfbuzz)
|
||||
[](https://coveralls.io/r/harfbuzz/harfbuzz)
|
||||
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
|
||||
|
||||
This is HarfBuzz, a text shaping library.
|
||||
|
||||
For bug reports, mailing list, and other information please visit:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see the file COPYING.
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
[](https://travis-ci.org/harfbuzz/harfbuzz)
|
||||
[](https://ci.appveyor.com/project/harfbuzz/harfbuzz)
|
||||
[](https://circleci.com/gh/harfbuzz/harfbuzz/tree/master)
|
||||
[](https://oss-fuzz-build-logs.storage.googleapis.com/index.html)
|
||||
[](https://scan.coverity.com/projects/behdad-harfbuzz)
|
||||
[](https://app.codacy.com/app/behdad/harfbuzz)
|
||||
[](https://codecov.io/gh/harfbuzz/harfbuzz)
|
||||
[](https://coveralls.io/r/harfbuzz/harfbuzz)
|
||||
[](https://repology.org/project/harfbuzz/versions)
|
||||
[ABI Tracker](http://abi-laboratory.pro/tracker/timeline/harfbuzz/)
|
||||
|
||||
This is HarfBuzz, a text shaping library.
|
||||
|
||||
For bug reports, mailing list, and other information please visit:
|
||||
|
||||
http://harfbuzz.org/
|
||||
|
||||
For license information, see [COPYING](COPYING).
|
||||
|
||||
For build information, see [BUILD.md](BUILD.md).
|
||||
|
||||
For custom configurations, see [CONFIG.md](CONFIG.md).
|
||||
|
||||
For test execution, see [TESTING.md](TESTING.md).
|
||||
|
||||
Documentation: https://harfbuzz.github.io
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Packaging status of HarfBuzz</summary
|
||||
|
||||
[](https://repology.org/project/harfbuzz/versions)
|
||||
|
||||
</details>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
Bradley Grainger
|
||||
Khaled Hosny
|
||||
Kenichi Ishibashi
|
||||
Ivan Kuckir <https://photopea.com/>
|
||||
Ryan Lortie
|
||||
Jeff Muizelaar
|
||||
suzuki toshiya
|
||||
|
|
|
|||
|
|
@ -1,24 +1,8 @@
|
|||
General fixes:
|
||||
=============
|
||||
|
||||
- AAT 'morx' implementation.
|
||||
|
||||
- Return "safe-to-break" bit from shaping.
|
||||
|
||||
- Implement 'rand' feature.
|
||||
|
||||
- mask propagation? (when ligation, "or" the masks).
|
||||
|
||||
|
||||
API issues:
|
||||
===========
|
||||
|
||||
- API to accept a list of languages?
|
||||
|
||||
- Add init_func to font_funcs. Adjust ft.
|
||||
|
||||
- 'const' for getter APIs? (use mutable internally)
|
||||
|
||||
- Remove hb_ot_shape_glyphs_closure()?
|
||||
|
||||
|
||||
|
|
@ -27,20 +11,12 @@ API additions
|
|||
|
||||
- Language to/from script.
|
||||
|
||||
- blob_from_file?
|
||||
|
||||
- Add hb-cairo glue
|
||||
|
||||
- Add sanitize API (and a cached version, that saves result on blob user-data)
|
||||
|
||||
- BCP 47 language handling / API (language_matches?)
|
||||
|
||||
- Add hb_font_create_unscaled()?
|
||||
- Add sanitize API.
|
||||
|
||||
- Add query / enumeration API for aalt-like features?
|
||||
|
||||
- SFNT api? get_num_faces? get_table_tags? (there's something in stash)
|
||||
|
||||
- Add segmentation API
|
||||
|
||||
- Add hb-fribidi glue?
|
||||
|
|
@ -50,20 +26,3 @@ hb-view / hb-shape enhancements:
|
|||
===============================
|
||||
|
||||
- Add --width, --height, --auto-size, --ink-box, --align, etc?
|
||||
|
||||
|
||||
Tests to write:
|
||||
==============
|
||||
|
||||
- ot-layout enumeration API (needs font)
|
||||
|
||||
- Finish test-shape.c, grep for TODO
|
||||
|
||||
- Finish test-unicode.c, grep for TODO
|
||||
|
||||
- GObject, FreeType, etc
|
||||
|
||||
- hb_cache_t and relatives
|
||||
|
||||
- hb_feature_to/from_string
|
||||
- hb_buffer_[sg]et_contents
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef QHARFBUZZ_CONFIG_H
|
||||
#define QHARFBUZZ_CONFIG_H
|
||||
|
||||
#include <QtCore/qatomic.h>
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
|
@ -37,11 +40,19 @@ inline QAtomicPointer<T> *makeAtomicPointer(T * const &ptr)
|
|||
return reinterpret_cast<QAtomicPointer<T> *>(const_cast<T **>(&ptr));
|
||||
}
|
||||
|
||||
static inline void _hb_memory_barrier ()
|
||||
{
|
||||
QAtomicInt a;
|
||||
a.ref(); // Ordered memory semantics, so imposes a memory barrier at this point
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) reinterpret_cast<QAtomicInt &>(AI).fetchAndAddOrdered(V)
|
||||
#define hb_atomic_int_impl_add(AI, V) reinterpret_cast<QAtomicInt *>(AI)->fetchAndAddOrdered(V)
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) makeAtomicPointer(*(P))->loadAcquire()
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) makeAtomicPointer(*(P))->testAndSetOrdered((O), (N))
|
||||
|
||||
#endif // QHARFBUZZ_CONFIG_H
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ darwin: SHAPERS += coretext
|
|||
#SHAPERS += fallback
|
||||
|
||||
DEFINES += HAVE_CONFIG_H
|
||||
DEFINES += HB_NO_UNICODE_FUNCS HB_DISABLE_DEPRECATED
|
||||
DEFINES += HB_NO_UNICODE_FUNCS
|
||||
DEFINES += HB_NDEBUG
|
||||
DEFINES += HB_EXTERN=
|
||||
|
||||
|
|
@ -36,54 +36,55 @@ INCLUDEPATH += $$QT.core.includes
|
|||
DEFINES += QT_NO_VERSION_TAGGING
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/src/hb-aat-layout.cc \
|
||||
$$PWD/src/hb-aat-map.cc \
|
||||
$$PWD/src/hb-blob.cc \
|
||||
$$PWD/src/hb-buffer.cc \
|
||||
$$PWD/src/hb-buffer-serialize.cc \
|
||||
$$PWD/src/hb-common.cc \
|
||||
$$PWD/src/hb-face.cc \
|
||||
$$PWD/src/hb-fallback-shape.cc \
|
||||
$$PWD/src/hb-font.cc \
|
||||
$$PWD/src/hb-ot-tag.cc \
|
||||
$$PWD/src/hb-map.cc \
|
||||
$$PWD/src/hb-number.cc \
|
||||
$$PWD/src/hb-set.cc \
|
||||
$$PWD/src/hb-shape.cc \
|
||||
$$PWD/src/hb-shape-plan.cc \
|
||||
$$PWD/src/hb-shaper.cc \
|
||||
$$PWD/src/hb-subset.cc \
|
||||
$$PWD/src/hb-subset-cff-common.cc \
|
||||
$$PWD/src/hb-subset-cff1.cc \
|
||||
$$PWD/src/hb-subset-cff2.cc \
|
||||
$$PWD/src/hb-subset-input.cc \
|
||||
$$PWD/src/hb-subset-plan.cc \
|
||||
$$PWD/src/hb-unicode.cc \
|
||||
$$PWD/src/hb-warning.cc
|
||||
$$PWD/hb-dummy.cc
|
||||
|
||||
OTHER_FILES += \
|
||||
$$PWD/src/harfbuzz.cc
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/src/hb-atomic-private.hh \
|
||||
$$PWD/src/hb-buffer-private.hh \
|
||||
$$PWD/src/hb-atomic.hh \
|
||||
$$PWD/src/hb-algs.hh \
|
||||
$$PWD/src/hb-buffer.hh \
|
||||
$$PWD/src/hb-buffer-deserialize-json.hh \
|
||||
$$PWD/src/hb-buffer-deserialize-text.hh \
|
||||
$$PWD/src/hb-cache-private.hh \
|
||||
$$PWD/src/hb-cache.hh \
|
||||
$$PWD/src/hb-debug.hh \
|
||||
$$PWD/src/hb-dsalgs.hh \
|
||||
$$PWD/src/hb-face-private.hh \
|
||||
$$PWD/src/hb-font-private.hh \
|
||||
$$PWD/src/hb-mutex-private.hh \
|
||||
$$PWD/src/hb-object-private.hh \
|
||||
$$PWD/src/hb-open-file-private.hh \
|
||||
$$PWD/src/hb-open-type-private.hh \
|
||||
$$PWD/src/hb-ot-cbdt-table.hh \
|
||||
$$PWD/src/hb-ot-cmap-table.hh \
|
||||
$$PWD/src/hb-ot-glyf-table.hh \
|
||||
$$PWD/src/hb-ot-head-table.hh \
|
||||
$$PWD/src/hb-ot-hhea-table.hh \
|
||||
$$PWD/src/hb-ot-hmtx-table.hh \
|
||||
$$PWD/src/hb-ot-maxp-table.hh \
|
||||
$$PWD/src/hb-ot-name-table.hh \
|
||||
$$PWD/src/hb-ot-os2-table.hh \
|
||||
$$PWD/src/hb-ot-post-table.hh \
|
||||
$$PWD/src/hb-private.hh \
|
||||
$$PWD/src/hb-set-digest-private.hh \
|
||||
$$PWD/src/hb-set-private.hh \
|
||||
$$PWD/src/hb-shape-plan-private.hh \
|
||||
$$PWD/src/hb-shaper-impl-private.hh \
|
||||
$$PWD/src/hb-face.hh \
|
||||
$$PWD/src/hb-font.hh \
|
||||
$$PWD/src/hb-mutex.hh \
|
||||
$$PWD/src/hb-object.hh \
|
||||
$$PWD/src/hb-open-file.hh \
|
||||
$$PWD/src/hb-open-type.hh \
|
||||
$$PWD/src/hb-set-digest.hh \
|
||||
$$PWD/src/hb-set.hh \
|
||||
$$PWD/src/hb-shape-plan.hh \
|
||||
$$PWD/src/hb-shaper-impl.hh \
|
||||
$$PWD/src/hb-shaper-list.hh \
|
||||
$$PWD/src/hb-shaper-private.hh \
|
||||
$$PWD/src/hb-shaper.hh \
|
||||
$$PWD/src/hb-string-array.hh \
|
||||
$$PWD/src/hb-unicode-private.hh \
|
||||
$$PWD/src/hb-utf-private.hh
|
||||
$$PWD/src/hb-unicode.hh \
|
||||
$$PWD/src/hb-utf.hh
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/src/hb.h \
|
||||
|
|
@ -103,52 +104,67 @@ contains(SHAPERS, opentype) {
|
|||
DEFINES += HAVE_OT
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/src/hb-ot-cff1-table.cc \
|
||||
$$PWD/src/hb-ot-cff2-table.cc \
|
||||
$$PWD/src/hb-ot-color.cc \
|
||||
$$PWD/src/hb-ot-face.cc \
|
||||
$$PWD/src/hb-ot-font.cc \
|
||||
$$PWD/src/hb-ot-layout.cc \
|
||||
$$PWD/src/hb-ot-map.cc \
|
||||
$$PWD/src/hb-ot-math.cc \
|
||||
$$PWD/src/hb-ot-meta.cc \
|
||||
$$PWD/src/hb-ot-metrics.cc \
|
||||
$$PWD/src/hb-ot-name.cc \
|
||||
$$PWD/src/hb-ot-shape.cc \
|
||||
$$PWD/src/hb-ot-tag.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-arabic.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-default.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-hangul.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-hebrew.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-indic.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-indic-table.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-khmer.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-myanmar.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-thai.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-tibetan.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-use.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-use-table.cc \
|
||||
$$PWD/src/hb-ot-shape-complex-vowel-constraints.cc \
|
||||
$$PWD/src/hb-ot-shape-fallback.cc \
|
||||
$$PWD/src/hb-ot-shape-normalize.cc \
|
||||
$$PWD/src/hb-ot-var.cc
|
||||
$$PWD/src/hb-ot-var.cc
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/src/hb-ot-cmap-table.hh \
|
||||
$$PWD/src/hb-ot-color-cbdt-table.hh \
|
||||
$$PWD/src/hb-ot-glyf-table.hh \
|
||||
$$PWD/src/hb-ot-head-table.hh \
|
||||
$$PWD/src/hb-ot-hhea-table.hh \
|
||||
$$PWD/src/hb-ot-hmtx-table.hh \
|
||||
$$PWD/src/hb-ot-kern-table.hh \
|
||||
$$PWD/src/hb-ot-layout-common-private.hh \
|
||||
$$PWD/src/hb-ot-layout.hh \
|
||||
$$PWD/src/hb-ot-layout-gdef-table.hh \
|
||||
$$PWD/src/hb-ot-layout-gpos-table.hh \
|
||||
$$PWD/src/hb-ot-layout-gsubgpos-private.hh \
|
||||
$$PWD/src/hb-ot-layout-gsub-table.hh \
|
||||
$$PWD/src/hb-ot-layout-jstf-table.hh \
|
||||
$$PWD/src/hb-ot-layout-math-table.hh \
|
||||
$$PWD/src/hb-ot-layout-private.hh \
|
||||
$$PWD/src/hb-ot-map-private.hh \
|
||||
$$PWD/src/hb-ot-map.hh \
|
||||
$$PWD/src/hb-ot-math-table.hh \
|
||||
$$PWD/src/hb-ot-maxp-table.hh \
|
||||
$$PWD/src/hb-ot-name-table.hh \
|
||||
$$PWD/src/hb-ot-os2-table.hh \
|
||||
$$PWD/src/hb-ot-post-table.hh \
|
||||
$$PWD/src/hb-ot-post-macroman.hh \
|
||||
$$PWD/src/hb-ot-shape.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-arabic.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-arabic-fallback.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-arabic-private.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-arabic-table.hh \
|
||||
# $$PWD/src/hb-ot-shape-complex-arabic-win1256.hh \ # disabled with HB_NO_WIN1256
|
||||
$$PWD/src/hb-ot-shape-complex-indic.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-indic-machine.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-indic-private.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-myanmar-machine.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-private.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-use.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-use-machine.hh \
|
||||
$$PWD/src/hb-ot-shape-complex-use-private.hh \
|
||||
$$PWD/src/hb-ot-shape-fallback-private.hh \
|
||||
$$PWD/src/hb-ot-shape-normalize-private.hh \
|
||||
$$PWD/src/hb-ot-shape-private.hh \
|
||||
$$PWD/src/hb-ot-shape-fallback.hh \
|
||||
$$PWD/src/hb-ot-shape-normalize.hh \
|
||||
$$PWD/src/hb-ot-var-avar-table.hh \
|
||||
$$PWD/src/hb-ot-var-fvar-table.hh \
|
||||
$$PWD/src/hb-ot-var-hvar-table.hh \
|
||||
|
|
@ -160,7 +176,6 @@ contains(SHAPERS, opentype) {
|
|||
$$PWD/src/hb-ot-layout.h \
|
||||
$$PWD/src/hb-ot-math.h \
|
||||
$$PWD/src/hb-ot-shape.h \
|
||||
$$PWD/src/hb-ot-tag.h \
|
||||
$$PWD/src/hb-ot-var.h
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
// Work-around for issue with qmake: Since hb-common.cc has #include "hb-static.cc" in it,
|
||||
// qmake will assume it is included and ignore it in the SOURCES list. But the #include
|
||||
// is protected inside an #ifdef and will not be used, so hb-static.cc ends up not being
|
||||
// linked at all and we get missing symbols. We work around this by including both in
|
||||
// the same compilation unit.
|
||||
|
||||
#include "src/hb-common.cc"
|
||||
#include "src/hb-static.cc"
|
||||
|
|
@ -1,23 +1,25 @@
|
|||
From: Konstantin Ritt <ritt.ks@gmail.com>
|
||||
Date: Sun, 17 Dec 2017 07:46:20 +0400
|
||||
Subject: Qt-specific workaround for AAT shaper
|
||||
From 96b71dc7c8ab8aa020f47dc659b32c2002001015 Mon Sep 17 00:00:00 2001
|
||||
From: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
|
||||
Date: Thu, 28 Nov 2019 14:51:39 +0100
|
||||
Subject: [PATCH] Qt-specific workaround for AAT shaper
|
||||
|
||||
CoreText API doesn't give us a fontdata to reconstruct the original font,
|
||||
so we have to store the CTFont and CGFont of interest in context object
|
||||
passed to HB from native font engine
|
||||
passed to HB from native font engine.
|
||||
|
||||
Change-Id: I9a71ae71b7d22f32498a9dd386500fa867a5f6cd
|
||||
---
|
||||
src/3rdparty/harfbuzz-ng/src/hb-coretext.cc | 20 ++++++++++++++++++++
|
||||
1 file changed, 20 insertions(+)
|
||||
|
||||
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc b/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
|
||||
index 2dd10d2..c993ec0 100644
|
||||
index 8885cfe..f4e3ef0 100644
|
||||
--- a/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
|
||||
+++ b/src/3rdparty/harfbuzz-ng/src/hb-coretext.cc
|
||||
@@ -35,6 +35,20 @@
|
||||
#include "hb-coretext.h"
|
||||
@@ -36,6 +36,18 @@
|
||||
#include "hb-aat-layout.hh"
|
||||
#include <math.h>
|
||||
|
||||
+
|
||||
+typedef bool (*qt_get_font_table_func_t) (void *user_data, unsigned int tag, unsigned char *buffer, unsigned int *length);
|
||||
+
|
||||
+struct FontEngineFaceData {
|
||||
|
|
@ -30,11 +32,26 @@ index 2dd10d2..c993ec0 100644
|
|||
+ CGFontRef cgFont;
|
||||
+};
|
||||
+
|
||||
+
|
||||
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
|
||||
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
|
||||
|
||||
@@ -129,6 +143,7 @@ create_cg_font (hb_face_t *face)
|
||||
/**
|
||||
* SECTION:hb-coretext
|
||||
@@ -107,6 +119,7 @@ get_last_resort_font_desc ()
|
||||
return font_desc;
|
||||
}
|
||||
|
||||
+#if 0
|
||||
static void
|
||||
release_data (void *info, const void *data, size_t size)
|
||||
{
|
||||
@@ -115,6 +128,7 @@ release_data (void *info, const void *data, size_t size)
|
||||
|
||||
hb_blob_destroy ((hb_blob_t *) info);
|
||||
}
|
||||
+#endif
|
||||
|
||||
static CGFontRef
|
||||
create_cg_font (hb_face_t *face)
|
||||
@@ -126,6 +140,7 @@ create_cg_font (hb_face_t *face)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -42,7 +59,7 @@ index 2dd10d2..c993ec0 100644
|
|||
hb_blob_t *blob = hb_face_reference_blob (face);
|
||||
unsigned int blob_length;
|
||||
const char *blob_data = hb_blob_get_data (blob, &blob_length);
|
||||
@@ -143,6 +158,11 @@ create_cg_font (hb_face_t *face)
|
||||
@@ -140,6 +155,11 @@ create_cg_font (hb_face_t *face)
|
||||
DEBUG_MSG (CORETEXT, face, "Face CGFontCreateWithDataProvider() failed");
|
||||
CGDataProviderRelease (provider);
|
||||
}
|
||||
|
|
@ -55,4 +72,5 @@ index 2dd10d2..c993ec0 100644
|
|||
return cg_font;
|
||||
}
|
||||
--
|
||||
2.8.1
|
||||
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@
|
|||
|
||||
"Description": "HarfBuzz is an OpenType text shaping engine.",
|
||||
"Homepage": "http://harfbuzz.org",
|
||||
"Version": "1.7.4",
|
||||
"Version": "2.6.4",
|
||||
|
||||
"License": "MIT License",
|
||||
"LicenseId": "MIT",
|
||||
"LicenseFile": "COPYING",
|
||||
"Copyright": "Copyright © 2010,2011,2012 Google, Inc.
|
||||
"Copyright": "Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019 Google, Inc.
|
||||
Copyright © 2019 Facebook, Inc.
|
||||
Copyright © 2012 Mozilla Foundation
|
||||
Copyright © 2011 Codethink Limited
|
||||
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-ot-shape-complex-indic.hh"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
hb_glyph_info_t info;
|
||||
info.codepoint = u;
|
||||
set_indic_properties (info);
|
||||
if (info.indic_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
|
||||
info.indic_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
|
||||
printf("U+%04X %u %u\n", u,
|
||||
info.indic_category(),
|
||||
info.indic_position());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-ot-shape-complex-khmer.hh"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
hb_glyph_info_t info;
|
||||
info.codepoint = u;
|
||||
set_khmer_properties (info);
|
||||
if (info.khmer_category() != INDIC_SYLLABIC_CATEGORY_OTHER)
|
||||
printf("U+%04X %u\n", u,
|
||||
info.khmer_category());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-ot-shape-complex-myanmar.hh"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
hb_glyph_info_t info;
|
||||
info.codepoint = u;
|
||||
set_myanmar_properties (info);
|
||||
if (info.myanmar_category() != INDIC_SYLLABIC_CATEGORY_OTHER ||
|
||||
info.myanmar_position() != INDIC_MATRA_CATEGORY_NOT_APPLICABLE)
|
||||
printf("U+%04X %u %u\n", u,
|
||||
info.myanmar_category(),
|
||||
info.myanmar_position());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-ot-shape-complex-use.hh"
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
for (hb_codepoint_t u = 0; u <= 0x10FFFF; u++)
|
||||
{
|
||||
unsigned int category = hb_use_get_category (u);
|
||||
if (category != USE_O)
|
||||
printf("U+%04X %u\n", u, category);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
# Set these variables so that the `${prefix}/lib` expands to something we can
|
||||
# remove.
|
||||
set(_harfbuzz_remove_string "REMOVE_ME")
|
||||
set(exec_prefix "${_harfbuzz_remove_string}")
|
||||
set(prefix "${_harfbuzz_remove_string}")
|
||||
|
||||
# Compute the installation prefix by stripping components from our current
|
||||
# location.
|
||||
get_filename_component(_harfbuzz_prefix "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
|
||||
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
|
||||
set(_harfbuzz_libdir "@libdir@")
|
||||
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}")
|
||||
set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}")
|
||||
while (_harfbuzz_libdir_iter)
|
||||
set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}")
|
||||
get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY)
|
||||
if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter)
|
||||
break()
|
||||
endif ()
|
||||
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
|
||||
endwhile ()
|
||||
unset(_harfbuzz_libdir_iter)
|
||||
|
||||
# Get the include subdir.
|
||||
set(_harfbuzz_includedir "@includedir@")
|
||||
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_includedir "${_harfbuzz_includedir}")
|
||||
|
||||
# Extract version information from libtool.
|
||||
set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
|
||||
string(REPLACE ":" ";" _harfbuzz_version_info "${_harfbuzz_version_info}")
|
||||
list(GET _harfbuzz_version_info 0
|
||||
_harfbuzz_current)
|
||||
list(GET _harfbuzz_version_info 1
|
||||
_harfbuzz_revision)
|
||||
list(GET _harfbuzz_version_info 2
|
||||
_harfbuzz_age)
|
||||
unset(_harfbuzz_version_info)
|
||||
|
||||
if (APPLE)
|
||||
set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
elseif (UNIX)
|
||||
set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}")
|
||||
else ()
|
||||
# Unsupported.
|
||||
set(harfbuzz_FOUND 0)
|
||||
endif ()
|
||||
|
||||
# Add the libraries.
|
||||
add_library(harfbuzz::harfbuzz SHARED IMPORTED)
|
||||
set_target_properties(harfbuzz::harfbuzz PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
|
||||
|
||||
add_library(harfbuzz::icu SHARED IMPORTED)
|
||||
set_target_properties(harfbuzz::icu PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
|
||||
|
||||
add_library(harfbuzz::subset SHARED IMPORTED)
|
||||
set_target_properties(harfbuzz::subset PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
|
||||
|
||||
# Only add the gobject library if it was built.
|
||||
set(_harfbuzz_have_gobject "@have_gobject@")
|
||||
if (_harfbuzz_have_gobject)
|
||||
add_library(harfbuzz::gobject SHARED IMPORTED)
|
||||
set_target_properties(harfbuzz::gobject PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
|
||||
endif ()
|
||||
|
||||
# Clean out variables we used in our scope.
|
||||
unset(_harfbuzz_lib_suffix)
|
||||
unset(_harfbuzz_current)
|
||||
unset(_harfbuzz_revision)
|
||||
unset(_harfbuzz_age)
|
||||
unset(_harfbuzz_includedir)
|
||||
unset(_harfbuzz_libdir)
|
||||
unset(_harfbuzz_prefix)
|
||||
unset(exec_prefix)
|
||||
unset(prefix)
|
||||
unset(_harfbuzz_remove_string)
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
prefix=%prefix%
|
||||
exec_prefix=%exec_prefix%
|
||||
libdir=%libdir%
|
||||
includedir=%includedir%
|
||||
|
||||
Name: harfbuzz
|
||||
Description: HarfBuzz text shaping library GObject integration
|
||||
Version: %VERSION%
|
||||
|
||||
Requires: harfbuzz gobject-2.0 glib-2.0
|
||||
Libs: -L${libdir} -lharfbuzz-gobject
|
||||
Cflags: -I${includedir}/harfbuzz
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
prefix=%prefix%
|
||||
exec_prefix=%exec_prefix%
|
||||
libdir=%libdir%
|
||||
includedir=%includedir%
|
||||
|
||||
Name: harfbuzz
|
||||
Description: HarfBuzz text shaping library ICU integration
|
||||
Version: %VERSION%
|
||||
|
||||
Requires: harfbuzz
|
||||
Requires.private: icu-uc
|
||||
Libs: -L${libdir} -lharfbuzz-icu
|
||||
Cflags: -I${includedir}/harfbuzz
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
prefix=%prefix%
|
||||
exec_prefix=%exec_prefix%
|
||||
libdir=%libdir%
|
||||
includedir=%includedir%
|
||||
|
||||
Name: harfbuzz
|
||||
Description: HarfBuzz font subsetter
|
||||
Version: %VERSION%
|
||||
|
||||
Requires: harfbuzz
|
||||
Libs: -L${libdir} -lharfbuzz-subset
|
||||
Cflags: -I${includedir}/harfbuzz
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include "hb-aat-layout.cc"
|
||||
#include "hb-aat-map.cc"
|
||||
#include "hb-blob.cc"
|
||||
#include "hb-buffer-serialize.cc"
|
||||
#include "hb-buffer.cc"
|
||||
#include "hb-common.cc"
|
||||
#include "hb-face.cc"
|
||||
#include "hb-fallback-shape.cc"
|
||||
#include "hb-font.cc"
|
||||
#include "hb-map.cc"
|
||||
#include "hb-number.cc"
|
||||
#include "hb-ot-cff1-table.cc"
|
||||
#include "hb-ot-cff2-table.cc"
|
||||
#include "hb-ot-color.cc"
|
||||
#include "hb-ot-face.cc"
|
||||
#include "hb-ot-font.cc"
|
||||
#include "hb-ot-layout.cc"
|
||||
#include "hb-ot-map.cc"
|
||||
#include "hb-ot-math.cc"
|
||||
#include "hb-ot-meta.cc"
|
||||
#include "hb-ot-metrics.cc"
|
||||
#include "hb-ot-name.cc"
|
||||
#include "hb-ot-shape-complex-arabic.cc"
|
||||
#include "hb-ot-shape-complex-default.cc"
|
||||
#include "hb-ot-shape-complex-hangul.cc"
|
||||
#include "hb-ot-shape-complex-hebrew.cc"
|
||||
#include "hb-ot-shape-complex-indic-table.cc"
|
||||
#include "hb-ot-shape-complex-indic.cc"
|
||||
#include "hb-ot-shape-complex-khmer.cc"
|
||||
#include "hb-ot-shape-complex-myanmar.cc"
|
||||
#include "hb-ot-shape-complex-thai.cc"
|
||||
#include "hb-ot-shape-complex-use-table.cc"
|
||||
#include "hb-ot-shape-complex-use.cc"
|
||||
#include "hb-ot-shape-complex-vowel-constraints.cc"
|
||||
#include "hb-ot-shape-fallback.cc"
|
||||
#include "hb-ot-shape-normalize.cc"
|
||||
#include "hb-ot-shape.cc"
|
||||
#include "hb-ot-tag.cc"
|
||||
#include "hb-ot-var.cc"
|
||||
#include "hb-set.cc"
|
||||
#include "hb-shape-plan.cc"
|
||||
#include "hb-shape.cc"
|
||||
#include "hb-shaper.cc"
|
||||
#include "hb-static.cc"
|
||||
#include "hb-ucd.cc"
|
||||
#include "hb-unicode.cc"
|
||||
#include "hb-glib.cc"
|
||||
#include "hb-ft.cc"
|
||||
#include "hb-graphite2.cc"
|
||||
#include "hb-uniscribe.cc"
|
||||
#include "hb-gdi.cc"
|
||||
#include "hb-directwrite.cc"
|
||||
#include "hb-coretext.cc"
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
prefix=%prefix%
|
||||
exec_prefix=%exec_prefix%
|
||||
libdir=%libdir%
|
||||
includedir=%includedir%
|
||||
|
||||
Name: harfbuzz
|
||||
Description: HarfBuzz text shaping library
|
||||
Version: %VERSION%
|
||||
|
||||
Libs: -L${libdir} -lharfbuzz
|
||||
Libs.private: -lm %libs_private%
|
||||
Requires.private: %requires_private%
|
||||
Cflags: -I${includedir}/harfbuzz
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_FDSC_TABLE_HH
|
||||
#define HB_AAT_FDSC_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* fdsc -- Font descriptors
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html
|
||||
*/
|
||||
#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct FontDescriptor
|
||||
{
|
||||
bool has_data () const { return tag; }
|
||||
|
||||
int cmp (hb_tag_t a) const { return tag.cmp (a); }
|
||||
|
||||
float get_value () const { return u.value.to_float (); }
|
||||
|
||||
enum non_alphabetic_value_t {
|
||||
Alphabetic = 0,
|
||||
Dingbats = 1,
|
||||
PiCharacters = 2,
|
||||
Fleurons = 3,
|
||||
DecorativeBorders = 4,
|
||||
InternationalSymbols= 5,
|
||||
MathSymbols = 6
|
||||
};
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
protected:
|
||||
Tag tag; /* The 4-byte table tag name. */
|
||||
union {
|
||||
HBFixed value; /* The value for the descriptor tag. */
|
||||
HBUINT32 nalfType; /* If the tag is `nalf`, see non_alphabetic_value_t */
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct fdsc
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
|
||||
|
||||
enum {
|
||||
Weight = HB_TAG ('w','g','h','t'),
|
||||
/* Percent weight relative to regular weight.
|
||||
* (defaul value: 1.0) */
|
||||
Width = HB_TAG ('w','d','t','h'),
|
||||
/* Percent width relative to regular width.
|
||||
* (default value: 1.0) */
|
||||
Slant = HB_TAG ('s','l','n','t'),
|
||||
/* Angle of slant in degrees, where positive
|
||||
* is clockwise from straight up.
|
||||
* (default value: 0.0) */
|
||||
OpticalSize = HB_TAG ('o','p','s','z'),
|
||||
/* Point size the font was designed for.
|
||||
* (default value: 12.0) */
|
||||
NonAlphabetic= HB_TAG ('n','a','l','f')
|
||||
/* These values are treated as integers,
|
||||
* not fixed32s. 0 means alphabetic, and greater
|
||||
* integers mean the font is non-alphabetic (e.g. symbols).
|
||||
* (default value: 0) */
|
||||
};
|
||||
|
||||
const FontDescriptor &get_descriptor (hb_tag_t style) const
|
||||
{ return descriptors.lsearch (style); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
descriptors.sanitize (c));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBFixed version; /* Version number of the font descriptors
|
||||
* table (0x00010000 for the current version). */
|
||||
LArrayOf<FontDescriptor>
|
||||
descriptors; /* List of tagged-coordinate pairs style descriptors
|
||||
* that will be included to characterize this font.
|
||||
* Each descriptor consists of a <tag, value> pair.
|
||||
* These pairs are located in the gxFontDescriptor
|
||||
* array that follows. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, descriptors);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_FDSC_TABLE_HH */
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_ANKR_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_ANKR_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
|
||||
/*
|
||||
* ankr -- Anchor Point
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ankr.html
|
||||
*/
|
||||
#define HB_AAT_TAG_ankr HB_TAG('a','n','k','r')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
struct Anchor
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
public:
|
||||
FWORD xCoordinate;
|
||||
FWORD yCoordinate;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
typedef LArrayOf<Anchor> GlyphAnchors;
|
||||
|
||||
struct ankr
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ankr;
|
||||
|
||||
const Anchor &get_anchor (hb_codepoint_t glyph_id,
|
||||
unsigned int i,
|
||||
unsigned int num_glyphs) const
|
||||
{
|
||||
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
|
||||
if (!offset)
|
||||
return Null(Anchor);
|
||||
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
|
||||
return anchors[i];
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version == 0 &&
|
||||
c->check_range (this, anchorData) &&
|
||||
lookupTable.sanitize (c, this, &(this+anchorData))));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Version number (set to zero) */
|
||||
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
|
||||
lookupTable; /* Offset to the table's lookup table */
|
||||
LNNOffsetTo<HBUINT8>
|
||||
anchorData; /* Offset to the glyph data table */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_ANKR_TABLE_HH */
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_BSLN_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_BSLN_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
|
||||
/*
|
||||
* bsln -- Baseline
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6bsln.html
|
||||
*/
|
||||
#define HB_AAT_TAG_bsln HB_TAG('b','s','l','n')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct BaselineTableFormat0Part
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
// Roman, Ideographic centered, Ideographic low, Hanging and Math
|
||||
// are the default defined ones, but any other maybe accessed also.
|
||||
HBINT16 deltas[32]; /* These are the FUnit distance deltas from
|
||||
* the font's natural baseline to the other
|
||||
* baselines used in the font. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (64);
|
||||
};
|
||||
|
||||
struct BaselineTableFormat1Part
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
lookupTable.sanitize (c)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBINT16 deltas[32]; /* ditto */
|
||||
Lookup<HBUINT16>
|
||||
lookupTable; /* Lookup table that maps glyphs to their
|
||||
* baseline values. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (66);
|
||||
};
|
||||
|
||||
struct BaselineTableFormat2Part
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBGlyphID stdGlyph; /* The specific glyph index number in this
|
||||
* font that is used to set the baseline values.
|
||||
* This is the standard glyph.
|
||||
* This glyph must contain a set of control points
|
||||
* (whose numbers are contained in the ctlPoints field)
|
||||
* that are used to determine baseline distances. */
|
||||
HBUINT16 ctlPoints[32]; /* Set of control point numbers,
|
||||
* associated with the standard glyph.
|
||||
* A value of 0xFFFF means there is no corresponding
|
||||
* control point in the standard glyph. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (66);
|
||||
};
|
||||
|
||||
struct BaselineTableFormat3Part
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && lookupTable.sanitize (c));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBGlyphID stdGlyph; /* ditto */
|
||||
HBUINT16 ctlPoints[32]; /* ditto */
|
||||
Lookup<HBUINT16>
|
||||
lookupTable; /* Lookup table that maps glyphs to their
|
||||
* baseline values. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (68);
|
||||
};
|
||||
|
||||
struct bsln
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_bsln;
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!(c->check_struct (this) && defaultBaseline < 32)))
|
||||
return_trace (false);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (parts.format0.sanitize (c));
|
||||
case 1: return_trace (parts.format1.sanitize (c));
|
||||
case 2: return_trace (parts.format2.sanitize (c));
|
||||
case 3: return_trace (parts.format3.sanitize (c));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the Baseline table. */
|
||||
HBUINT16 format; /* Format of the baseline table. Only one baseline
|
||||
* format may be selected for the font. */
|
||||
HBUINT16 defaultBaseline;/* Default baseline value for all glyphs.
|
||||
* This value can be from 0 through 31. */
|
||||
union {
|
||||
// Distance-Based Formats
|
||||
BaselineTableFormat0Part format0;
|
||||
BaselineTableFormat1Part format1;
|
||||
// Control Point-based Formats
|
||||
BaselineTableFormat2Part format2;
|
||||
BaselineTableFormat3Part format3;
|
||||
} parts;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_BSLN_TABLE_HH */
|
||||
|
|
@ -0,0 +1,841 @@
|
|||
/*
|
||||
* Copyright © 2017 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_COMMON_HH
|
||||
#define HB_AAT_LAYOUT_COMMON_HH
|
||||
|
||||
#include "hb-aat-layout.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
/*
|
||||
* Lookup Table
|
||||
*/
|
||||
|
||||
template <typename T> struct Lookup;
|
||||
|
||||
template <typename T>
|
||||
struct LookupFormat0
|
||||
{
|
||||
friend struct Lookup<T>;
|
||||
|
||||
private:
|
||||
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
{
|
||||
if (unlikely (glyph_id >= num_glyphs)) return nullptr;
|
||||
return &arrayZ[glyph_id];
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 0 */
|
||||
UnsizedArrayOf<T>
|
||||
arrayZ; /* Array of lookup values, indexed by glyph index. */
|
||||
public:
|
||||
DEFINE_SIZE_UNBOUNDED (2);
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct LookupSegmentSingle
|
||||
{
|
||||
static constexpr unsigned TerminationWordCount = 2u;
|
||||
|
||||
int cmp (hb_codepoint_t g) const
|
||||
{ return g < first ? -1 : g <= last ? 0 : +1 ; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && value.sanitize (c));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && value.sanitize (c, base));
|
||||
}
|
||||
|
||||
HBGlyphID last; /* Last GlyphID in this segment */
|
||||
HBGlyphID first; /* First GlyphID in this segment */
|
||||
T value; /* The lookup value (only one) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4 + T::static_size);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupFormat2
|
||||
{
|
||||
friend struct Lookup<T>;
|
||||
|
||||
private:
|
||||
const T* get_value (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
|
||||
return v ? &v->value : nullptr;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (segments.sanitize (c));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (segments.sanitize (c, base));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, segments);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupSegmentArray
|
||||
{
|
||||
static constexpr unsigned TerminationWordCount = 2u;
|
||||
|
||||
const T* get_value (hb_codepoint_t glyph_id, const void *base) const
|
||||
{
|
||||
return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
|
||||
}
|
||||
|
||||
int cmp (hb_codepoint_t g) const
|
||||
{ return g < first ? -1 : g <= last ? 0 : +1; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1));
|
||||
}
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
|
||||
}
|
||||
|
||||
HBGlyphID last; /* Last GlyphID in this segment */
|
||||
HBGlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T>>
|
||||
valuesZ; /* A 16-bit offset from the start of
|
||||
* the table to the data. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (6);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupFormat4
|
||||
{
|
||||
friend struct Lookup<T>;
|
||||
|
||||
private:
|
||||
const T* get_value (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
|
||||
return v ? v->get_value (glyph_id, this) : nullptr;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (segments.sanitize (c, this));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (segments.sanitize (c, this, base));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 4 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, segments);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupSingle
|
||||
{
|
||||
static constexpr unsigned TerminationWordCount = 1u;
|
||||
|
||||
int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && value.sanitize (c));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && value.sanitize (c, base));
|
||||
}
|
||||
|
||||
HBGlyphID glyph; /* Last GlyphID */
|
||||
T value; /* The lookup value (only one) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (2 + T::static_size);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupFormat6
|
||||
{
|
||||
friend struct Lookup<T>;
|
||||
|
||||
private:
|
||||
const T* get_value (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
const LookupSingle<T> *v = entries.bsearch (glyph_id);
|
||||
return v ? &v->value : nullptr;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (entries.sanitize (c));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (entries.sanitize (c, base));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 6 */
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T>>
|
||||
entries; /* The actual entries, sorted by glyph index. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, entries);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupFormat8
|
||||
{
|
||||
friend struct Lookup<T>;
|
||||
|
||||
private:
|
||||
const T* get_value (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
|
||||
&valueArrayZ[glyph_id - firstGlyph] : nullptr;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 8 */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
|
||||
* glyph minus the value of firstGlyph plus 1). */
|
||||
UnsizedArrayOf<T>
|
||||
valueArrayZ; /* The lookup values (indexed by the glyph index
|
||||
* minus the value of firstGlyph). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (6, valueArrayZ);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct LookupFormat10
|
||||
{
|
||||
friend struct Lookup<T>;
|
||||
|
||||
private:
|
||||
const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
|
||||
return Null(T);
|
||||
|
||||
const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
|
||||
|
||||
unsigned int v = 0;
|
||||
unsigned int count = valueSize;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
v = (v << 8) | *p++;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
valueSize <= 4 &&
|
||||
valueArrayZ.sanitize (c, glyphCount * valueSize));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 8 */
|
||||
HBUINT16 valueSize; /* Byte size of each value. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
|
||||
* glyph minus the value of firstGlyph plus 1). */
|
||||
UnsizedArrayOf<HBUINT8>
|
||||
valueArrayZ; /* The lookup values (indexed by the glyph index
|
||||
* minus the value of firstGlyph). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, valueArrayZ);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Lookup
|
||||
{
|
||||
const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 0: return u.format0.get_value (glyph_id, num_glyphs);
|
||||
case 2: return u.format2.get_value (glyph_id);
|
||||
case 4: return u.format4.get_value (glyph_id);
|
||||
case 6: return u.format6.get_value (glyph_id);
|
||||
case 8: return u.format8.get_value (glyph_id);
|
||||
default:return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
{
|
||||
switch (u.format) {
|
||||
/* Format 10 cannot return a pointer. */
|
||||
case 10: return u.format10.get_value_or_null (glyph_id);
|
||||
default:
|
||||
const T *v = get_value (glyph_id, num_glyphs);
|
||||
return v ? *v : Null(T);
|
||||
}
|
||||
}
|
||||
|
||||
typename T::type get_class (hb_codepoint_t glyph_id,
|
||||
unsigned int num_glyphs,
|
||||
unsigned int outOfRange) const
|
||||
{
|
||||
const T *v = get_value (glyph_id, num_glyphs);
|
||||
return v ? *v : outOfRange;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
switch (u.format) {
|
||||
case 0: return_trace (u.format0.sanitize (c));
|
||||
case 2: return_trace (u.format2.sanitize (c));
|
||||
case 4: return_trace (u.format4.sanitize (c));
|
||||
case 6: return_trace (u.format6.sanitize (c));
|
||||
case 8: return_trace (u.format8.sanitize (c));
|
||||
case 10: return_trace (u.format10.sanitize (c));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.format.sanitize (c)) return_trace (false);
|
||||
switch (u.format) {
|
||||
case 0: return_trace (u.format0.sanitize (c, base));
|
||||
case 2: return_trace (u.format2.sanitize (c, base));
|
||||
case 4: return_trace (u.format4.sanitize (c, base));
|
||||
case 6: return_trace (u.format6.sanitize (c, base));
|
||||
case 8: return_trace (u.format8.sanitize (c, base));
|
||||
case 10: return_trace (false); /* We don't support format10 here currently. */
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
union {
|
||||
HBUINT16 format; /* Format identifier */
|
||||
LookupFormat0<T> format0;
|
||||
LookupFormat2<T> format2;
|
||||
LookupFormat4<T> format4;
|
||||
LookupFormat6<T> format6;
|
||||
LookupFormat8<T> format8;
|
||||
LookupFormat10<T> format10;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_UNION (2, format);
|
||||
};
|
||||
/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined
|
||||
* special NULL objects for Lookup<> objects, but since it's template our macros
|
||||
* don't work. So we have to hand-code them here. UGLY. */
|
||||
} /* Close namespace. */
|
||||
/* Ugly hand-coded null objects for template Lookup<> :(. */
|
||||
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
|
||||
template <typename T>
|
||||
struct Null<AAT::Lookup<T>> {
|
||||
static AAT::Lookup<T> const & get_null ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
|
||||
};
|
||||
namespace AAT {
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
|
||||
/*
|
||||
* (Extended) State Table
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct Entry
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
/* Note, we don't recurse-sanitize data because we don't access it.
|
||||
* That said, in our DEFINE_SIZE_STATIC we access T::static_size,
|
||||
* which ensures that data has a simple sanitize(). To be determined
|
||||
* if I need to remove that as well.
|
||||
*
|
||||
* HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
|
||||
* assertion wouldn't be checked, hence the line below. */
|
||||
static_assert (T::static_size, "");
|
||||
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
public:
|
||||
HBUINT16 newState; /* Byte offset from beginning of state table
|
||||
* to the new state. Really?!?! Or just state
|
||||
* number? The latter in morx for sure. */
|
||||
HBUINT16 flags; /* Table specific. */
|
||||
T data; /* Optional offsets to per-glyph tables. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4 + T::static_size);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Entry<void>
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
public:
|
||||
HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */
|
||||
HBUINT16 flags; /* Table specific. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
template <typename Types, typename Extra>
|
||||
struct StateTable
|
||||
{
|
||||
typedef typename Types::HBUINT HBUINT;
|
||||
typedef typename Types::HBUSHORT HBUSHORT;
|
||||
typedef typename Types::ClassTypeNarrow ClassType;
|
||||
|
||||
enum State
|
||||
{
|
||||
STATE_START_OF_TEXT = 0,
|
||||
STATE_START_OF_LINE = 1,
|
||||
};
|
||||
enum Class
|
||||
{
|
||||
CLASS_END_OF_TEXT = 0,
|
||||
CLASS_OUT_OF_BOUNDS = 1,
|
||||
CLASS_DELETED_GLYPH = 2,
|
||||
CLASS_END_OF_LINE = 3,
|
||||
};
|
||||
|
||||
int new_state (unsigned int newState) const
|
||||
{ return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
|
||||
|
||||
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
|
||||
{
|
||||
if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
|
||||
return (this+classTable).get_class (glyph_id, num_glyphs, 1);
|
||||
}
|
||||
|
||||
const Entry<Extra> *get_entries () const
|
||||
{ return (this+entryTable).arrayZ; }
|
||||
|
||||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
||||
unsigned int entry = states[state * nClasses + klass];
|
||||
DEBUG_MSG (APPLY, nullptr, "e%u", entry);
|
||||
|
||||
return entries[entry];
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
unsigned int *num_entries_out = nullptr) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!(c->check_struct (this) &&
|
||||
nClasses >= 4 /* Ensure pre-defined classes fit. */ &&
|
||||
classTable.sanitize (c, this)))) return_trace (false);
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
|
||||
unsigned int num_classes = nClasses;
|
||||
if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
|
||||
return_trace (false);
|
||||
unsigned int row_stride = num_classes * states[0].static_size;
|
||||
|
||||
/* Apple 'kern' table has this peculiarity:
|
||||
*
|
||||
* "Because the stateTableOffset in the state table header is (strictly
|
||||
* speaking) redundant, some 'kern' tables use it to record an initial
|
||||
* state where that should not be StartOfText. To determine if this is
|
||||
* done, calculate what the stateTableOffset should be. If it's different
|
||||
* from the actual stateTableOffset, use it as the initial state."
|
||||
*
|
||||
* We implement this by calling the initial state zero, but allow *negative*
|
||||
* states if the start state indeed was not the first state. Since the code
|
||||
* is shared, this will also apply to 'mort' table. The 'kerx' / 'morx'
|
||||
* tables are not affected since those address states by index, not offset.
|
||||
*/
|
||||
|
||||
int min_state = 0;
|
||||
int max_state = 0;
|
||||
unsigned int num_entries = 0;
|
||||
|
||||
int state_pos = 0;
|
||||
int state_neg = 0;
|
||||
unsigned int entry = 0;
|
||||
while (min_state < state_neg || state_pos <= max_state)
|
||||
{
|
||||
if (min_state < state_neg)
|
||||
{
|
||||
/* Negative states. */
|
||||
if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
|
||||
return_trace (false);
|
||||
if (unlikely (!c->check_range (&states[min_state * num_classes],
|
||||
-min_state,
|
||||
row_stride)))
|
||||
return_trace (false);
|
||||
if ((c->max_ops -= state_neg - min_state) <= 0)
|
||||
return_trace (false);
|
||||
{ /* Sweep new states. */
|
||||
const HBUSHORT *stop = &states[min_state * num_classes];
|
||||
if (unlikely (stop > states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = states; stop < p; p--)
|
||||
num_entries = hb_max (num_entries, *(p - 1) + 1);
|
||||
state_neg = min_state;
|
||||
}
|
||||
}
|
||||
|
||||
if (state_pos <= max_state)
|
||||
{
|
||||
/* Positive states. */
|
||||
if (unlikely (!c->check_range (states,
|
||||
max_state + 1,
|
||||
row_stride)))
|
||||
return_trace (false);
|
||||
if ((c->max_ops -= max_state - state_pos + 1) <= 0)
|
||||
return_trace (false);
|
||||
{ /* Sweep new states. */
|
||||
if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
|
||||
return_trace (false);
|
||||
const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
|
||||
if (unlikely (stop < states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
|
||||
num_entries = hb_max (num_entries, *p + 1);
|
||||
state_pos = max_state + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely (!c->check_array (entries, num_entries)))
|
||||
return_trace (false);
|
||||
if ((c->max_ops -= num_entries - entry) <= 0)
|
||||
return_trace (false);
|
||||
{ /* Sweep new entries. */
|
||||
const Entry<Extra> *stop = &entries[num_entries];
|
||||
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
|
||||
{
|
||||
int newState = new_state (p->newState);
|
||||
min_state = hb_min (min_state, newState);
|
||||
max_state = hb_max (max_state, newState);
|
||||
}
|
||||
entry = num_entries;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_entries_out)
|
||||
*num_entries_out = num_entries;
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT nClasses; /* Number of classes, which is the number of indices
|
||||
* in a single line in the state array. */
|
||||
NNOffsetTo<ClassType, HBUINT>
|
||||
classTable; /* Offset to the class table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
|
||||
stateArrayTable;/* Offset to the state array. */
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
|
||||
entryTable; /* Offset to the entry array. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
|
||||
};
|
||||
|
||||
template <typename HBUCHAR>
|
||||
struct ClassTable
|
||||
{
|
||||
unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
|
||||
{
|
||||
unsigned int i = glyph_id - firstGlyph;
|
||||
return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
|
||||
}
|
||||
unsigned int get_class (hb_codepoint_t glyph_id,
|
||||
unsigned int num_glyphs HB_UNUSED,
|
||||
unsigned int outOfRange) const
|
||||
{
|
||||
return get_class (glyph_id, outOfRange);
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && classArray.sanitize (c));
|
||||
}
|
||||
protected:
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
|
||||
* firstGlyph). */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, classArray);
|
||||
};
|
||||
|
||||
struct ObsoleteTypes
|
||||
{
|
||||
static constexpr bool extended = false;
|
||||
typedef HBUINT16 HBUINT;
|
||||
typedef HBUINT8 HBUSHORT;
|
||||
typedef ClassTable<HBUINT8> ClassTypeNarrow;
|
||||
typedef ClassTable<HBUINT16> ClassTypeWide;
|
||||
|
||||
template <typename T>
|
||||
static unsigned int offsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return (offset - ((const char *) array - (const char *) base)) / T::static_size;
|
||||
}
|
||||
template <typename T>
|
||||
static unsigned int byteOffsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return offsetToIndex (offset, base, array);
|
||||
}
|
||||
template <typename T>
|
||||
static unsigned int wordOffsetToIndex (unsigned int offset,
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return offsetToIndex (2 * offset, base, array);
|
||||
}
|
||||
};
|
||||
struct ExtendedTypes
|
||||
{
|
||||
static constexpr bool extended = true;
|
||||
typedef HBUINT32 HBUINT;
|
||||
typedef HBUINT16 HBUSHORT;
|
||||
typedef Lookup<HBUINT16> ClassTypeNarrow;
|
||||
typedef Lookup<HBUINT16> ClassTypeWide;
|
||||
|
||||
template <typename T>
|
||||
static unsigned int offsetToIndex (unsigned int offset,
|
||||
const void *base HB_UNUSED,
|
||||
const T *array HB_UNUSED)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
template <typename T>
|
||||
static unsigned int byteOffsetToIndex (unsigned int offset,
|
||||
const void *base HB_UNUSED,
|
||||
const T *array HB_UNUSED)
|
||||
{
|
||||
return offset / 2;
|
||||
}
|
||||
template <typename T>
|
||||
static unsigned int wordOffsetToIndex (unsigned int offset,
|
||||
const void *base HB_UNUSED,
|
||||
const T *array HB_UNUSED)
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Types, typename EntryData>
|
||||
struct StateTableDriver
|
||||
{
|
||||
StateTableDriver (const StateTable<Types, EntryData> &machine_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_face_t *face_) :
|
||||
machine (machine_),
|
||||
buffer (buffer_),
|
||||
num_glyphs (face_->get_num_glyphs ()) {}
|
||||
|
||||
template <typename context_t>
|
||||
void drive (context_t *c)
|
||||
{
|
||||
if (!c->in_place)
|
||||
buffer->clear_output ();
|
||||
|
||||
int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
|
||||
for (buffer->idx = 0; buffer->successful;)
|
||||
{
|
||||
unsigned int klass = buffer->idx < buffer->len ?
|
||||
machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
|
||||
(unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
|
||||
DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
|
||||
const Entry<EntryData> &entry = machine.get_entry (state, klass);
|
||||
|
||||
/* Unsafe-to-break before this if not in state 0, as things might
|
||||
* go differently if we start from state 0 here.
|
||||
*
|
||||
* Ugh. The indexing here is ugly... */
|
||||
if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
|
||||
{
|
||||
/* If there's no action and we're just epsilon-transitioning to state 0,
|
||||
* safe to break. */
|
||||
if (c->is_actionable (this, entry) ||
|
||||
!(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
|
||||
entry.flags == context_t::DontAdvance))
|
||||
buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
|
||||
}
|
||||
|
||||
/* Unsafe-to-break if end-of-text would kick in here. */
|
||||
if (buffer->idx + 2 <= buffer->len)
|
||||
{
|
||||
const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
|
||||
if (c->is_actionable (this, end_entry))
|
||||
buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
|
||||
}
|
||||
|
||||
c->transition (this, entry);
|
||||
|
||||
state = machine.new_state (entry.newState);
|
||||
DEBUG_MSG (APPLY, nullptr, "s%d", state);
|
||||
|
||||
if (buffer->idx == buffer->len)
|
||||
break;
|
||||
|
||||
if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
|
||||
buffer->next_glyph ();
|
||||
}
|
||||
|
||||
if (!c->in_place)
|
||||
{
|
||||
for (; buffer->successful && buffer->idx < buffer->len;)
|
||||
buffer->next_glyph ();
|
||||
buffer->swap_buffers ();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
const StateTable<Types, EntryData> &machine;
|
||||
hb_buffer_t *buffer;
|
||||
unsigned int num_glyphs;
|
||||
};
|
||||
|
||||
|
||||
struct ankr;
|
||||
|
||||
struct hb_aat_apply_context_t :
|
||||
hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
|
||||
{
|
||||
const char *get_name () { return "APPLY"; }
|
||||
template <typename T>
|
||||
return_t dispatch (const T &obj) { return obj.apply (this); }
|
||||
static return_t default_return_value () { return false; }
|
||||
bool stop_sublookup_iteration (return_t r) const { return r; }
|
||||
|
||||
const hb_ot_shape_plan_t *plan;
|
||||
hb_font_t *font;
|
||||
hb_face_t *face;
|
||||
hb_buffer_t *buffer;
|
||||
hb_sanitize_context_t sanitizer;
|
||||
const ankr *ankr_table;
|
||||
|
||||
/* Unused. For debug tracing only. */
|
||||
unsigned int lookup_index;
|
||||
unsigned int debug_depth;
|
||||
|
||||
HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
|
||||
hb_font_t *font_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
|
||||
|
||||
HB_INTERNAL ~hb_aat_apply_context_t ();
|
||||
|
||||
HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
|
||||
|
||||
void set_lookup_index (unsigned int i) { lookup_index = i; }
|
||||
};
|
||||
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_COMMON_HH */
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_FEAT_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_FEAT_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
|
||||
/*
|
||||
* feat -- Feature Name
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6feat.html
|
||||
*/
|
||||
#define HB_AAT_TAG_feat HB_TAG('f','e','a','t')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct SettingName
|
||||
{
|
||||
friend struct FeatureName;
|
||||
|
||||
int cmp (hb_aat_layout_feature_selector_t key) const
|
||||
{ return (int) key - (int) setting; }
|
||||
|
||||
hb_aat_layout_feature_selector_t get_selector () const
|
||||
{ return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
|
||||
|
||||
hb_aat_layout_feature_selector_info_t get_info (hb_aat_layout_feature_selector_t default_selector) const
|
||||
{
|
||||
return {
|
||||
nameIndex,
|
||||
(hb_aat_layout_feature_selector_t) (unsigned int) setting,
|
||||
default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
|
||||
? (hb_aat_layout_feature_selector_t) (setting + 1)
|
||||
: default_selector,
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 setting; /* The setting. */
|
||||
NameID nameIndex; /* The name table index for the setting's name. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
DECLARE_NULL_NAMESPACE_BYTES (AAT, SettingName);
|
||||
|
||||
struct feat;
|
||||
|
||||
struct FeatureName
|
||||
{
|
||||
int cmp (hb_aat_layout_feature_type_t key) const
|
||||
{ return (int) key - (int) feature; }
|
||||
|
||||
enum {
|
||||
Exclusive = 0x8000, /* If set, the feature settings are mutually exclusive. */
|
||||
NotDefault = 0x4000, /* If clear, then the setting with an index of 0 in
|
||||
* the setting name array for this feature should
|
||||
* be taken as the default for the feature
|
||||
* (if one is required). If set, then bits 0-15 of this
|
||||
* featureFlags field contain the index of the setting
|
||||
* which is to be taken as the default. */
|
||||
IndexMask = 0x00FF /* If bits 30 and 31 are set, then these sixteen bits
|
||||
* indicate the index of the setting in the setting name
|
||||
* array for this feature which should be taken
|
||||
* as the default. */
|
||||
};
|
||||
|
||||
unsigned int get_selector_infos (unsigned int start_offset,
|
||||
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
|
||||
unsigned int *pdefault_index, /* OUT. May be NULL. */
|
||||
const void *base) const
|
||||
{
|
||||
hb_array_t< const SettingName> settings_table = (base+settingTableZ).as_array (nSettings);
|
||||
|
||||
static_assert (Index::NOT_FOUND_INDEX == HB_AAT_LAYOUT_NO_SELECTOR_INDEX, "");
|
||||
|
||||
hb_aat_layout_feature_selector_t default_selector = HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID;
|
||||
unsigned int default_index = Index::NOT_FOUND_INDEX;
|
||||
if (featureFlags & Exclusive)
|
||||
{
|
||||
default_index = (featureFlags & NotDefault) ? featureFlags & IndexMask : 0;
|
||||
default_selector = settings_table[default_index].get_selector ();
|
||||
}
|
||||
if (pdefault_index)
|
||||
*pdefault_index = default_index;
|
||||
|
||||
if (selectors_count)
|
||||
{
|
||||
+ settings_table.sub_array (start_offset, selectors_count)
|
||||
| hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
|
||||
| hb_sink (hb_array (selectors, *selectors_count))
|
||||
;
|
||||
}
|
||||
return settings_table.length;
|
||||
}
|
||||
|
||||
hb_aat_layout_feature_type_t get_feature_type () const
|
||||
{ return (hb_aat_layout_feature_type_t) (unsigned int) feature; }
|
||||
|
||||
hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
(base+settingTableZ).sanitize (c, nSettings)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 feature; /* Feature type. */
|
||||
HBUINT16 nSettings; /* The number of records in the setting name array. */
|
||||
LOffsetTo<UnsizedArrayOf<SettingName>, false>
|
||||
settingTableZ; /* Offset in bytes from the beginning of this table to
|
||||
* this feature's setting name array. The actual type of
|
||||
* record this offset refers to will depend on the
|
||||
* exclusivity value, as described below. */
|
||||
HBUINT16 featureFlags; /* Single-bit flags associated with the feature type. */
|
||||
HBINT16 nameIndex; /* The name table index for the feature's name.
|
||||
* This index has values greater than 255 and
|
||||
* less than 32768. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
struct feat
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_feat;
|
||||
|
||||
bool has_data () const { return version.to_int (); }
|
||||
|
||||
unsigned int get_feature_types (unsigned int start_offset,
|
||||
unsigned int *count,
|
||||
hb_aat_layout_feature_type_t *features) const
|
||||
{
|
||||
if (count)
|
||||
{
|
||||
+ namesZ.as_array (featureNameCount).sub_array (start_offset, count)
|
||||
| hb_map (&FeatureName::get_feature_type)
|
||||
| hb_sink (hb_array (features, *count))
|
||||
;
|
||||
}
|
||||
return featureNameCount;
|
||||
}
|
||||
|
||||
const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
|
||||
{ return namesZ.bsearch (featureNameCount, feature_type); }
|
||||
|
||||
hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
|
||||
{ return get_feature (feature).get_feature_name_id (); }
|
||||
|
||||
unsigned int get_selector_infos (hb_aat_layout_feature_type_t feature_type,
|
||||
unsigned int start_offset,
|
||||
unsigned int *selectors_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
|
||||
unsigned int *default_index /* OUT. May be NULL. */) const
|
||||
{
|
||||
return get_feature (feature_type).get_selector_infos (start_offset, selectors_count, selectors,
|
||||
default_index, this);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version.major == 1 &&
|
||||
namesZ.sanitize (c, featureNameCount, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the feature name table
|
||||
* (0x00010000 for the current version). */
|
||||
HBUINT16 featureNameCount;
|
||||
/* The number of entries in the feature name array. */
|
||||
HBUINT16 reserved1; /* Reserved (set to zero). */
|
||||
HBUINT32 reserved2; /* Reserved (set to zero). */
|
||||
SortedUnsizedArrayOf<FeatureName>
|
||||
namesZ; /* The feature name array. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (12, namesZ);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_FEAT_TABLE_HH */
|
||||
|
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_JUST_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_JUST_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-ot-layout.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
#include "hb-aat-layout-morx-table.hh"
|
||||
|
||||
/*
|
||||
* just -- Justification
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6just.html
|
||||
*/
|
||||
#define HB_AAT_TAG_just HB_TAG('j','u','s','t')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
struct ActionSubrecordHeader
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
HBUINT16 actionClass; /* The JustClass value associated with this
|
||||
* ActionSubrecord. */
|
||||
HBUINT16 actionType; /* The type of postcompensation action. */
|
||||
HBUINT16 actionLength; /* Length of this ActionSubrecord record, which
|
||||
* must be a multiple of 4. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (6);
|
||||
};
|
||||
|
||||
struct DecompositionAction
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBFixed lowerLimit; /* If the distance factor is less than this value,
|
||||
* then the ligature is decomposed. */
|
||||
HBFixed upperLimit; /* If the distance factor is greater than this value,
|
||||
* then the ligature is decomposed. */
|
||||
HBUINT16 order; /* Numerical order in which this ligature will
|
||||
* be decomposed; you may want infrequent ligatures
|
||||
* to decompose before more frequent ones. The ligatures
|
||||
* on the line of text will decompose in increasing
|
||||
* value of this field. */
|
||||
ArrayOf<HBUINT16>
|
||||
decomposedglyphs;
|
||||
/* Number of 16-bit glyph indexes that follow;
|
||||
* the ligature will be decomposed into these glyphs.
|
||||
*
|
||||
* Array of decomposed glyphs. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (18, decomposedglyphs);
|
||||
};
|
||||
|
||||
struct UnconditionalAddGlyphAction
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBGlyphID addGlyph; /* Glyph that should be added if the distance factor
|
||||
* is growing. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct ConditionalAddGlyphAction
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBFixed substThreshold; /* Distance growth factor (in ems) at which
|
||||
* this glyph is replaced and the growth factor
|
||||
* recalculated. */
|
||||
HBGlyphID addGlyph; /* Glyph to be added as kashida. If this value is
|
||||
* 0xFFFF, no extra glyph will be added. Note that
|
||||
* generally when a glyph is added, justification
|
||||
* will need to be redone. */
|
||||
HBGlyphID substGlyph; /* Glyph to be substituted for this glyph if the
|
||||
* growth factor equals or exceeds the value of
|
||||
* substThreshold. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (14);
|
||||
};
|
||||
|
||||
struct DuctileGlyphAction
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
|
||||
* This would normally be 0x64756374 ('duct'),
|
||||
* but you may use any axis the font contains. */
|
||||
HBFixed minimumLimit; /* The lowest value for the ductility axis tha
|
||||
* still yields an acceptable appearance. Normally
|
||||
* this will be 1.0. */
|
||||
HBFixed noStretchValue; /* This is the default value that corresponds to
|
||||
* no change in appearance. Normally, this will
|
||||
* be 1.0. */
|
||||
HBFixed maximumLimit; /* The highest value for the ductility axis that
|
||||
* still yields an acceptable appearance. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (22);
|
||||
};
|
||||
|
||||
struct RepeatedAddGlyphAction
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBUINT16 flags; /* Currently unused; set to 0. */
|
||||
HBGlyphID glyph; /* Glyph that should be added if the distance factor
|
||||
* is growing. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (10);
|
||||
};
|
||||
|
||||
struct ActionSubrecord
|
||||
{
|
||||
unsigned int get_length () const { return u.header.actionLength; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
|
||||
switch (u.header.actionType)
|
||||
{
|
||||
case 0: return_trace (u.decompositionAction.sanitize (c));
|
||||
case 1: return_trace (u.unconditionalAddGlyphAction.sanitize (c));
|
||||
case 2: return_trace (u.conditionalAddGlyphAction.sanitize (c));
|
||||
// case 3: return_trace (u.stretchGlyphAction.sanitize (c));
|
||||
case 4: return_trace (u.decompositionAction.sanitize (c));
|
||||
case 5: return_trace (u.decompositionAction.sanitize (c));
|
||||
default: return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
union {
|
||||
ActionSubrecordHeader header;
|
||||
DecompositionAction decompositionAction;
|
||||
UnconditionalAddGlyphAction unconditionalAddGlyphAction;
|
||||
ConditionalAddGlyphAction conditionalAddGlyphAction;
|
||||
/* StretchGlyphAction stretchGlyphAction; -- Not supported by CoreText */
|
||||
DuctileGlyphAction ductileGlyphAction;
|
||||
RepeatedAddGlyphAction repeatedAddGlyphAction;
|
||||
} u; /* Data. The format of this data depends on
|
||||
* the value of the actionType field. */
|
||||
public:
|
||||
DEFINE_SIZE_UNION (6, header);
|
||||
};
|
||||
|
||||
struct PostcompensationActionChain
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
|
||||
unsigned int offset = min_size;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
const ActionSubrecord& subrecord = StructAtOffset<ActionSubrecord> (this, offset);
|
||||
if (unlikely (!subrecord.sanitize (c))) return_trace (false);
|
||||
offset += subrecord.get_length ();
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT32 count;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
struct JustWidthDeltaEntry
|
||||
{
|
||||
enum Flags
|
||||
{
|
||||
Reserved1 =0xE000,/* Reserved. You should set these bits to zero. */
|
||||
UnlimiteGap =0x1000,/* The glyph can take unlimited gap. When this
|
||||
* glyph participates in the justification process,
|
||||
* it and any other glyphs on the line having this
|
||||
* bit set absorb all the remaining gap. */
|
||||
Reserved2 =0x0FF0,/* Reserved. You should set these bits to zero. */
|
||||
Priority =0x000F /* The justification priority of the glyph. */
|
||||
};
|
||||
|
||||
enum Priority
|
||||
{
|
||||
Kashida = 0, /* Kashida priority. This is the highest priority
|
||||
* during justification. */
|
||||
Whitespace = 1, /* Whitespace priority. Any whitespace glyphs (as
|
||||
* identified in the glyph properties table) will
|
||||
* get this priority. */
|
||||
InterCharacter = 2, /* Inter-character priority. Give this to any
|
||||
* remaining glyphs. */
|
||||
NullPriority = 3 /* Null priority. You should set this priority for
|
||||
* glyphs that only participate in justification
|
||||
* after the above priorities. Normally all glyphs
|
||||
* have one of the previous three values. If you
|
||||
* don't want a glyph to participate in justification,
|
||||
* and you don't want to set its factors to zero,
|
||||
* you may instead assign it to the null priority. */
|
||||
};
|
||||
|
||||
protected:
|
||||
HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
|
||||
* glyph is permitted to grow on the left or top side. */
|
||||
HBFixed beforeShrinkLimit;
|
||||
/* The ratio by which the advance width of the
|
||||
* glyph is permitted to shrink on the left or top side. */
|
||||
HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
|
||||
* is permitted to shrink on the left or top side. */
|
||||
HBFixed afterShrinkLimit;
|
||||
/* The ratio by which the advance width of the glyph
|
||||
* is at most permitted to shrink on the right or
|
||||
* bottom side. */
|
||||
HBUINT16 growFlags; /* Flags controlling the grow case. */
|
||||
HBUINT16 shrinkFlags; /* Flags controlling the shrink case. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (20);
|
||||
};
|
||||
|
||||
struct WidthDeltaPair
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT32 justClass; /* The justification category associated
|
||||
* with the wdRecord field. Only 7 bits of
|
||||
* this field are used. (The other bits are
|
||||
* used as padding to guarantee longword
|
||||
* alignment of the following record). */
|
||||
JustWidthDeltaEntry
|
||||
wdRecord; /* The actual width delta record. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
};
|
||||
|
||||
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
|
||||
|
||||
struct JustificationCategory
|
||||
{
|
||||
typedef void EntryData;
|
||||
|
||||
enum Flags
|
||||
{
|
||||
SetMark =0x8000,/* If set, make the current glyph the marked
|
||||
* glyph. */
|
||||
DontAdvance =0x4000,/* If set, don't advance to the next glyph before
|
||||
* going to the new state. */
|
||||
MarkCategory =0x3F80,/* The justification category for the marked
|
||||
* glyph if nonzero. */
|
||||
CurrentCategory =0x007F /* The justification category for the current
|
||||
* glyph if nonzero. */
|
||||
};
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
morphHeader.sanitize (c) &&
|
||||
stHeader.sanitize (c)));
|
||||
}
|
||||
|
||||
protected:
|
||||
ChainSubtable<ObsoleteTypes>
|
||||
morphHeader; /* Metamorphosis-style subtable header. */
|
||||
StateTable<ObsoleteTypes, EntryData>
|
||||
stHeader; /* The justification insertion state table header */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (30);
|
||||
};
|
||||
|
||||
struct JustificationHeader
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
justClassTable.sanitize (c, base, base) &&
|
||||
wdcTable.sanitize (c, base) &&
|
||||
pcTable.sanitize (c, base) &&
|
||||
lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
OffsetTo<JustificationCategory>
|
||||
justClassTable; /* Offset to the justification category state table. */
|
||||
OffsetTo<WidthDeltaCluster>
|
||||
wdcTable; /* Offset from start of justification table to start
|
||||
* of the subtable containing the width delta factors
|
||||
* for the glyphs in your font.
|
||||
*
|
||||
* The width delta clusters table. */
|
||||
OffsetTo<PostcompensationActionChain>
|
||||
pcTable; /* Offset from start of justification table to start
|
||||
* of postcompensation subtable (set to zero if none).
|
||||
*
|
||||
* The postcompensation subtable, if present in the font. */
|
||||
Lookup<OffsetTo<WidthDeltaCluster>>
|
||||
lookupTable; /* Lookup table associating glyphs with width delta
|
||||
* clusters. See the description of Width Delta Clusters
|
||||
* table for details on how to interpret the lookup values. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
struct just
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_just;
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version.major == 1 &&
|
||||
horizData.sanitize (c, this, this) &&
|
||||
vertData.sanitize (c, this, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version of the justification table
|
||||
* (0x00010000u for version 1.0). */
|
||||
HBUINT16 format; /* Format of the justification table (set to 0). */
|
||||
OffsetTo<JustificationHeader>
|
||||
horizData; /* Byte offset from the start of the justification table
|
||||
* to the header for tables that contain justification
|
||||
* information for horizontal text.
|
||||
* If you are not including this information,
|
||||
* store 0. */
|
||||
OffsetTo<JustificationHeader>
|
||||
vertData; /* ditto, vertical */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (10);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_JUST_TABLE_HH */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_LCAR_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-aat-layout-common.hh"
|
||||
|
||||
/*
|
||||
* lcar -- Ligature caret
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
|
||||
*/
|
||||
#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
typedef ArrayOf<HBINT16> LigCaretClassEntry;
|
||||
|
||||
struct lcarFormat0
|
||||
{
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */,
|
||||
const void *base) const
|
||||
{
|
||||
const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
|
||||
font->face->get_num_glyphs ());
|
||||
const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
|
||||
for (unsigned int i = 0; i < arr.length; ++i)
|
||||
caret_array[i] = font->em_scale_dir (arr[i], direction);
|
||||
}
|
||||
return array.len;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<LigCaretClassEntry>>
|
||||
lookupTable; /* data Lookup table associating glyphs */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct lcarFormat1
|
||||
{
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */,
|
||||
const void *base) const
|
||||
{
|
||||
const OffsetTo<LigCaretClassEntry>* entry_offset = lookupTable.get_value (glyph,
|
||||
font->face->get_num_glyphs ());
|
||||
const LigCaretClassEntry& array = entry_offset ? base+*entry_offset : Null (LigCaretClassEntry);
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
|
||||
for (unsigned int i = 0; i < arr.length; ++i)
|
||||
{
|
||||
hb_position_t x = 0, y = 0;
|
||||
font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
|
||||
caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
|
||||
}
|
||||
}
|
||||
return array.len;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<LigCaretClassEntry>>
|
||||
lookupTable; /* data Lookup table associating glyphs */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct lcar
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
|
||||
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */) const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_lig_carets (font, direction, glyph, start_offset,
|
||||
caret_count, caret_array, this);
|
||||
case 1: return u.format1.get_lig_carets (font, direction, glyph, start_offset,
|
||||
caret_count, caret_array, this);
|
||||
default:if (caret_count) *caret_count = 0; return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this) || version.major != 1))
|
||||
return_trace (false);
|
||||
|
||||
switch (format) {
|
||||
case 0: return_trace (u.format0.sanitize (c, this));
|
||||
case 1: return_trace (u.format1.sanitize (c, this));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the ligature caret table */
|
||||
HBUINT16 format; /* Format of the ligature caret table. */
|
||||
union {
|
||||
lcarFormat0 format0;
|
||||
lcarFormat0 format1;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_OPBD_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* opbd -- Optical Bounds
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
|
||||
*/
|
||||
#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
struct OpticalBounds
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
FWORD leftSide;
|
||||
FWORD topSide;
|
||||
FWORD rightSide;
|
||||
FWORD bottomSide;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct opbdFormat0
|
||||
{
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents, const void *base) const
|
||||
{
|
||||
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
|
||||
if (!bounds_offset) return false;
|
||||
const OpticalBounds &bounds = base+*bounds_offset;
|
||||
|
||||
if (extents)
|
||||
*extents = {
|
||||
font->em_scale_x (bounds.leftSide),
|
||||
font->em_scale_y (bounds.topSide),
|
||||
font->em_scale_x (bounds.rightSide),
|
||||
font->em_scale_y (bounds.bottomSide)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<OpticalBounds>>
|
||||
lookupTable; /* Lookup table associating glyphs with the four
|
||||
* int16 values for the left-side, top-side,
|
||||
* right-side, and bottom-side optical bounds. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct opbdFormat1
|
||||
{
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents, const void *base) const
|
||||
{
|
||||
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
|
||||
if (!bounds_offset) return false;
|
||||
const OpticalBounds &bounds = base+*bounds_offset;
|
||||
|
||||
hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
|
||||
if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
|
||||
{
|
||||
if (extents)
|
||||
*extents = {left, top, right, bottom};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<OpticalBounds>>
|
||||
lookupTable; /* Lookup table associating glyphs with the four
|
||||
* int16 values for the left-side, top-side,
|
||||
* right-side, and bottom-side optical bounds. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct opbd
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
|
||||
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
|
||||
case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this) || version.major != 1))
|
||||
return_trace (false);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (u.format0.sanitize (c, this));
|
||||
case 1: return_trace (u.format1.sanitize (c, this));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the optical bounds
|
||||
* table (0x00010000 for the current version). */
|
||||
HBUINT16 format; /* Format of the optical bounds table.
|
||||
* Format 0 indicates distance and Format 1 indicates
|
||||
* control point. */
|
||||
union {
|
||||
opbdFormat0 format0;
|
||||
opbdFormat1 format1;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_TRAK_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_TRAK_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-ot-layout.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* trak -- Tracking
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
|
||||
*/
|
||||
#define HB_AAT_TAG_trak HB_TAG('t','r','a','k')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct TrackTableEntry
|
||||
{
|
||||
friend struct TrackData;
|
||||
|
||||
float get_track_value () const { return track.to_float (); }
|
||||
|
||||
int get_value (const void *base, unsigned int index,
|
||||
unsigned int table_size) const
|
||||
{ return (base+valuesZ).as_array (table_size)[index]; }
|
||||
|
||||
public:
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base,
|
||||
unsigned int table_size) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
(valuesZ.sanitize (c, base, table_size))));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBFixed track; /* Track value for this record. */
|
||||
NameID trackNameID; /* The 'name' table index for this track.
|
||||
* (a short word or phrase like "loose"
|
||||
* or "very tight") */
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD>>
|
||||
valuesZ; /* Offset from start of tracking table to
|
||||
* per-size tracking values for this track. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct TrackData
|
||||
{
|
||||
float interpolate_at (unsigned int idx,
|
||||
float target_size,
|
||||
const TrackTableEntry &trackTableEntry,
|
||||
const void *base) const
|
||||
{
|
||||
unsigned int sizes = nSizes;
|
||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
|
||||
float s0 = size_table[idx].to_float ();
|
||||
float s1 = size_table[idx + 1].to_float ();
|
||||
float t = unlikely (s0 == s1) ? 0.f : (target_size - s0) / (s1 - s0);
|
||||
return t * trackTableEntry.get_value (base, idx + 1, sizes) +
|
||||
(1.f - t) * trackTableEntry.get_value (base, idx, sizes);
|
||||
}
|
||||
|
||||
int get_tracking (const void *base, float ptem) const
|
||||
{
|
||||
/*
|
||||
* Choose track.
|
||||
*/
|
||||
const TrackTableEntry *trackTableEntry = nullptr;
|
||||
unsigned int count = nTracks;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
/* Note: Seems like the track entries are sorted by values. But the
|
||||
* spec doesn't explicitly say that. It just mentions it in the example. */
|
||||
|
||||
/* For now we only seek for track entries with zero tracking value */
|
||||
|
||||
if (trackTable[i].get_track_value () == 0.f)
|
||||
{
|
||||
trackTableEntry = &trackTable[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!trackTableEntry) return 0.;
|
||||
|
||||
/*
|
||||
* Choose size.
|
||||
*/
|
||||
unsigned int sizes = nSizes;
|
||||
if (!sizes) return 0.;
|
||||
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
||||
|
||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
unsigned int size_index;
|
||||
for (size_index = 0; size_index < sizes - 1; size_index++)
|
||||
if (size_table[size_index].to_float () >= ptem)
|
||||
break;
|
||||
|
||||
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
|
||||
*trackTableEntry, base));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
sizeTable.sanitize (c, base, nSizes) &&
|
||||
trackTable.sanitize (c, nTracks, base, nSizes)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
|
||||
HBUINT16 nSizes; /* Number of point sizes included in this table. */
|
||||
LOffsetTo<UnsizedArrayOf<HBFixed>, false>
|
||||
sizeTable; /* Offset from start of the tracking table to
|
||||
* Array[nSizes] of size values.. */
|
||||
UnsizedArrayOf<TrackTableEntry>
|
||||
trackTable; /* Array[nTracks] of TrackTableEntry records. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, trackTable);
|
||||
};
|
||||
|
||||
struct trak
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_trak;
|
||||
|
||||
bool has_data () const { return version.to_int (); }
|
||||
|
||||
bool apply (hb_aat_apply_context_t *c) const
|
||||
{
|
||||
TRACE_APPLY (this);
|
||||
|
||||
hb_mask_t trak_mask = c->plan->trak_mask;
|
||||
|
||||
const float ptem = c->font->ptem;
|
||||
if (unlikely (ptem <= 0.f))
|
||||
return_trace (false);
|
||||
|
||||
hb_buffer_t *buffer = c->buffer;
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
{
|
||||
const TrackData &trackData = this+horizData;
|
||||
int tracking = trackData.get_tracking (this, ptem);
|
||||
hb_position_t offset_to_add = c->font->em_scalef_x (tracking / 2);
|
||||
hb_position_t advance_to_add = c->font->em_scalef_x (tracking);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
{
|
||||
if (!(buffer->info[start].mask & trak_mask)) continue;
|
||||
buffer->pos[start].x_advance += advance_to_add;
|
||||
buffer->pos[start].x_offset += offset_to_add;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const TrackData &trackData = this+vertData;
|
||||
int tracking = trackData.get_tracking (this, ptem);
|
||||
hb_position_t offset_to_add = c->font->em_scalef_y (tracking / 2);
|
||||
hb_position_t advance_to_add = c->font->em_scalef_y (tracking);
|
||||
foreach_grapheme (buffer, start, end)
|
||||
{
|
||||
if (!(buffer->info[start].mask & trak_mask)) continue;
|
||||
buffer->pos[start].y_advance += advance_to_add;
|
||||
buffer->pos[start].y_offset += offset_to_add;
|
||||
}
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version.major == 1 &&
|
||||
horizData.sanitize (c, this, this) &&
|
||||
vertData.sanitize (c, this, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version of the tracking table
|
||||
* (0x00010000u for version 1.0). */
|
||||
HBUINT16 format; /* Format of the tracking table (set to 0). */
|
||||
OffsetTo<TrackData>
|
||||
horizData; /* Offset from start of tracking table to TrackData
|
||||
* for horizontal text (or 0 if none). */
|
||||
OffsetTo<TrackData>
|
||||
vertData; /* Offset from start of tracking table to TrackData
|
||||
* for vertical text (or 0 if none). */
|
||||
HBUINT16 reserved; /* Reserved. Set to 0. */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_TRAK_TABLE_HH */
|
||||
|
|
@ -0,0 +1,388 @@
|
|||
/*
|
||||
* Copyright © 2017 Google, Inc.
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-aat-layout.hh"
|
||||
#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-ankr-table.hh"
|
||||
#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-feat-table.hh"
|
||||
#include "hb-aat-layout-just-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-kerx-table.hh"
|
||||
#include "hb-aat-layout-morx-table.hh"
|
||||
#include "hb-aat-layout-trak-table.hh"
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_apply_context_t
|
||||
*/
|
||||
|
||||
/* Note: This context is used for kerning, even without AAT, hence the condition. */
|
||||
#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
|
||||
|
||||
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
|
||||
hb_font_t *font_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_blob_t *blob) :
|
||||
plan (plan_),
|
||||
font (font_),
|
||||
face (font->face),
|
||||
buffer (buffer_),
|
||||
sanitizer (),
|
||||
ankr_table (&Null(AAT::ankr)),
|
||||
lookup_index (0),
|
||||
debug_depth (0)
|
||||
{
|
||||
sanitizer.init (blob);
|
||||
sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
||||
sanitizer.start_processing ();
|
||||
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
|
||||
}
|
||||
|
||||
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
|
||||
{ sanitizer.end_processing (); }
|
||||
|
||||
void
|
||||
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
|
||||
{ ankr_table = ankr_table_; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-aat-layout
|
||||
* @title: hb-aat-layout
|
||||
* @short_description: Apple Advanced Typography Layout
|
||||
* @include: hb-aat.h
|
||||
*
|
||||
* Functions for querying OpenType Layout features in the font face.
|
||||
**/
|
||||
|
||||
|
||||
#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
|
||||
|
||||
/* Table data courtesy of Apple. Converted from mnemonics to integers
|
||||
* when moving to this file. */
|
||||
static const hb_aat_feature_mapping_t feature_mappings[] =
|
||||
{
|
||||
{HB_TAG ('a','f','r','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
|
||||
{HB_TAG ('c','2','p','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
|
||||
{HB_TAG ('c','2','s','c'), HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE},
|
||||
{HB_TAG ('c','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF},
|
||||
{HB_TAG ('c','a','s','e'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF},
|
||||
{HB_TAG ('c','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF},
|
||||
{HB_TAG ('c','p','s','p'), HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF},
|
||||
{HB_TAG ('c','s','w','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF},
|
||||
{HB_TAG ('d','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF},
|
||||
{HB_TAG ('e','x','p','t'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('f','r','a','c'), HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS},
|
||||
{HB_TAG ('f','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('h','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('h','i','s','t'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
|
||||
{HB_TAG ('h','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF},
|
||||
{HB_TAG ('h','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF},
|
||||
{HB_TAG ('h','n','g','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION, HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION},
|
||||
{HB_TAG ('h','o','j','o'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('h','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('i','t','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF},
|
||||
{HB_TAG ('j','p','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('j','p','7','8'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('j','p','8','3'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('j','p','9','0'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('l','i','g','a'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF},
|
||||
{HB_TAG ('l','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2},
|
||||
{HB_TAG ('m','g','r','k'), HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF},
|
||||
{HB_TAG ('n','l','c','k'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('o','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS, (hb_aat_layout_feature_selector_t) 2},
|
||||
{HB_TAG ('o','r','d','n'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
|
||||
{HB_TAG ('p','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('p','c','a','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
|
||||
{HB_TAG ('p','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
|
||||
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
|
||||
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
|
||||
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
|
||||
{HB_TAG ('s','m','p','l'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('s','s','0','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF},
|
||||
{HB_TAG ('s','s','0','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF},
|
||||
{HB_TAG ('s','s','0','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF},
|
||||
{HB_TAG ('s','s','0','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF},
|
||||
{HB_TAG ('s','s','0','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF},
|
||||
{HB_TAG ('s','s','0','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF},
|
||||
{HB_TAG ('s','s','0','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF},
|
||||
{HB_TAG ('s','s','0','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF},
|
||||
{HB_TAG ('s','s','0','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF},
|
||||
{HB_TAG ('s','s','1','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF},
|
||||
{HB_TAG ('s','s','1','1'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF},
|
||||
{HB_TAG ('s','s','1','2'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF},
|
||||
{HB_TAG ('s','s','1','3'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF},
|
||||
{HB_TAG ('s','s','1','4'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF},
|
||||
{HB_TAG ('s','s','1','5'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF},
|
||||
{HB_TAG ('s','s','1','6'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF},
|
||||
{HB_TAG ('s','s','1','7'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF},
|
||||
{HB_TAG ('s','s','1','8'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF},
|
||||
{HB_TAG ('s','s','1','9'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF},
|
||||
{HB_TAG ('s','s','2','0'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF},
|
||||
{HB_TAG ('s','u','b','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
|
||||
{HB_TAG ('s','u','p','s'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
|
||||
{HB_TAG ('s','w','s','h'), HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF},
|
||||
{HB_TAG ('t','i','t','l'), HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS, HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS},
|
||||
{HB_TAG ('t','n','a','m'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('t','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
|
||||
{HB_TAG ('t','r','a','d'), HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE, HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS, (hb_aat_layout_feature_selector_t) 16},
|
||||
{HB_TAG ('t','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('u','n','i','c'), HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE, (hb_aat_layout_feature_selector_t) 14, (hb_aat_layout_feature_selector_t) 15},
|
||||
{HB_TAG ('v','a','l','t'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('v','e','r','t'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
|
||||
{HB_TAG ('v','h','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('v','k','n','a'), HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF},
|
||||
{HB_TAG ('v','p','a','l'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||
{HB_TAG ('v','r','t','2'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF},
|
||||
{HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
|
||||
};
|
||||
|
||||
const hb_aat_feature_mapping_t *
|
||||
hb_aat_layout_find_feature_mapping (hb_tag_t tag)
|
||||
{
|
||||
return (const hb_aat_feature_mapping_t *) hb_bsearch (&tag,
|
||||
feature_mappings,
|
||||
ARRAY_LENGTH (feature_mappings),
|
||||
sizeof (feature_mappings[0]),
|
||||
hb_aat_feature_mapping_t::cmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef HB_NO_AAT
|
||||
|
||||
/*
|
||||
* mort/morx/kerx/trak
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
|
||||
hb_aat_map_t *map)
|
||||
{
|
||||
const AAT::morx& morx = *mapper->face->table.morx;
|
||||
if (morx.has_data ())
|
||||
{
|
||||
morx.compile_flags (mapper, map);
|
||||
return;
|
||||
}
|
||||
|
||||
const AAT::mort& mort = *mapper->face->table.mort;
|
||||
if (mort.has_data ())
|
||||
{
|
||||
mort.compile_flags (mapper, map);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_layout_has_substitution:
|
||||
* @face:
|
||||
*
|
||||
* Returns:
|
||||
* Since: 2.3.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_substitution (hb_face_t *face)
|
||||
{
|
||||
return face->table.morx->has_data () ||
|
||||
face->table.mort->has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
|
||||
const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
|
||||
if (morx.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
|
||||
morx.apply (&c);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_blob_t *mort_blob = font->face->table.mort.get_blob ();
|
||||
const AAT::mort& mort = *mort_blob->as<AAT::mort> ();
|
||||
if (mort.has_data ())
|
||||
{
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
|
||||
mort.apply (&c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
unsigned int count = buffer->len;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pos = buffer->pos;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (info[i].codepoint == AAT::DELETED_GLYPH))
|
||||
pos[i].x_advance = pos[i].y_advance = pos[i].x_offset = pos[i].y_offset = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
is_deleted_glyph (const hb_glyph_info_t *info)
|
||||
{
|
||||
return info->codepoint == AAT::DELETED_GLYPH;
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph);
|
||||
}
|
||||
|
||||
/*
|
||||
* hb_aat_layout_has_positioning:
|
||||
* @face:
|
||||
*
|
||||
* Returns:
|
||||
* Since: 2.3.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_positioning (hb_face_t *face)
|
||||
{
|
||||
return face->table.kerx->has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
hb_blob_t *kerx_blob = font->face->table.kerx.get_blob ();
|
||||
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
|
||||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
|
||||
c.set_ankr_table (font->face->table.ankr.get ());
|
||||
kerx.apply (&c);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_layout_has_tracking:
|
||||
* @face:
|
||||
*
|
||||
* Returns:
|
||||
* Since: 2.3.0
|
||||
*/
|
||||
hb_bool_t
|
||||
hb_aat_layout_has_tracking (hb_face_t *face)
|
||||
{
|
||||
return face->table.trak->has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
const AAT::trak& trak = *font->face->table.trak;
|
||||
|
||||
AAT::hb_aat_apply_context_t c (plan, font, buffer);
|
||||
trak.apply (&c);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_aat_layout_get_feature_types:
|
||||
* @face: a face object
|
||||
* @start_offset: iteration's start offset
|
||||
* @feature_count:(inout) (allow-none): buffer size as input, filled size as output
|
||||
* @features: (out caller-allocates) (array length=feature_count): features buffer
|
||||
*
|
||||
* Return value: Number of all available feature types.
|
||||
*
|
||||
* Since: 2.2.0
|
||||
*/
|
||||
unsigned int
|
||||
hb_aat_layout_get_feature_types (hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */)
|
||||
{
|
||||
return face->table.feat->get_feature_types (start_offset, feature_count, features);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_aat_layout_feature_type_get_name_id:
|
||||
* @face: a face object
|
||||
* @feature_type: feature id
|
||||
*
|
||||
* Return value: Name ID index
|
||||
*
|
||||
* Since: 2.2.0
|
||||
*/
|
||||
hb_ot_name_id_t
|
||||
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
|
||||
hb_aat_layout_feature_type_t feature_type)
|
||||
{
|
||||
return face->table.feat->get_feature_name_id (feature_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_aat_layout_feature_type_get_selectors:
|
||||
* @face: a face object
|
||||
* @feature_type: feature id
|
||||
* @start_offset: iteration's start offset
|
||||
* @selector_count: (inout) (allow-none): buffer size as input, filled size as output
|
||||
* @selectors: (out caller-allocates) (array length=selector_count): settings buffer
|
||||
* @default_index: (out) (allow-none): index of default selector if any
|
||||
*
|
||||
* If upon return, @default_index is set to #HB_AAT_LAYOUT_NO_SELECTOR_INDEX, then
|
||||
* the feature type is non-exclusive. Otherwise, @default_index is the index of
|
||||
* the selector that is selected by default.
|
||||
*
|
||||
* Return value: Number of all available feature selectors.
|
||||
*
|
||||
* Since: 2.2.0
|
||||
*/
|
||||
unsigned int
|
||||
hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face,
|
||||
hb_aat_layout_feature_type_t feature_type,
|
||||
unsigned int start_offset,
|
||||
unsigned int *selector_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
|
||||
unsigned int *default_index /* OUT. May be NULL. */)
|
||||
{
|
||||
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,486 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_H_IN
|
||||
#error "Include <hb-aat.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_H
|
||||
#define HB_AAT_LAYOUT_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include "hb-ot.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* hb_aat_layout_feature_type_t:
|
||||
*
|
||||
*
|
||||
* Since: 2.2.0
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_INVALID = 0xFFFF,
|
||||
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CURISVE_CONNECTION = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION = 10,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS = 11,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE = 13,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS = 14,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS = 15,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE = 16,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES = 17,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE = 18,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS = 19,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE = 20,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE = 21,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING = 22,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION = 23,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE = 24,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE = 25,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE = 26,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE = 27,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA = 28,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE = 29,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE = 30,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE = 31,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN = 32,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT = 33,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA = 34,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES = 35,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES = 36,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE = 37,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE = 38,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103,
|
||||
|
||||
_HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
} hb_aat_layout_feature_type_t;
|
||||
|
||||
/**
|
||||
* hb_aat_layout_feature_selector_t:
|
||||
*
|
||||
*
|
||||
* Since: 2.2.0
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID = 0xFFFF,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALL_TYPOGRAPHIC */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_TYPE_FEATURES_OFF = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMMON_LIGATURES_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_RARE_LIGATURES_OFF = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_ON = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOGOS_OFF = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_ON = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_REBUS_PICTURES_OFF = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_ON = 10,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIPHTHONG_LIGATURES_OFF = 11,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_ON = 12,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SQUARED_LIGATURES_OFF = 13,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_ON = 14,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ABBREV_SQUARED_LIGATURES_OFF = 15,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_ON = 16,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SYMBOL_LIGATURES_OFF = 17,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_ON = 18,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_LIGATURES_OFF = 19,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_ON = 20,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HISTORICAL_LIGATURES_OFF = 21,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_UNCONNECTED = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARTIALLY_CONNECTED = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CURSIVE = 2,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_AND_LOWER_CASE = 0, /* deprecated */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_CAPS = 1, /* deprecated */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALL_LOWER_CASE = 2, /* deprecated */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS = 3, /* deprecated */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS = 4, /* deprecated */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INITIAL_CAPS_AND_SMALL_CAPS = 5, /* deprecated */
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_SUBSTITUTION */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUBSTITUTE_VERTICAL_FORMS_OFF = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LINGUISTIC_REARRANGEMENT */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINGUISTIC_REARRANGEMENT_OFF = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_NUMBERS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_NUMBERS = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_NUMBERS = 3,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_SMART_SWASH_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_INITIAL_SWASHES_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_WORD_FINAL_SWASHES_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_INITIAL_SWASHES_OFF = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_ON = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LINE_FINAL_SWASHES_OFF = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_ON = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NON_FINAL_SWASHES_OFF = 9,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DIACRITICS_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SHOW_DIACRITICS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIDE_DIACRITICS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECOMPOSE_DIACRITICS = 2,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SUPERIORS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INFERIORS = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ORDINALS = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS = 4,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_FRACTIONS */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_FRACTIONS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_VERTICAL_FRACTIONS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAGONAL_FRACTIONS = 2,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_OVERLAPPING_CHARACTERS_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PREVENT_OVERLAP_OFF = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHENS_TO_EM_DASH_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_EN_DASH_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_ON = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FORM_INTERROBANG_OFF = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_ON = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SMART_QUOTES_OFF = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_ON = 10,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIODS_TO_ELLIPSIS_OFF = 11,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_MATHEMATICAL_EXTRAS */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HYPHEN_TO_MINUS_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ASTERISK_TO_MULTIPLY_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASH_TO_DIVIDE_OFF = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_ON = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INEQUALITY_LIGATURES_OFF = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_ON = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPONENTS_OFF = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_ON = 10,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATHEMATICAL_GREEK_OFF = 11,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ORNAMENT_SETS_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ORNAMENTS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DINGBATS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PI_CHARACTERS = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FLEURONS = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DECORATIVE_BORDERS = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INTERNATIONAL_SYMBOLS = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_MATH_SYMBOLS = 6,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ALTERNATES = 0,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_DESIGN_COMPLEXITY_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL1 = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL2 = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL3 = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL4 = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DESIGN_LEVEL5 = 4,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLE_OPTIONS */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLE_OPTIONS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DISPLAY_TEXT = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ENGRAVED_TEXT = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ILLUMINATED_CAPS = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TITLING_CAPS = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TALL_CAPS = 5,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_SHAPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_CHARACTERS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SIMPLIFIED_CHARACTERS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1978_CHARACTERS = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1983_CHARACTERS = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS1990_CHARACTERS = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_ONE = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_TWO = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_THREE = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FOUR = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_ALT_FIVE = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_EXPERT_CHARACTERS = 10,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_JIS2004_CHARACTERS = 11,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HOJO_CHARACTERS = 12,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NLCCHARACTERS = 13,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRADITIONAL_NAMES_CHARACTERS = 14,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_CASE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_NUMBERS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_NUMBERS = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_MONOSPACED_TEXT = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_TEXT = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_THIRD_WIDTH_TEXT = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_PROPORTIONAL_TEXT = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALT_HALF_WIDTH_TEXT = 6,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_TRANSLITERATION */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_TRANSLITERATION = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HIRAGANA_TO_KATAKANA = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_KATAKANA_TO_HIRAGANA = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_KANA_TO_ROMANIZATION = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_HIRAGANA = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMANIZATION_TO_KATAKANA = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_ONE = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_TWO = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HANJA_TO_HANGUL_ALT_THREE = 9,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ANNOTATION_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_ANNOTATION = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_BOX_ANNOTATION = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROUNDED_BOX_ANNOTATION = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CIRCLE_ANNOTATION = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_CIRCLE_ANNOTATION = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PARENTHESIS_ANNOTATION = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PERIOD_ANNOTATION = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ROMAN_NUMERAL_ANNOTATION = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DIAMOND_ANNOTATION = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_BOX_ANNOTATION = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_INVERTED_ROUNDED_BOX_ANNOTATION= 10,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_KANA_SPACING_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_KANA = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_KANA = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_SPACING_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_IDEOGRAPHS = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_IDEOGRAPHS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_IDEOGRAPHS = 2,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UNICODE_DECOMPOSITION_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CANONICAL_COMPOSITION_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_COMPATIBILITY_COMPOSITION_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_TRANSCODING_COMPOSITION_OFF = 5,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_RUBY_KANA = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF instead */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON instead */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF = 3,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_SYMBOL_ALTERNATIVES_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_SYMBOL_ALTERNATIVES = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_ONE = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_TWO = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_THREE = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FOUR = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_SYMBOL_ALT_FIVE = 5,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_IDEOGRAPHIC_ALTERNATIVES_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_IDEOGRAPHIC_ALTERNATIVES = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_ONE = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_TWO = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_THREE = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FOUR = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_IDEOGRAPHIC_ALT_FIVE = 5,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_VERTICAL_ROMAN_PLACEMENT_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_CENTERED = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_VERTICAL_ROMAN_HBASELINE = 1,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ITALIC_CJK_ROMAN */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_CJK_ITALIC_ROMAN = 0, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF instead */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN = 1, /* deprecated - use HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON instead */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CJK_ITALIC_ROMAN_OFF = 3,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CASE_SENSITIVE_LAYOUT */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_LAYOUT_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CASE_SENSITIVE_SPACING_OFF = 3,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_ALTERNATE_KANA */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_HORIZ_KANA_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_ALTERNATE_VERT_KANA_OFF = 3,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_STYLISTIC_ALTERNATIVES */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_NO_STYLISTIC_ALTERNATES = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ONE_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWO_OFF = 5,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_ON = 6,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THREE_OFF = 7,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_ON = 8,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOUR_OFF = 9,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_ON = 10,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIVE_OFF = 11,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_ON = 12,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIX_OFF = 13,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_ON = 14,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVEN_OFF = 15,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_ON = 16,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHT_OFF = 17,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_ON = 18,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINE_OFF = 19,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_ON = 20,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TEN_OFF = 21,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_ON = 22,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_ELEVEN_OFF = 23,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_ON = 24,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWELVE_OFF = 25,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_ON = 26,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_THIRTEEN_OFF = 27,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_ON = 28,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FOURTEEN_OFF = 29,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_ON = 30,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_FIFTEEN_OFF = 31,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_ON = 32,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SIXTEEN_OFF = 33,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_ON = 34,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_SEVENTEEN_OFF = 35,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_ON = 36,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_EIGHTEEN_OFF = 37,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_ON = 38,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_NINETEEN_OFF = 39,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_ON = 40,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_STYLISTIC_ALT_TWENTY_OFF = 41,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CONTEXTUAL_ALTERNATIVES */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_ON = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_ALTERNATES_OFF = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_ON = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_SWASH_ALTERNATES_OFF = 3,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_ON = 4,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_CONTEXTUAL_SWASH_ALTERNATES_OFF= 5,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_PETITE_CAPS = 2,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_UPPER_CASE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_UPPER_CASE = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_SMALL_CAPS = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_UPPER_CASE_PETITE_CAPS = 2,
|
||||
|
||||
/* Selectors for #HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE */
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_HALF_WIDTH_CJK_ROMAN = 0,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_CJK_ROMAN = 1,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3,
|
||||
|
||||
_HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
} hb_aat_layout_feature_selector_t;
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_aat_layout_get_feature_types (hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *feature_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_type_t *features /* OUT. May be NULL. */);
|
||||
|
||||
HB_EXTERN hb_ot_name_id_t
|
||||
hb_aat_layout_feature_type_get_name_id (hb_face_t *face,
|
||||
hb_aat_layout_feature_type_t feature_type);
|
||||
|
||||
typedef struct hb_aat_layout_feature_selector_info_t
|
||||
{
|
||||
hb_ot_name_id_t name_id;
|
||||
hb_aat_layout_feature_selector_t enable;
|
||||
hb_aat_layout_feature_selector_t disable;
|
||||
/*< private >*/
|
||||
unsigned int reserved;
|
||||
} hb_aat_layout_feature_selector_info_t;
|
||||
|
||||
#define HB_AAT_LAYOUT_NO_SELECTOR_INDEX 0xFFFFu
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_aat_layout_feature_type_get_selector_infos (hb_face_t *face,
|
||||
hb_aat_layout_feature_type_t feature_type,
|
||||
unsigned int start_offset,
|
||||
unsigned int *selector_count, /* IN/OUT. May be NULL. */
|
||||
hb_aat_layout_feature_selector_info_t *selectors, /* OUT. May be NULL. */
|
||||
unsigned int *default_index /* OUT. May be NULL. */);
|
||||
|
||||
|
||||
/*
|
||||
* morx/mort
|
||||
*/
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_aat_layout_has_substitution (hb_face_t *face);
|
||||
|
||||
|
||||
/*
|
||||
* kerx
|
||||
*/
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_aat_layout_has_positioning (hb_face_t *face);
|
||||
|
||||
|
||||
/*
|
||||
* trak
|
||||
*/
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_aat_layout_has_tracking (hb_face_t *face);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_H */
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright © 2017 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_HH
|
||||
#define HB_AAT_LAYOUT_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-ot-shape.hh"
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
struct hb_aat_feature_mapping_t
|
||||
{
|
||||
hb_tag_t otFeatureTag;
|
||||
hb_aat_layout_feature_type_t aatFeatureType;
|
||||
hb_aat_layout_feature_selector_t selectorToEnable;
|
||||
hb_aat_layout_feature_selector_t selectorToDisable;
|
||||
|
||||
HB_INTERNAL static int cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
hb_tag_t key = * (unsigned int *) key_;
|
||||
const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
|
||||
return key < entry->otFeatureTag ? -1 :
|
||||
key > entry->otFeatureTag ? 1 :
|
||||
0;
|
||||
}
|
||||
};
|
||||
|
||||
HB_INTERNAL const hb_aat_feature_mapping_t *
|
||||
hb_aat_layout_find_feature_mapping (hb_tag_t tag);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
|
||||
hb_aat_map_t *map);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL void
|
||||
hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_HH */
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LTAG_TABLE_HH
|
||||
#define HB_AAT_LTAG_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* ltag -- Language Tag
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6ltag.html
|
||||
*/
|
||||
#define HB_AAT_TAG_ltag HB_TAG('l','t','a','g')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
|
||||
struct FTStringRange
|
||||
{
|
||||
friend struct ltag;
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && (base+tag).sanitize (c, length));
|
||||
}
|
||||
|
||||
protected:
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
tag; /* Offset from the start of the table to
|
||||
* the beginning of the string */
|
||||
HBUINT16 length; /* String length (in bytes) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
struct ltag
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_ltag;
|
||||
|
||||
hb_language_t get_language (unsigned int i) const
|
||||
{
|
||||
const FTStringRange &range = tagRanges[i];
|
||||
return hb_language_from_string ((const char *) (this+range.tag).arrayZ,
|
||||
range.length);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version >= 1 &&
|
||||
tagRanges.sanitize (c, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT32 version; /* Table version; currently 1 */
|
||||
HBUINT32 flags; /* Table flags; currently none defined */
|
||||
LArrayOf<FTStringRange>
|
||||
tagRanges; /* Range for each tag's string */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (12, tagRanges);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LTAG_TABLE_HH */
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright © 2009,2010 Red Hat, Inc.
|
||||
* Copyright © 2010,2011,2013 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
|
||||
#include "hb-aat-map.hh"
|
||||
|
||||
#include "hb-aat-layout.hh"
|
||||
|
||||
|
||||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
||||
unsigned int value)
|
||||
{
|
||||
if (tag == HB_TAG ('a','a','l','t'))
|
||||
{
|
||||
feature_info_t *info = features.push();
|
||||
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
|
||||
info->setting = (hb_aat_layout_feature_selector_t) value;
|
||||
return;
|
||||
}
|
||||
|
||||
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
|
||||
if (!mapping) return;
|
||||
|
||||
feature_info_t *info = features.push();
|
||||
info->type = mapping->aatFeatureType;
|
||||
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
|
||||
}
|
||||
|
||||
void
|
||||
hb_aat_map_builder_t::compile (hb_aat_map_t &m)
|
||||
{
|
||||
/* Sort features and merge duplicates */
|
||||
if (features.length)
|
||||
{
|
||||
features.qsort ();
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 1; i < features.length; i++)
|
||||
if (features[i].type != features[j].type)
|
||||
features[++j] = features[i];
|
||||
features.shrink (j + 1);
|
||||
}
|
||||
|
||||
hb_aat_layout_compile_map (this, &m);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_MAP_HH
|
||||
#define HB_AAT_MAP_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
struct hb_aat_map_t
|
||||
{
|
||||
friend struct hb_aat_map_builder_t;
|
||||
|
||||
public:
|
||||
|
||||
void init ()
|
||||
{
|
||||
memset (this, 0, sizeof (*this));
|
||||
chain_flags.init ();
|
||||
}
|
||||
void fini () { chain_flags.fini (); }
|
||||
|
||||
public:
|
||||
hb_vector_t<hb_mask_t> chain_flags;
|
||||
};
|
||||
|
||||
struct hb_aat_map_builder_t
|
||||
{
|
||||
public:
|
||||
|
||||
HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_,
|
||||
const hb_segment_properties_t *props_ HB_UNUSED) :
|
||||
face (face_) {}
|
||||
|
||||
HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
|
||||
|
||||
HB_INTERNAL void compile (hb_aat_map_t &m);
|
||||
|
||||
public:
|
||||
struct feature_info_t
|
||||
{
|
||||
hb_aat_layout_feature_type_t type;
|
||||
hb_aat_layout_feature_selector_t setting;
|
||||
unsigned seq; /* For stable sorting only. */
|
||||
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
const feature_info_t *a = (const feature_info_t *) pa;
|
||||
const feature_info_t *b = (const feature_info_t *) pb;
|
||||
return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
|
||||
(a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
|
||||
}
|
||||
|
||||
int cmp (hb_aat_layout_feature_type_t ty) const
|
||||
{
|
||||
return (type != ty) ? (type < ty ? -1 : 1) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
hb_face_t *face;
|
||||
|
||||
public:
|
||||
hb_sorted_vector_t<feature_info_t> features;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_AAT_MAP_HH */
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_H
|
||||
#define HB_AAT_H
|
||||
#define HB_AAT_H_IN
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include "hb-aat-layout.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#undef HB_AAT_H_IN
|
||||
#endif /* HB_AAT_H */
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,382 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_ARRAY_HH
|
||||
#define HB_ARRAY_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-algs.hh"
|
||||
#include "hb-iter.hh"
|
||||
#include "hb-null.hh"
|
||||
|
||||
|
||||
template <typename Type>
|
||||
struct hb_sorted_array_t;
|
||||
|
||||
template <typename Type>
|
||||
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
{
|
||||
/*
|
||||
* Constructors.
|
||||
*/
|
||||
hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
|
||||
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
template <unsigned int length_>
|
||||
hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_with_fallback_t<hb_array_t, Type&> (),
|
||||
arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
|
||||
|
||||
/*
|
||||
* Iterator implementation.
|
||||
*/
|
||||
typedef Type& __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
Type& __item_at__ (unsigned i) const
|
||||
{
|
||||
if (unlikely (i >= length)) return CrapOrNull (Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
void __forward__ (unsigned n)
|
||||
{
|
||||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
backwards_length += n;
|
||||
arrayZ += n;
|
||||
}
|
||||
void __rewind__ (unsigned n)
|
||||
{
|
||||
if (unlikely (n > backwards_length))
|
||||
n = backwards_length;
|
||||
length += n;
|
||||
backwards_length -= n;
|
||||
arrayZ -= n;
|
||||
}
|
||||
unsigned __len__ () const { return length; }
|
||||
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
|
||||
* it's best if we can just compare arrayZ, though comparing contents is still fast,
|
||||
* but also would require that Type has operator==. As such, we optimize this operator
|
||||
* for range-based for loop and just compare arrayZ. No need to compare length, as we
|
||||
* assume we're only compared to .end(). */
|
||||
bool operator != (const hb_array_t& o) const
|
||||
{ return arrayZ != o.arrayZ; }
|
||||
|
||||
/* Extra operators.
|
||||
*/
|
||||
Type * operator & () const { return arrayZ; }
|
||||
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
|
||||
template <typename T> operator T * () const { return arrayZ; }
|
||||
|
||||
HB_INTERNAL bool operator == (const hb_array_t &o) const;
|
||||
|
||||
uint32_t hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++) {
|
||||
current = current * 31 + hb_hash (this->arrayZ[i]);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare, Sort, and Search.
|
||||
*/
|
||||
|
||||
/* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
|
||||
int cmp (const hb_array_t &a) const
|
||||
{
|
||||
if (length != a.length)
|
||||
return (int) a.length - (int) length;
|
||||
return hb_memcmp (a.arrayZ, arrayZ, get_size ());
|
||||
}
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
hb_array_t *a = (hb_array_t *) pa;
|
||||
hb_array_t *b = (hb_array_t *) pb;
|
||||
return b->cmp (*a);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Type *lsearch (const T &x, Type *not_found = nullptr)
|
||||
{
|
||||
unsigned int count = length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!this->arrayZ[i].cmp (x))
|
||||
return &this->arrayZ[i];
|
||||
return not_found;
|
||||
}
|
||||
template <typename T>
|
||||
const Type *lsearch (const T &x, const Type *not_found = nullptr) const
|
||||
{
|
||||
unsigned int count = length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!this->arrayZ[i].cmp (x))
|
||||
return &this->arrayZ[i];
|
||||
return not_found;
|
||||
}
|
||||
|
||||
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
|
||||
{
|
||||
if (likely (length))
|
||||
hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
|
||||
return hb_sorted_array_t<Type> (*this);
|
||||
}
|
||||
hb_sorted_array_t<Type> qsort ()
|
||||
{
|
||||
if (likely (length))
|
||||
hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
|
||||
return hb_sorted_array_t<Type> (*this);
|
||||
}
|
||||
void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
end = hb_min (end, length);
|
||||
assert (start <= end);
|
||||
if (likely (start < end))
|
||||
hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Other methods.
|
||||
*/
|
||||
|
||||
unsigned int get_size () const { return length * this->get_item_size (); }
|
||||
|
||||
hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
|
||||
{
|
||||
if (!start_offset && !seg_count)
|
||||
return *this;
|
||||
|
||||
unsigned int count = length;
|
||||
if (unlikely (start_offset > count))
|
||||
count = 0;
|
||||
else
|
||||
count -= start_offset;
|
||||
if (seg_count)
|
||||
count = *seg_count = hb_min (count, *seg_count);
|
||||
return hb_array_t (arrayZ + start_offset, count);
|
||||
}
|
||||
hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{ return sub_array (start_offset, &seg_count); }
|
||||
|
||||
hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
|
||||
|
||||
template <typename T,
|
||||
unsigned P = sizeof (Type),
|
||||
hb_enable_if (P == 1)>
|
||||
const T *as () const
|
||||
{ return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
|
||||
|
||||
template <typename T,
|
||||
unsigned P = sizeof (Type),
|
||||
hb_enable_if (P == 1)>
|
||||
bool in_range (const T *p, unsigned int size = T::static_size) const
|
||||
{
|
||||
return ((const char *) p) >= arrayZ
|
||||
&& ((const char *) p + size) <= arrayZ + length;
|
||||
}
|
||||
|
||||
/* Only call if you allocated the underlying array using malloc() or similar. */
|
||||
void free ()
|
||||
{ ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
|
||||
|
||||
template <typename hb_serialize_context_t>
|
||||
hb_array_t copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto* out = c->start_embed (arrayZ);
|
||||
if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
|
||||
return_trace (hb_array_t (out, length));
|
||||
}
|
||||
|
||||
template <typename hb_sanitize_context_t>
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return c->check_array (arrayZ, length); }
|
||||
|
||||
/*
|
||||
* Members
|
||||
*/
|
||||
|
||||
public:
|
||||
Type *arrayZ;
|
||||
unsigned int length;
|
||||
unsigned int backwards_length;
|
||||
};
|
||||
template <typename T> inline hb_array_t<T>
|
||||
hb_array (T *array, unsigned int length)
|
||||
{ return hb_array_t<T> (array, length); }
|
||||
template <typename T, unsigned int length_> inline hb_array_t<T>
|
||||
hb_array (T (&array_)[length_])
|
||||
{ return hb_array_t<T> (array_); }
|
||||
|
||||
enum hb_bfind_not_found_t
|
||||
{
|
||||
HB_BFIND_NOT_FOUND_DONT_STORE,
|
||||
HB_BFIND_NOT_FOUND_STORE,
|
||||
HB_BFIND_NOT_FOUND_STORE_CLOSEST,
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct hb_sorted_array_t :
|
||||
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
|
||||
hb_array_t<Type>
|
||||
{
|
||||
typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
|
||||
HB_ITER_USING (iter_base_t);
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
|
||||
hb_sorted_array_t () : hb_array_t<Type> () {}
|
||||
hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
|
||||
template <unsigned int length_>
|
||||
hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
|
||||
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_t<hb_sorted_array_t, Type&> (),
|
||||
hb_array_t<Type> (o) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ hb_array_t<Type> (*this) = o; return *this; }
|
||||
|
||||
/* Iterator implementation. */
|
||||
bool operator != (const hb_sorted_array_t& o) const
|
||||
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
|
||||
|
||||
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
|
||||
{ return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
|
||||
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{ return sub_array (start_offset, &seg_count); }
|
||||
|
||||
hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
|
||||
|
||||
template <typename T>
|
||||
Type *bsearch (const T &x, Type *not_found = nullptr)
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &this->arrayZ[i] : not_found;
|
||||
}
|
||||
template <typename T>
|
||||
const Type *bsearch (const T &x, const Type *not_found = nullptr) const
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &this->arrayZ[i] : not_found;
|
||||
}
|
||||
template <typename T>
|
||||
bool bfind (const T &x, unsigned int *i = nullptr,
|
||||
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
{
|
||||
int min = 0, max = (int) this->length - 1;
|
||||
const Type *array = this->arrayZ;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
int c = array[mid].cmp (x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
if (i)
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (i)
|
||||
{
|
||||
switch (not_found)
|
||||
{
|
||||
case HB_BFIND_NOT_FOUND_DONT_STORE:
|
||||
break;
|
||||
|
||||
case HB_BFIND_NOT_FOUND_STORE:
|
||||
*i = to_store;
|
||||
break;
|
||||
|
||||
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
|
||||
if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
template <typename T> inline hb_sorted_array_t<T>
|
||||
hb_sorted_array (T *array, unsigned int length)
|
||||
{ return hb_sorted_array_t<T> (array, length); }
|
||||
template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
|
||||
hb_sorted_array (T (&array_)[length_])
|
||||
{ return hb_sorted_array_t<T> (array_); }
|
||||
|
||||
template <typename T>
|
||||
bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
|
||||
{
|
||||
if (o.length != this->length) return false;
|
||||
for (unsigned int i = 0; i < this->length; i++) {
|
||||
if (this->arrayZ[i] != o.arrayZ[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
|
||||
|
||||
template <>
|
||||
inline uint32_t hb_array_t<const char>::hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++)
|
||||
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
|
||||
return current;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t hb_array_t<const unsigned char>::hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++)
|
||||
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
typedef hb_array_t<const char> hb_bytes_t;
|
||||
typedef hb_array_t<const unsigned char> hb_ubytes_t;
|
||||
|
||||
|
||||
|
||||
#endif /* HB_ARRAY_HH */
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2007 Chris Wilson
|
||||
* Copyright © 2009,2010 Red Hat, Inc.
|
||||
* Copyright © 2011,2012 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_ATOMIC_PRIVATE_HH
|
||||
#define HB_ATOMIC_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
|
||||
/* atomic_int */
|
||||
|
||||
/* We need external help for these */
|
||||
|
||||
#if defined(hb_atomic_int_impl_add) \
|
||||
&& defined(hb_atomic_ptr_impl_get) \
|
||||
&& defined(hb_atomic_ptr_impl_cmpexch)
|
||||
|
||||
/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier
|
||||
* properly. As such, define a function to wrap the whole
|
||||
* thing. */
|
||||
static inline void _HBMemoryBarrier (void) {
|
||||
#if !defined(MemoryBarrier)
|
||||
long dummy = 0;
|
||||
InterlockedExchange (&dummy, 1);
|
||||
#else
|
||||
MemoryBarrier ();
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef LONG hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (_HBMemoryBarrier (), (void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(__APPLE__)
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
#ifdef __MAC_OS_X_MIN_REQUIRED
|
||||
#include <AvailabilityMacros.h>
|
||||
#elif defined(__IPHONE_OS_MIN_REQUIRED)
|
||||
#include <Availability.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef int32_t hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P))
|
||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
|
||||
#else
|
||||
#if __ppc64__ || __x86_64__ || __aarch64__
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (void *) (O), (int64_t) (void *) (N), (int64_t*) (P))
|
||||
#else
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (void *) (O), (int32_t) (void *) (N), (int32_t*) (P))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add (&(AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (void *) (__sync_synchronize (), *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
|
||||
|
||||
#include <atomic.h>
|
||||
#include <mbarrier.h>
|
||||
|
||||
typedef unsigned int hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(_AIX) && defined(__IBMCPP__)
|
||||
|
||||
#include <builtins.h>
|
||||
|
||||
|
||||
static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) {
|
||||
__lwsync();
|
||||
int result = __fetch_and_add(AI, V);
|
||||
__isync();
|
||||
return result;
|
||||
}
|
||||
static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) {
|
||||
__sync();
|
||||
int result = __compare_and_swaplp (P, &O, N);
|
||||
__sync();
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add (&(AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
|
||||
|
||||
#elif !defined(HB_NO_MT)
|
||||
|
||||
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
|
||||
|
||||
typedef volatile int hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) ((void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#else /* HB_NO_MT */
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define HB_ATOMIC_INT_IMPL_INIT(V) (V)
|
||||
#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) ((void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define HB_ATOMIC_INT_INIT(V) {HB_ATOMIC_INT_IMPL_INIT(V)}
|
||||
|
||||
struct hb_atomic_int_t
|
||||
{
|
||||
hb_atomic_int_impl_t v;
|
||||
|
||||
inline void set_unsafe (int v_) { v = v_; }
|
||||
inline int get_unsafe (void) const { return v; }
|
||||
inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), 1); }
|
||||
inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); }
|
||||
};
|
||||
|
||||
|
||||
#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P)
|
||||
#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
|
||||
|
||||
|
||||
#endif /* HB_ATOMIC_PRIVATE_HH */
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
/*
|
||||
* Copyright © 2007 Chris Wilson
|
||||
* Copyright © 2009,2010 Red Hat, Inc.
|
||||
* Copyright © 2011,2012 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Chris Wilson <chris@chris-wilson.co.uk>
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_ATOMIC_HH
|
||||
#define HB_ATOMIC_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-meta.hh"
|
||||
|
||||
|
||||
/*
|
||||
* Atomic integers and pointers.
|
||||
*/
|
||||
|
||||
|
||||
/* We need external help for these */
|
||||
|
||||
#if defined(hb_atomic_int_impl_add) \
|
||||
&& defined(hb_atomic_ptr_impl_get) \
|
||||
&& defined(hb_atomic_ptr_impl_cmpexch)
|
||||
|
||||
/* Defined externally, i.e. in config.h. */
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(__ATOMIC_ACQUIRE)
|
||||
|
||||
/* C++11-style GCC primitives. */
|
||||
|
||||
#define _hb_memory_barrier() __sync_synchronize ()
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
|
||||
#define hb_atomic_int_impl_set(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELEASE)
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED)
|
||||
#define hb_atomic_int_impl_get(AI) __atomic_load_n ((AI), __ATOMIC_ACQUIRE)
|
||||
|
||||
#define hb_atomic_ptr_impl_set_relaxed(P, V) __atomic_store_n ((P), (V), __ATOMIC_RELAXED)
|
||||
#define hb_atomic_ptr_impl_get_relaxed(P) __atomic_load_n ((P), __ATOMIC_RELAXED)
|
||||
#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_ACQUIRE)
|
||||
static inline bool
|
||||
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
{
|
||||
const void *O = O_; // Need lvalue
|
||||
return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
|
||||
}
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
|
||||
|
||||
#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
|
||||
|
||||
/* C++11 atomics. */
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#define _hb_memory_barrier() std::atomic_thread_fence(std::memory_order_ack_rel)
|
||||
#define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire)
|
||||
#define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release)
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
|
||||
|
||||
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
|
||||
static inline bool
|
||||
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
{
|
||||
const void *O = O_; // Need lvalue
|
||||
return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
|
||||
}
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static inline void _hb_memory_barrier ()
|
||||
{
|
||||
#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier. */
|
||||
LONG dummy = 0;
|
||||
InterlockedExchange (&dummy, 1);
|
||||
#else
|
||||
MemoryBarrier ();
|
||||
#endif
|
||||
}
|
||||
#define _hb_memory_barrier() _hb_memory_barrier ()
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((LONG *) (AI), (V))
|
||||
static_assert ((sizeof (LONG) == sizeof (int)), "");
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((P), (N), (O)) == (O))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
|
||||
|
||||
#define _hb_memory_barrier() __sync_synchronize ()
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_SOLARIS_ATOMIC_OPS)
|
||||
|
||||
#include <atomic.h>
|
||||
#include <mbarrier.h>
|
||||
|
||||
#define _hb_memory_r_barrier() __machine_r_barrier ()
|
||||
#define _hb_memory_w_barrier() __machine_w_barrier ()
|
||||
#define _hb_memory_barrier() __machine_rw_barrier ()
|
||||
|
||||
static inline int _hb_fetch_and_add (int *AI, int V)
|
||||
{
|
||||
_hb_memory_w_barrier ();
|
||||
int result = atomic_add_int_nv ((uint_t *) AI, V) - V;
|
||||
_hb_memory_r_barrier ();
|
||||
return result;
|
||||
}
|
||||
static inline bool _hb_compare_and_swap_ptr (void **P, void *O, void *N)
|
||||
{
|
||||
_hb_memory_w_barrier ();
|
||||
bool result = atomic_cas_ptr (P, O, N) == O;
|
||||
_hb_memory_r_barrier ();
|
||||
return result;
|
||||
}
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((P), (O), (N))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(__APPLE__)
|
||||
|
||||
#include <libkern/OSAtomic.h>
|
||||
#ifdef __MAC_OS_X_MIN_REQUIRED
|
||||
#include <AvailabilityMacros.h>
|
||||
#elif defined(__IPHONE_OS_MIN_REQUIRED)
|
||||
#include <Availability.h>
|
||||
#endif
|
||||
|
||||
#define _hb_memory_barrier() OSMemoryBarrier ()
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
|
||||
|
||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((O), (N), (P))
|
||||
#else
|
||||
#if __ppc64__ || __x86_64__ || __aarch64__
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap64Barrier ((int64_t) (O), (int64_t) (N), (int64_t*) (P))
|
||||
#else
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwap32Barrier ((int32_t) (O), (int32_t) (N), (int32_t*) (P))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))
|
||||
|
||||
#include <builtins.h>
|
||||
|
||||
#define _hb_memory_barrier() __lwsync ()
|
||||
|
||||
static inline int _hb_fetch_and_add (int *AI, int V)
|
||||
{
|
||||
_hb_memory_barrier ();
|
||||
int result = __fetch_and_add (AI, V);
|
||||
_hb_memory_barrier ();
|
||||
return result;
|
||||
}
|
||||
static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
|
||||
{
|
||||
_hb_memory_barrier ();
|
||||
bool result = __compare_and_swaplp (P, &O, N);
|
||||
_hb_memory_barrier ();
|
||||
return result;
|
||||
}
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long *) (P), (long) (O), (long) (N))
|
||||
static_assert ((sizeof (long) == sizeof (void *)), "");
|
||||
|
||||
|
||||
#elif defined(HB_NO_MT)
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier() do {} while (0)
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#error "Could not find any system to define atomic_int macros."
|
||||
#error "Check hb-atomic.hh for possible resolutions."
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _hb_memory_r_barrier
|
||||
#define _hb_memory_r_barrier() _hb_memory_barrier ()
|
||||
#endif
|
||||
#ifndef _hb_memory_w_barrier
|
||||
#define _hb_memory_w_barrier() _hb_memory_barrier ()
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_set_relaxed
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V))
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_get_relaxed
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (*(AI))
|
||||
#endif
|
||||
|
||||
#ifndef hb_atomic_ptr_impl_set_relaxed
|
||||
#define hb_atomic_ptr_impl_set_relaxed(P, V) (*(P) = (V))
|
||||
#endif
|
||||
#ifndef hb_atomic_ptr_impl_get_relaxed
|
||||
#define hb_atomic_ptr_impl_get_relaxed(P) (*(P))
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_set
|
||||
inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; }
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_get
|
||||
inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; }
|
||||
#endif
|
||||
#ifndef hb_atomic_ptr_impl_get
|
||||
inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; }
|
||||
#endif
|
||||
|
||||
|
||||
#define HB_ATOMIC_INT_INIT(V) {V}
|
||||
struct hb_atomic_int_t
|
||||
{
|
||||
void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
|
||||
void set (int v_) { hb_atomic_int_impl_set (&v, v_); }
|
||||
int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
|
||||
int get () const { return hb_atomic_int_impl_get (&v); }
|
||||
int inc () { return hb_atomic_int_impl_add (&v, 1); }
|
||||
int dec () { return hb_atomic_int_impl_add (&v, -1); }
|
||||
|
||||
int v;
|
||||
};
|
||||
|
||||
|
||||
#define HB_ATOMIC_PTR_INIT(V) {V}
|
||||
template <typename P>
|
||||
struct hb_atomic_ptr_t
|
||||
{
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
void init (T* v_ = nullptr) { set_relaxed (v_); }
|
||||
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
|
||||
T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); }
|
||||
T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); }
|
||||
bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); }
|
||||
|
||||
T * operator -> () const { return get (); }
|
||||
template <typename C> operator C * () const { return get (); }
|
||||
|
||||
T *v;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_ATOMIC_HH */
|
||||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright © 2019 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
#ifndef HB_BIMAP_HH
|
||||
#define HB_BIMAP_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-map.hh"
|
||||
|
||||
/* Bi-directional map */
|
||||
struct hb_bimap_t
|
||||
{
|
||||
hb_bimap_t () { init (); }
|
||||
~hb_bimap_t () { fini (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
forw_map.init ();
|
||||
back_map.init ();
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
forw_map.fini ();
|
||||
back_map.fini ();
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
forw_map.reset ();
|
||||
back_map.reset ();
|
||||
}
|
||||
|
||||
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
|
||||
|
||||
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
|
||||
{
|
||||
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
|
||||
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
|
||||
forw_map.set (lhs, rhs);
|
||||
back_map.set (rhs, lhs);
|
||||
}
|
||||
|
||||
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
|
||||
hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
|
||||
|
||||
hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
|
||||
bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
|
||||
|
||||
void del (hb_codepoint_t lhs)
|
||||
{
|
||||
back_map.del (get (lhs));
|
||||
forw_map.del (lhs);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
forw_map.clear ();
|
||||
back_map.clear ();
|
||||
}
|
||||
|
||||
bool is_empty () const { return get_population () == 0; }
|
||||
|
||||
unsigned int get_population () const { return forw_map.get_population (); }
|
||||
|
||||
protected:
|
||||
hb_map_t forw_map;
|
||||
hb_map_t back_map;
|
||||
};
|
||||
|
||||
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
|
||||
struct hb_inc_bimap_t : hb_bimap_t
|
||||
{
|
||||
hb_inc_bimap_t () { init (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
hb_bimap_t::init ();
|
||||
next_value = 0;
|
||||
}
|
||||
|
||||
/* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
|
||||
* Return the rhs value as the result.
|
||||
*/
|
||||
hb_codepoint_t add (hb_codepoint_t lhs)
|
||||
{
|
||||
hb_codepoint_t rhs = forw_map[lhs];
|
||||
if (rhs == HB_MAP_VALUE_INVALID)
|
||||
{
|
||||
rhs = next_value++;
|
||||
set (lhs, rhs);
|
||||
}
|
||||
return rhs;
|
||||
}
|
||||
|
||||
hb_codepoint_t skip ()
|
||||
{ return next_value++; }
|
||||
|
||||
hb_codepoint_t get_next_value () const
|
||||
{ return next_value; }
|
||||
|
||||
void add_set (const hb_set_t *set)
|
||||
{
|
||||
hb_codepoint_t i = HB_SET_VALUE_INVALID;
|
||||
while (hb_set_next (set, &i)) add (i);
|
||||
}
|
||||
|
||||
/* Create an identity map. */
|
||||
bool identity (unsigned int size)
|
||||
{
|
||||
clear ();
|
||||
for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
|
||||
return !in_error ();
|
||||
}
|
||||
|
||||
protected:
|
||||
static int cmp_id (const void* a, const void* b)
|
||||
{ return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; }
|
||||
|
||||
public:
|
||||
/* Optional: after finished adding all mappings in a random order,
|
||||
* reassign rhs to lhs so that they are in the same order. */
|
||||
void sort ()
|
||||
{
|
||||
hb_codepoint_t count = get_population ();
|
||||
hb_vector_t <hb_codepoint_t> work;
|
||||
work.resize (count);
|
||||
|
||||
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
|
||||
work[rhs] = back_map[rhs];
|
||||
|
||||
work.qsort (cmp_id);
|
||||
|
||||
clear ();
|
||||
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
|
||||
set (work[rhs], rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int next_value;
|
||||
};
|
||||
|
||||
#endif /* HB_BIMAP_HH */
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
|
|
@ -24,15 +25,20 @@
|
|||
* Red Hat Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
/* http://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html */
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 199309L
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1308
|
||||
* http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
* https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
|
||||
*/
|
||||
#if !defined(_POSIX_C_SOURCE) && !defined(_MSC_VER) && !defined(__NetBSD__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb.hh"
|
||||
#include "hb-blob.hh"
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#ifdef HAVE_UNISTD_H
|
||||
|
|
@ -42,35 +48,21 @@
|
|||
#endif /* HAVE_SYS_MMAN_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
struct hb_blob_t {
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
/**
|
||||
* SECTION: hb-blob
|
||||
* @title: hb-blob
|
||||
* @short_description: Binary data containers
|
||||
* @include: hb.h
|
||||
*
|
||||
* Blobs wrap a chunk of binary data to handle lifecycle management of data
|
||||
* while it is passed between client and HarfBuzz. Blobs are primarily used
|
||||
* to create font faces, but also to access font face tables, as well as
|
||||
* pass around other binary data.
|
||||
**/
|
||||
|
||||
bool immutable;
|
||||
|
||||
const char *data;
|
||||
unsigned int length;
|
||||
hb_memory_mode_t mode;
|
||||
|
||||
void *user_data;
|
||||
hb_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
|
||||
static bool _try_writable (hb_blob_t *blob);
|
||||
|
||||
static void
|
||||
_hb_blob_destroy_user_data (hb_blob_t *blob)
|
||||
{
|
||||
if (blob->destroy) {
|
||||
blob->destroy (blob->user_data);
|
||||
blob->user_data = nullptr;
|
||||
blob->destroy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_blob_create: (skip)
|
||||
|
|
@ -114,7 +106,7 @@ hb_blob_create (const char *data,
|
|||
|
||||
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
|
||||
blob->mode = HB_MEMORY_MODE_READONLY;
|
||||
if (!_try_writable (blob)) {
|
||||
if (!blob->try_make_writable ()) {
|
||||
hb_blob_destroy (blob);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
|
|
@ -156,13 +148,13 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
|||
{
|
||||
hb_blob_t *blob;
|
||||
|
||||
if (!length || offset >= parent->length)
|
||||
if (!length || !parent || offset >= parent->length)
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
hb_blob_make_immutable (parent);
|
||||
|
||||
blob = hb_blob_create (parent->data + offset,
|
||||
MIN (length, parent->length - offset),
|
||||
hb_min (length, parent->length - offset),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
hb_blob_reference (parent),
|
||||
_hb_blob_destroy);
|
||||
|
|
@ -170,6 +162,31 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
|||
return blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_blob_copy_writable_or_fail:
|
||||
* @blob: A blob.
|
||||
*
|
||||
* Makes a writable copy of @blob.
|
||||
*
|
||||
* Return value: New blob, or nullptr if allocation failed.
|
||||
*
|
||||
* Since: 1.8.0
|
||||
**/
|
||||
hb_blob_t *
|
||||
hb_blob_copy_writable_or_fail (hb_blob_t *blob)
|
||||
{
|
||||
blob = hb_blob_create (blob->data,
|
||||
blob->length,
|
||||
HB_MEMORY_MODE_DUPLICATE,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (unlikely (blob == hb_blob_get_empty ()))
|
||||
blob = nullptr;
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_blob_get_empty:
|
||||
*
|
||||
|
|
@ -182,22 +199,9 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
hb_blob_t *
|
||||
hb_blob_get_empty (void)
|
||||
hb_blob_get_empty ()
|
||||
{
|
||||
static const hb_blob_t _hb_blob_nil = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
||||
nullptr, /* data */
|
||||
0, /* length */
|
||||
HB_MEMORY_MODE_READONLY, /* mode */
|
||||
|
||||
nullptr, /* user_data */
|
||||
nullptr /* destroy */
|
||||
};
|
||||
|
||||
return const_cast<hb_blob_t *> (&_hb_blob_nil);
|
||||
return const_cast<hb_blob_t *> (&Null(hb_blob_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -222,7 +226,7 @@ hb_blob_reference (hb_blob_t *blob)
|
|||
* hb_blob_destroy: (skip)
|
||||
* @blob: a blob.
|
||||
*
|
||||
* Descreases the reference count on @blob, and if it reaches zero, destroys
|
||||
* Decreases the reference count on @blob, and if it reaches zero, destroys
|
||||
* @blob, freeing all memory, possibly calling the destroy-callback the blob
|
||||
* was created for if it has not been called already.
|
||||
*
|
||||
|
|
@ -235,7 +239,7 @@ hb_blob_destroy (hb_blob_t *blob)
|
|||
{
|
||||
if (!hb_object_destroy (blob)) return;
|
||||
|
||||
_hb_blob_destroy_user_data (blob);
|
||||
blob->fini_shallow ();
|
||||
|
||||
free (blob);
|
||||
}
|
||||
|
|
@ -248,7 +252,7 @@ hb_blob_destroy (hb_blob_t *blob)
|
|||
* @destroy: callback to call when @data is not needed anymore.
|
||||
* @replace: whether to replace an existing data with the same key.
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -267,9 +271,9 @@ hb_blob_set_user_data (hb_blob_t *blob,
|
|||
* @blob: a blob.
|
||||
* @key: key for data to get.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -285,24 +289,24 @@ hb_blob_get_user_data (hb_blob_t *blob,
|
|||
* hb_blob_make_immutable:
|
||||
* @blob: a blob.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
void
|
||||
hb_blob_make_immutable (hb_blob_t *blob)
|
||||
{
|
||||
if (hb_object_is_inert (blob))
|
||||
if (hb_object_is_immutable (blob))
|
||||
return;
|
||||
|
||||
blob->immutable = true;
|
||||
hb_object_make_immutable (blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_blob_is_immutable:
|
||||
* @blob: a blob.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: TODO
|
||||
*
|
||||
|
|
@ -311,7 +315,7 @@ hb_blob_make_immutable (hb_blob_t *blob)
|
|||
hb_bool_t
|
||||
hb_blob_is_immutable (hb_blob_t *blob)
|
||||
{
|
||||
return blob->immutable;
|
||||
return hb_object_is_immutable (blob);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -319,7 +323,7 @@ hb_blob_is_immutable (hb_blob_t *blob)
|
|||
* hb_blob_get_length:
|
||||
* @blob: a blob.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: the length of blob data in bytes.
|
||||
*
|
||||
|
|
@ -336,9 +340,9 @@ hb_blob_get_length (hb_blob_t *blob)
|
|||
* @blob: a blob.
|
||||
* @length: (out):
|
||||
*
|
||||
*
|
||||
*
|
||||
* Returns: (transfer none) (array length=length):
|
||||
*
|
||||
* Returns: (transfer none) (array length=length):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -370,7 +374,7 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length)
|
|||
char *
|
||||
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
|
||||
{
|
||||
if (!_try_writable (blob)) {
|
||||
if (!blob->try_make_writable ()) {
|
||||
if (length)
|
||||
*length = 0;
|
||||
|
||||
|
|
@ -384,8 +388,8 @@ hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length)
|
|||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
_try_make_writable_inplace_unix (hb_blob_t *blob)
|
||||
bool
|
||||
hb_blob_t::try_make_writable_inplace_unix ()
|
||||
{
|
||||
#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MPROTECT)
|
||||
uintptr_t pagesize = -1, mask, length;
|
||||
|
|
@ -400,25 +404,25 @@ _try_make_writable_inplace_unix (hb_blob_t *blob)
|
|||
#endif
|
||||
|
||||
if ((uintptr_t) -1L == pagesize) {
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "failed to get pagesize: %s", strerror (errno));
|
||||
DEBUG_MSG_FUNC (BLOB, this, "failed to get pagesize: %s", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "pagesize is %lu", (unsigned long) pagesize);
|
||||
DEBUG_MSG_FUNC (BLOB, this, "pagesize is %lu", (unsigned long) pagesize);
|
||||
|
||||
mask = ~(pagesize-1);
|
||||
addr = (const char *) (((uintptr_t) blob->data) & mask);
|
||||
length = (const char *) (((uintptr_t) blob->data + blob->length + pagesize-1) & mask) - addr;
|
||||
DEBUG_MSG_FUNC (BLOB, blob,
|
||||
addr = (const char *) (((uintptr_t) this->data) & mask);
|
||||
length = (const char *) (((uintptr_t) this->data + this->length + pagesize-1) & mask) - addr;
|
||||
DEBUG_MSG_FUNC (BLOB, this,
|
||||
"calling mprotect on [%p..%p] (%lu bytes)",
|
||||
addr, addr+length, (unsigned long) length);
|
||||
if (-1 == mprotect ((void *) addr, length, PROT_READ | PROT_WRITE)) {
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "mprotect failed: %s", strerror (errno));
|
||||
DEBUG_MSG_FUNC (BLOB, this, "mprotect failed: %s", strerror (errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
blob->mode = HB_MEMORY_MODE_WRITABLE;
|
||||
this->mode = HB_MEMORY_MODE_WRITABLE;
|
||||
|
||||
DEBUG_MSG_FUNC (BLOB, blob,
|
||||
DEBUG_MSG_FUNC (BLOB, this,
|
||||
"successfully made [%p..%p] (%lu bytes) writable\n",
|
||||
addr, addr+length, (unsigned long) length);
|
||||
return true;
|
||||
|
|
@ -427,53 +431,249 @@ _try_make_writable_inplace_unix (hb_blob_t *blob)
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
_try_writable_inplace (hb_blob_t *blob)
|
||||
bool
|
||||
hb_blob_t::try_make_writable_inplace ()
|
||||
{
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "making writable inplace\n");
|
||||
DEBUG_MSG_FUNC (BLOB, this, "making writable inplace\n");
|
||||
|
||||
if (_try_make_writable_inplace_unix (blob))
|
||||
if (this->try_make_writable_inplace_unix ())
|
||||
return true;
|
||||
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "making writable -> FAILED\n");
|
||||
DEBUG_MSG_FUNC (BLOB, this, "making writable -> FAILED\n");
|
||||
|
||||
/* Failed to make writable inplace, mark that */
|
||||
blob->mode = HB_MEMORY_MODE_READONLY;
|
||||
this->mode = HB_MEMORY_MODE_READONLY;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
_try_writable (hb_blob_t *blob)
|
||||
bool
|
||||
hb_blob_t::try_make_writable ()
|
||||
{
|
||||
if (blob->immutable)
|
||||
if (hb_object_is_immutable (this))
|
||||
return false;
|
||||
|
||||
if (blob->mode == HB_MEMORY_MODE_WRITABLE)
|
||||
if (this->mode == HB_MEMORY_MODE_WRITABLE)
|
||||
return true;
|
||||
|
||||
if (blob->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && _try_writable_inplace (blob))
|
||||
if (this->mode == HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE && this->try_make_writable_inplace ())
|
||||
return true;
|
||||
|
||||
if (blob->mode == HB_MEMORY_MODE_WRITABLE)
|
||||
if (this->mode == HB_MEMORY_MODE_WRITABLE)
|
||||
return true;
|
||||
|
||||
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "current data is -> %p\n", blob->data);
|
||||
DEBUG_MSG_FUNC (BLOB, this, "current data is -> %p\n", this->data);
|
||||
|
||||
char *new_data;
|
||||
|
||||
new_data = (char *) malloc (blob->length);
|
||||
new_data = (char *) malloc (this->length);
|
||||
if (unlikely (!new_data))
|
||||
return false;
|
||||
|
||||
DEBUG_MSG_FUNC (BLOB, blob, "dupped successfully -> %p\n", blob->data);
|
||||
DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data);
|
||||
|
||||
memcpy (new_data, blob->data, blob->length);
|
||||
_hb_blob_destroy_user_data (blob);
|
||||
blob->mode = HB_MEMORY_MODE_WRITABLE;
|
||||
blob->data = new_data;
|
||||
blob->user_data = new_data;
|
||||
blob->destroy = free;
|
||||
memcpy (new_data, this->data, this->length);
|
||||
this->destroy_user_data ();
|
||||
this->mode = HB_MEMORY_MODE_WRITABLE;
|
||||
this->data = new_data;
|
||||
this->user_data = new_data;
|
||||
this->destroy = free;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mmap
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_OPEN
|
||||
#ifdef HAVE_MMAP
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
#else
|
||||
# ifndef O_BINARY
|
||||
# define O_BINARY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef MAP_NORESERVE
|
||||
# define MAP_NORESERVE 0
|
||||
#endif
|
||||
|
||||
struct hb_mapped_file_t
|
||||
{
|
||||
char *contents;
|
||||
unsigned long length;
|
||||
#ifdef _WIN32
|
||||
HANDLE mapping;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if (defined(HAVE_MMAP) || defined(_WIN32)) && !defined(HB_NO_MMAP)
|
||||
static void
|
||||
_hb_mapped_file_destroy (void *file_)
|
||||
{
|
||||
hb_mapped_file_t *file = (hb_mapped_file_t *) file_;
|
||||
#ifdef HAVE_MMAP
|
||||
munmap (file->contents, file->length);
|
||||
#elif defined(_WIN32)
|
||||
UnmapViewOfFile (file->contents);
|
||||
CloseHandle (file->mapping);
|
||||
#else
|
||||
assert (0); // If we don't have mmap we shouldn't reach here
|
||||
#endif
|
||||
|
||||
free (file);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_blob_create_from_file:
|
||||
* @file_name: font filename.
|
||||
*
|
||||
* Returns: A hb_blob_t pointer with the content of the file
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name)
|
||||
{
|
||||
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
|
||||
Allison Lortie permission but changed a lot to suit our need. */
|
||||
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
|
||||
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
|
||||
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||
|
||||
int fd = open (file_name, O_RDONLY | O_BINARY, 0);
|
||||
if (unlikely (fd == -1)) goto fail_without_close;
|
||||
|
||||
struct stat st;
|
||||
if (unlikely (fstat (fd, &st) == -1)) goto fail;
|
||||
|
||||
file->length = (unsigned long) st.st_size;
|
||||
file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
|
||||
MAP_PRIVATE | MAP_NORESERVE, fd, 0);
|
||||
|
||||
if (unlikely (file->contents == MAP_FAILED)) goto fail;
|
||||
|
||||
close (fd);
|
||||
|
||||
return hb_blob_create (file->contents, file->length,
|
||||
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
||||
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
||||
|
||||
fail:
|
||||
close (fd);
|
||||
fail_without_close:
|
||||
free (file);
|
||||
|
||||
#elif defined(_WIN32) && !defined(HB_NO_MMAP)
|
||||
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
|
||||
if (unlikely (!file)) return hb_blob_get_empty ();
|
||||
|
||||
HANDLE fd;
|
||||
unsigned int size = strlen (file_name) + 1;
|
||||
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
|
||||
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
|
||||
mbstowcs (wchar_file_name, file_name, size);
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
{
|
||||
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
|
||||
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
|
||||
ceparams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFFF;
|
||||
ceparams.dwFileFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0xFFF00000;
|
||||
ceparams.dwSecurityQosFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED & 0x000F0000;
|
||||
ceparams.lpSecurityAttributes = nullptr;
|
||||
ceparams.hTemplateFile = nullptr;
|
||||
fd = CreateFile2 (wchar_file_name, GENERIC_READ, FILE_SHARE_READ,
|
||||
OPEN_EXISTING, &ceparams);
|
||||
}
|
||||
#else
|
||||
fd = CreateFileW (wchar_file_name, GENERIC_READ, FILE_SHARE_READ, nullptr,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
|
||||
nullptr);
|
||||
#endif
|
||||
free (wchar_file_name);
|
||||
|
||||
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
{
|
||||
LARGE_INTEGER length;
|
||||
GetFileSizeEx (fd, &length);
|
||||
file->length = length.LowPart;
|
||||
file->mapping = CreateFileMappingFromApp (fd, nullptr, PAGE_READONLY, length.QuadPart, nullptr);
|
||||
}
|
||||
#else
|
||||
file->length = (unsigned long) GetFileSize (fd, nullptr);
|
||||
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
#endif
|
||||
if (unlikely (file->mapping == nullptr)) goto fail;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
|
||||
#else
|
||||
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
#endif
|
||||
if (unlikely (file->contents == nullptr)) goto fail;
|
||||
|
||||
CloseHandle (fd);
|
||||
return hb_blob_create (file->contents, file->length,
|
||||
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
|
||||
(hb_destroy_func_t) _hb_mapped_file_destroy);
|
||||
|
||||
fail:
|
||||
CloseHandle (fd);
|
||||
fail_without_close:
|
||||
free (file);
|
||||
|
||||
#endif
|
||||
|
||||
/* The following tries to read a file without knowing its size beforehand
|
||||
It's used as a fallback for systems without mmap or to read from pipes */
|
||||
unsigned long len = 0, allocated = BUFSIZ * 16;
|
||||
char *data = (char *) malloc (allocated);
|
||||
if (unlikely (data == nullptr)) return hb_blob_get_empty ();
|
||||
|
||||
FILE *fp = fopen (file_name, "rb");
|
||||
if (unlikely (fp == nullptr)) goto fread_fail_without_close;
|
||||
|
||||
while (!feof (fp))
|
||||
{
|
||||
if (allocated - len < BUFSIZ)
|
||||
{
|
||||
allocated *= 2;
|
||||
/* Don't allocate and go more than ~536MB, our mmap reader still
|
||||
can cover files like that but lets limit our fallback reader */
|
||||
if (unlikely (allocated > (2 << 28))) goto fread_fail;
|
||||
char *new_data = (char *) realloc (data, allocated);
|
||||
if (unlikely (new_data == nullptr)) goto fread_fail;
|
||||
data = new_data;
|
||||
}
|
||||
|
||||
unsigned long addition = fread (data + len, 1, allocated - len, fp);
|
||||
|
||||
int err = ferror (fp);
|
||||
#ifdef EINTR // armcc doesn't have it
|
||||
if (unlikely (err == EINTR)) continue;
|
||||
#endif
|
||||
if (unlikely (err)) goto fread_fail;
|
||||
|
||||
len += addition;
|
||||
}
|
||||
|
||||
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
|
||||
(hb_destroy_func_t) free);
|
||||
|
||||
fread_fail:
|
||||
fclose (fp);
|
||||
fread_fail_without_close:
|
||||
free (data);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
#endif /* !HB_NO_OPEN */
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ HB_BEGIN_DECLS
|
|||
* any such possibility, MODE_DUPLICATE should be used
|
||||
* such that HarfBuzz makes a copy immediately,
|
||||
*
|
||||
* - Use MODE_READONLY otherse, unless you really really
|
||||
* - Use MODE_READONLY otherwise, unless you really really
|
||||
* really know what you are doing,
|
||||
*
|
||||
* - MODE_WRITABLE is appropriate if you really made a
|
||||
|
|
@ -71,6 +71,9 @@ hb_blob_create (const char *data,
|
|||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name);
|
||||
|
||||
/* Always creates with MEMORY_MODE_READONLY.
|
||||
* Even if the parent blob is writable, we don't
|
||||
* want the user of the sub-blob to be able to
|
||||
|
|
@ -82,6 +85,9 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
|||
unsigned int offset,
|
||||
unsigned int length);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_copy_writable_or_fail (hb_blob_t *blob);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_get_empty (void);
|
||||
|
||||
|
|
@ -120,7 +126,6 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
|
|||
HB_EXTERN char *
|
||||
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_BLOB_H */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_BLOB_HH
|
||||
#define HB_BLOB_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_blob_t
|
||||
*/
|
||||
|
||||
struct hb_blob_t
|
||||
{
|
||||
void fini_shallow () { destroy_user_data (); }
|
||||
|
||||
void destroy_user_data ()
|
||||
{
|
||||
if (destroy)
|
||||
{
|
||||
destroy (user_data);
|
||||
user_data = nullptr;
|
||||
destroy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HB_INTERNAL bool try_make_writable ();
|
||||
HB_INTERNAL bool try_make_writable_inplace ();
|
||||
HB_INTERNAL bool try_make_writable_inplace_unix ();
|
||||
|
||||
hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); }
|
||||
template <typename Type>
|
||||
const Type* as () const { return as_bytes ().as<Type> (); }
|
||||
|
||||
public:
|
||||
hb_object_header_t header;
|
||||
|
||||
const char *data;
|
||||
unsigned int length;
|
||||
hb_memory_mode_t mode;
|
||||
|
||||
void *user_data;
|
||||
hb_destroy_func_t destroy;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* hb_blob_ptr_t
|
||||
*/
|
||||
|
||||
template <typename P>
|
||||
struct hb_blob_ptr_t
|
||||
{
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {}
|
||||
hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; }
|
||||
const T * operator -> () const { return get (); }
|
||||
const T & operator * () const { return *get (); }
|
||||
template <typename C> operator const C * () const { return get (); }
|
||||
operator const char * () const { return (const char *) get (); }
|
||||
const T * get () const { return b->as<T> (); }
|
||||
hb_blob_t * get_blob () const { return b.get_raw (); }
|
||||
unsigned int get_length () const { return b.get ()->length; }
|
||||
void destroy () { hb_blob_destroy (b.get ()); b = nullptr; }
|
||||
|
||||
hb_nonnull_ptr_t<hb_blob_t> b;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_BLOB_HH */
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
|
||||
#define HB_BUFFER_DESERIALIZE_JSON_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 36 "hb-buffer-deserialize-json.hh"
|
||||
|
|
@ -448,7 +448,7 @@ _hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
|
|||
const char *p = buf, *pe = buf + buf_len;
|
||||
|
||||
/* Ensure we have positions. */
|
||||
(void) hb_buffer_get_glyph_positions (buffer, NULL);
|
||||
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
|
|
@ -457,7 +457,7 @@ _hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
|
|||
*end_ptr = ++p;
|
||||
}
|
||||
|
||||
const char *tok = NULL;
|
||||
const char *tok = nullptr;
|
||||
int cs;
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
|
|
@ -503,7 +503,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -554,7 +554,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -566,7 +566,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -578,7 +578,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -590,7 +590,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -602,7 +602,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -614,7 +614,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-json.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright © 2013 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_BUFFER_DESERIALIZE_JSON_HH
|
||||
#define HB_BUFFER_DESERIALIZE_JSON_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
%%{
|
||||
|
||||
machine deserialize_json;
|
||||
alphtype unsigned char;
|
||||
write data;
|
||||
|
||||
action clear_item {
|
||||
memset (&info, 0, sizeof (info));
|
||||
memset (&pos , 0, sizeof (pos ));
|
||||
}
|
||||
|
||||
action add_item {
|
||||
buffer->add_info (info);
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
}
|
||||
|
||||
action tok {
|
||||
tok = p;
|
||||
}
|
||||
|
||||
action parse_glyph {
|
||||
if (!hb_font_glyph_from_string (font,
|
||||
tok, p - tok,
|
||||
&info.codepoint))
|
||||
return false;
|
||||
}
|
||||
|
||||
action parse_gid { if (!parse_uint (tok, p, &info.codepoint)) return false; }
|
||||
action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
|
||||
action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
|
||||
action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
|
||||
action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
|
||||
action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
|
||||
|
||||
unum = '0' | [1-9] digit*;
|
||||
num = '-'? unum;
|
||||
|
||||
comma = space* ',' space*;
|
||||
colon = space* ':' space*;
|
||||
|
||||
glyph_id = unum;
|
||||
glyph_name = alpha (alnum|'_'|'.'|'-')*;
|
||||
|
||||
glyph_string = '"' (glyph_name >tok %parse_glyph) '"';
|
||||
glyph_number = (glyph_id >tok %parse_gid);
|
||||
|
||||
glyph = "\"g\"" colon (glyph_string | glyph_number);
|
||||
cluster = "\"cl\"" colon (unum >tok %parse_cluster);
|
||||
xoffset = "\"dx\"" colon (num >tok %parse_x_offset);
|
||||
yoffset = "\"dy\"" colon (num >tok %parse_y_offset);
|
||||
xadvance= "\"ax\"" colon (num >tok %parse_x_advance);
|
||||
yadvance= "\"ay\"" colon (num >tok %parse_y_advance);
|
||||
|
||||
element = glyph | cluster | xoffset | yoffset | xadvance | yadvance;
|
||||
item =
|
||||
( '{' space* element (comma element)* space* '}')
|
||||
>clear_item
|
||||
@add_item
|
||||
;
|
||||
|
||||
main := space* item (comma item)* space* (','|']')?;
|
||||
|
||||
}%%
|
||||
|
||||
static hb_bool_t
|
||||
_hb_buffer_deserialize_glyphs_json (hb_buffer_t *buffer,
|
||||
const char *buf,
|
||||
unsigned int buf_len,
|
||||
const char **end_ptr,
|
||||
hb_font_t *font)
|
||||
{
|
||||
const char *p = buf, *pe = buf + buf_len;
|
||||
|
||||
/* Ensure we have positions. */
|
||||
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
if (p < pe && *p == (buffer->len ? ',' : '['))
|
||||
{
|
||||
*end_ptr = ++p;
|
||||
}
|
||||
|
||||
const char *tok = nullptr;
|
||||
int cs;
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
%%{
|
||||
write init;
|
||||
write exec;
|
||||
}%%
|
||||
|
||||
*end_ptr = p;
|
||||
|
||||
return p == pe && *(p-1) != ']';
|
||||
}
|
||||
|
||||
#endif /* HB_BUFFER_DESERIALIZE_JSON_HH */
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
|
||||
#define HB_BUFFER_DESERIALIZE_TEXT_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 36 "hb-buffer-deserialize-text.hh"
|
||||
|
|
@ -325,7 +325,7 @@ _hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
|
|||
const char *p = buf, *pe = buf + buf_len;
|
||||
|
||||
/* Ensure we have positions. */
|
||||
(void) hb_buffer_get_glyph_positions (buffer, NULL);
|
||||
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
|
|
@ -334,7 +334,7 @@ _hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
|
|||
*end_ptr = ++p;
|
||||
}
|
||||
|
||||
const char *eof = pe, *tok = NULL;
|
||||
const char *eof = pe, *tok = nullptr;
|
||||
int cs;
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
|
|
@ -422,7 +422,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -434,7 +434,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -446,7 +446,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -458,7 +458,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -470,7 +470,7 @@ _resume:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -499,7 +499,7 @@ _again:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -511,7 +511,7 @@ _again:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -523,7 +523,7 @@ _again:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -535,7 +535,7 @@ _again:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
@ -547,7 +547,7 @@ _again:
|
|||
#line 43 "hb-buffer-deserialize-text.rl"
|
||||
{
|
||||
buffer->add_info (info);
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright © 2013 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
|
||||
#define HB_BUFFER_DESERIALIZE_TEXT_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
%%{
|
||||
|
||||
machine deserialize_text;
|
||||
alphtype unsigned char;
|
||||
write data;
|
||||
|
||||
action clear_item {
|
||||
memset (&info, 0, sizeof (info));
|
||||
memset (&pos , 0, sizeof (pos ));
|
||||
}
|
||||
|
||||
action add_item {
|
||||
buffer->add_info (info);
|
||||
if (unlikely (!buffer->successful))
|
||||
return false;
|
||||
buffer->pos[buffer->len - 1] = pos;
|
||||
*end_ptr = p;
|
||||
}
|
||||
|
||||
action tok {
|
||||
tok = p;
|
||||
}
|
||||
|
||||
action parse_glyph {
|
||||
if (!hb_font_glyph_from_string (font,
|
||||
tok, p - tok,
|
||||
&info.codepoint))
|
||||
return false;
|
||||
}
|
||||
|
||||
action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; }
|
||||
action parse_x_offset { if (!parse_int (tok, p, &pos.x_offset )) return false; }
|
||||
action parse_y_offset { if (!parse_int (tok, p, &pos.y_offset )) return false; }
|
||||
action parse_x_advance { if (!parse_int (tok, p, &pos.x_advance)) return false; }
|
||||
action parse_y_advance { if (!parse_int (tok, p, &pos.y_advance)) return false; }
|
||||
|
||||
unum = '0' | [1-9] digit*;
|
||||
num = '-'? unum;
|
||||
|
||||
glyph_id = unum;
|
||||
glyph_name = alpha (alnum|'_'|'.'|'-')*;
|
||||
|
||||
glyph = (glyph_id | glyph_name) >tok %parse_glyph;
|
||||
cluster = '=' (unum >tok %parse_cluster);
|
||||
offsets = '@' (num >tok %parse_x_offset) ',' (num >tok %parse_y_offset );
|
||||
advances= '+' (num >tok %parse_x_advance) (',' (num >tok %parse_y_advance))?;
|
||||
item =
|
||||
(
|
||||
glyph
|
||||
cluster?
|
||||
offsets?
|
||||
advances?
|
||||
)
|
||||
>clear_item
|
||||
%add_item
|
||||
;
|
||||
|
||||
main := space* item (space* '|' space* item)* space* ('|'|']')?;
|
||||
|
||||
}%%
|
||||
|
||||
static hb_bool_t
|
||||
_hb_buffer_deserialize_glyphs_text (hb_buffer_t *buffer,
|
||||
const char *buf,
|
||||
unsigned int buf_len,
|
||||
const char **end_ptr,
|
||||
hb_font_t *font)
|
||||
{
|
||||
const char *p = buf, *pe = buf + buf_len;
|
||||
|
||||
/* Ensure we have positions. */
|
||||
(void) hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
if (p < pe && *p == (buffer->len ? '|' : '['))
|
||||
{
|
||||
*end_ptr = ++p;
|
||||
}
|
||||
|
||||
const char *eof = pe, *tok = nullptr;
|
||||
int cs;
|
||||
hb_glyph_info_t info = {0};
|
||||
hb_glyph_position_t pos = {0};
|
||||
%%{
|
||||
write init;
|
||||
write exec;
|
||||
}%%
|
||||
|
||||
*end_ptr = p;
|
||||
|
||||
return p == pe && *(p-1) != ']';
|
||||
}
|
||||
|
||||
#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */
|
||||
|
|
@ -24,7 +24,11 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-buffer-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_BUFFER_SERIALIZE
|
||||
|
||||
#include "hb-buffer.hh"
|
||||
|
||||
|
||||
static const char *serialize_formats[] = {
|
||||
|
|
@ -44,7 +48,7 @@ static const char *serialize_formats[] = {
|
|||
* Since: 0.9.7
|
||||
**/
|
||||
const char **
|
||||
hb_buffer_serialize_list_formats (void)
|
||||
hb_buffer_serialize_list_formats ()
|
||||
{
|
||||
return serialize_formats;
|
||||
}
|
||||
|
|
@ -58,7 +62,7 @@ hb_buffer_serialize_list_formats (void)
|
|||
* @str is a valid buffer serialization format, use
|
||||
* hb_buffer_serialize_list_formats() to get the list of supported formats.
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* The parsed #hb_buffer_serialize_format_t.
|
||||
*
|
||||
* Since: 0.9.7
|
||||
|
|
@ -85,7 +89,7 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
|
|||
const char *
|
||||
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
|
||||
{
|
||||
switch (format)
|
||||
switch ((unsigned) format)
|
||||
{
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
|
||||
|
|
@ -109,6 +113,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
|||
nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
*buf_consumed = 0;
|
||||
hb_position_t x = 0, y = 0;
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
{
|
||||
char b[1024];
|
||||
|
|
@ -130,40 +135,41 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
|||
hb_font_glyph_to_string (font, info[i].codepoint, g, sizeof (g));
|
||||
*p++ = '"';
|
||||
for (char *q = g; *q; q++) {
|
||||
if (*q == '"')
|
||||
if (*q == '"')
|
||||
*p++ = '\\';
|
||||
*p++ = *q;
|
||||
}
|
||||
*p++ = '"';
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
pos[i].x_offset, pos[i].y_offset));
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
pos[i].x_advance, pos[i].y_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
pos[i].x_advance, pos[i].y_advance));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
extents.x_bearing, extents.y_bearing));
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
extents.width, extents.height));
|
||||
}
|
||||
|
||||
|
|
@ -179,6 +185,12 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
|||
*buf = '\0';
|
||||
} else
|
||||
return i - start;
|
||||
|
||||
if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
{
|
||||
x += pos[i].x_advance;
|
||||
y += pos[i].y_advance;
|
||||
}
|
||||
}
|
||||
|
||||
return end - start;
|
||||
|
|
@ -199,6 +211,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
|||
nullptr : hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
|
||||
*buf_consumed = 0;
|
||||
hb_position_t x = 0, y = 0;
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
{
|
||||
char b[1024];
|
||||
|
|
@ -215,34 +228,37 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
|||
p += strlen (p);
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
if (pos[i].x_offset || pos[i].y_offset)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", pos[i].x_offset, pos[i].y_offset));
|
||||
if (x+pos[i].x_offset || y+pos[i].y_offset)
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
|
||||
*p++ = '+';
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
if (pos[i].y_advance)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
{
|
||||
*p++ = '+';
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
if (pos[i].y_advance)
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask &HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
}
|
||||
|
||||
unsigned int l = p - b;
|
||||
|
|
@ -255,6 +271,12 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
|||
*buf = '\0';
|
||||
} else
|
||||
return i - start;
|
||||
|
||||
if (pos && (flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
{
|
||||
x += pos[i].x_advance;
|
||||
y += pos[i].y_advance;
|
||||
}
|
||||
}
|
||||
|
||||
return end - start;
|
||||
|
|
@ -301,7 +323,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
|||
* ## json
|
||||
* TODO.
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* The number of serialized items.
|
||||
*
|
||||
* Since: 0.9.7
|
||||
|
|
@ -357,43 +379,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
static bool
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
uint32_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend || pend - p != end - pp)
|
||||
int v;
|
||||
const char *p = pp;
|
||||
if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
static bool
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
int32_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend || pend - p != end - pp)
|
||||
unsigned int v;
|
||||
const char *p = pp;
|
||||
if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
|
|
@ -407,14 +410,14 @@ parse_int (const char *pp, const char *end, int32_t *pv)
|
|||
* hb_buffer_deserialize_glyphs:
|
||||
* @buffer: an #hb_buffer_t buffer.
|
||||
* @buf: (array length=buf_len):
|
||||
* @buf_len:
|
||||
* @buf_len:
|
||||
* @end_ptr: (out):
|
||||
* @font:
|
||||
* @format:
|
||||
* @font:
|
||||
* @format:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.7
|
||||
**/
|
||||
|
|
@ -422,8 +425,8 @@ hb_bool_t
|
|||
hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
||||
const char *buf,
|
||||
int buf_len, /* -1 means nul-terminated */
|
||||
const char **end_ptr, /* May be nullptr */
|
||||
hb_font_t *font, /* May be nullptr */
|
||||
const char **end_ptr, /* May be NULL */
|
||||
hb_font_t *font, /* May be NULL */
|
||||
hb_buffer_serialize_format_t format)
|
||||
{
|
||||
const char *end;
|
||||
|
|
@ -466,3 +469,6 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,20 +27,21 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-buffer-private.hh"
|
||||
#include "hb-utf-private.hh"
|
||||
#include "hb-buffer.hh"
|
||||
#include "hb-utf.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION: hb-buffer
|
||||
* @title: Buffers
|
||||
* @title: hb-buffer
|
||||
* @short_description: Input and output buffers
|
||||
* @include: hb.h
|
||||
*
|
||||
* Buffers serve dual role in HarfBuzz; they hold the input characters that are
|
||||
* passed hb_shape(), and after shaping they hold the output glyphs.
|
||||
* passed to hb_shape(), and after shaping they hold the output glyphs.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_segment_properties_equal:
|
||||
* @a: first #hb_segment_properties_t to compare.
|
||||
|
|
@ -111,11 +112,11 @@ hb_segment_properties_hash (const hb_segment_properties_t *p)
|
|||
bool
|
||||
hb_buffer_t::enlarge (unsigned int size)
|
||||
{
|
||||
if (unlikely (in_error))
|
||||
if (unlikely (!successful))
|
||||
return false;
|
||||
if (unlikely (size > max_len))
|
||||
{
|
||||
in_error = true;
|
||||
successful = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -124,14 +125,14 @@ hb_buffer_t::enlarge (unsigned int size)
|
|||
hb_glyph_info_t *new_info = nullptr;
|
||||
bool separate_out = out_info != info;
|
||||
|
||||
if (unlikely (_hb_unsigned_int_mul_overflows (size, sizeof (info[0]))))
|
||||
if (unlikely (hb_unsigned_mul_overflows (size, sizeof (info[0]))))
|
||||
goto done;
|
||||
|
||||
while (size >= new_allocated)
|
||||
new_allocated += (new_allocated >> 1) + 32;
|
||||
|
||||
static_assert ((sizeof (info[0]) == sizeof (pos[0])), "");
|
||||
if (unlikely (_hb_unsigned_int_mul_overflows (new_allocated, sizeof (info[0]))))
|
||||
if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
|
||||
goto done;
|
||||
|
||||
new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
|
||||
|
|
@ -139,7 +140,7 @@ hb_buffer_t::enlarge (unsigned int size)
|
|||
|
||||
done:
|
||||
if (unlikely (!new_pos || !new_info))
|
||||
in_error = true;
|
||||
successful = false;
|
||||
|
||||
if (likely (new_pos))
|
||||
pos = new_pos;
|
||||
|
|
@ -148,10 +149,10 @@ done:
|
|||
info = new_info;
|
||||
|
||||
out_info = separate_out ? (hb_glyph_info_t *) pos : info;
|
||||
if (likely (!in_error))
|
||||
if (likely (successful))
|
||||
allocated = new_allocated;
|
||||
|
||||
return likely (!in_error);
|
||||
return likely (successful);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -182,7 +183,11 @@ hb_buffer_t::shift_forward (unsigned int count)
|
|||
if (idx + count > len)
|
||||
{
|
||||
/* Under memory failure we might expose this area. At least
|
||||
* clean it up. Oh well... */
|
||||
* clean it up. Oh well...
|
||||
*
|
||||
* Ideally, we should at least set Default_Ignorable bits on
|
||||
* these, as well as consistent cluster values. But the former
|
||||
* is layering violation... */
|
||||
memset (info + len, 0, (idx + count - len) * sizeof (info[0]));
|
||||
}
|
||||
len += count;
|
||||
|
|
@ -210,23 +215,24 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size)
|
|||
/* HarfBuzz-Internal API */
|
||||
|
||||
void
|
||||
hb_buffer_t::reset (void)
|
||||
hb_buffer_t::reset ()
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (this)))
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
|
||||
hb_unicode_funcs_destroy (unicode);
|
||||
unicode = hb_unicode_funcs_get_default ();
|
||||
unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ());
|
||||
flags = HB_BUFFER_FLAG_DEFAULT;
|
||||
replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
|
||||
invisible = 0;
|
||||
|
||||
clear ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::clear (void)
|
||||
hb_buffer_t::clear ()
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (this)))
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
|
||||
hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT;
|
||||
|
|
@ -234,7 +240,7 @@ hb_buffer_t::clear (void)
|
|||
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
|
||||
|
||||
content_type = HB_BUFFER_CONTENT_TYPE_INVALID;
|
||||
in_error = false;
|
||||
successful = true;
|
||||
have_output = false;
|
||||
have_positions = false;
|
||||
|
||||
|
|
@ -281,9 +287,9 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
|
|||
|
||||
|
||||
void
|
||||
hb_buffer_t::remove_output (void)
|
||||
hb_buffer_t::remove_output ()
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (this)))
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
|
||||
have_output = false;
|
||||
|
|
@ -294,9 +300,9 @@ hb_buffer_t::remove_output (void)
|
|||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::clear_output (void)
|
||||
hb_buffer_t::clear_output ()
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (this)))
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
|
||||
have_output = true;
|
||||
|
|
@ -307,9 +313,9 @@ hb_buffer_t::clear_output (void)
|
|||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::clear_positions (void)
|
||||
hb_buffer_t::clear_positions ()
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (this)))
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
|
||||
have_output = false;
|
||||
|
|
@ -318,13 +324,13 @@ hb_buffer_t::clear_positions (void)
|
|||
out_len = 0;
|
||||
out_info = info;
|
||||
|
||||
memset (pos, 0, sizeof (pos[0]) * len);
|
||||
hb_memset (pos, 0, sizeof (pos[0]) * len);
|
||||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::swap_buffers (void)
|
||||
hb_buffer_t::swap_buffers ()
|
||||
{
|
||||
if (unlikely (in_error)) return;
|
||||
if (unlikely (!successful)) return;
|
||||
|
||||
assert (have_output);
|
||||
have_output = false;
|
||||
|
|
@ -354,6 +360,8 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
|
|||
{
|
||||
if (unlikely (!make_room_for (num_in, num_out))) return;
|
||||
|
||||
assert (idx + num_in <= len);
|
||||
|
||||
merge_clusters (idx, idx + num_in);
|
||||
|
||||
hb_glyph_info_t orig_info = info[idx];
|
||||
|
|
@ -369,37 +377,6 @@ hb_buffer_t::replace_glyphs (unsigned int num_in,
|
|||
out_len += num_out;
|
||||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::output_glyph (hb_codepoint_t glyph_index)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return;
|
||||
|
||||
out_info[out_len] = info[idx];
|
||||
out_info[out_len].codepoint = glyph_index;
|
||||
|
||||
out_len++;
|
||||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::output_info (const hb_glyph_info_t &glyph_info)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return;
|
||||
|
||||
out_info[out_len] = glyph_info;
|
||||
|
||||
out_len++;
|
||||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::copy_glyph (void)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return;
|
||||
|
||||
out_info[out_len] = info[idx];
|
||||
|
||||
out_len++;
|
||||
}
|
||||
|
||||
bool
|
||||
hb_buffer_t::move_to (unsigned int i)
|
||||
{
|
||||
|
|
@ -409,7 +386,7 @@ hb_buffer_t::move_to (unsigned int i)
|
|||
idx = i;
|
||||
return true;
|
||||
}
|
||||
if (unlikely (in_error))
|
||||
if (unlikely (!successful))
|
||||
return false;
|
||||
|
||||
assert (i <= out_len + (len - idx));
|
||||
|
|
@ -429,8 +406,14 @@ hb_buffer_t::move_to (unsigned int i)
|
|||
unsigned int count = out_len - i;
|
||||
|
||||
/* This will blow in our face if memory allocation fails later
|
||||
* in this same lookup... */
|
||||
if (unlikely (idx < count && !shift_forward (count + 32))) return false;
|
||||
* in this same lookup...
|
||||
*
|
||||
* We used to shift with extra 32 items, instead of the 0 below.
|
||||
* But that would leave empty slots in the buffer in case of allocation
|
||||
* failures. Setting to zero for now to avoid other problems (see
|
||||
* comments in shift_forward(). This can cause O(N^2) behavior more
|
||||
* severely than adding 32 empty slots can... */
|
||||
if (unlikely (idx < count && !shift_forward (count + 0))) return false;
|
||||
|
||||
assert (idx >= count);
|
||||
|
||||
|
|
@ -442,19 +425,6 @@ hb_buffer_t::move_to (unsigned int i)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::replace_glyph (hb_codepoint_t glyph_index)
|
||||
{
|
||||
if (unlikely (out_info != info || out_len != idx)) {
|
||||
if (unlikely (!make_room_for (1, 1))) return;
|
||||
out_info[out_len] = info[idx];
|
||||
}
|
||||
out_info[out_len].codepoint = glyph_index;
|
||||
|
||||
idx++;
|
||||
out_len++;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
hb_buffer_t::set_masks (hb_mask_t value,
|
||||
|
|
@ -510,7 +480,7 @@ hb_buffer_t::reverse_range (unsigned int start,
|
|||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::reverse (void)
|
||||
hb_buffer_t::reverse ()
|
||||
{
|
||||
if (unlikely (!len))
|
||||
return;
|
||||
|
|
@ -519,7 +489,7 @@ hb_buffer_t::reverse (void)
|
|||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::reverse_clusters (void)
|
||||
hb_buffer_t::reverse_clusters ()
|
||||
{
|
||||
unsigned int i, start, count, last_cluster;
|
||||
|
||||
|
|
@ -554,7 +524,7 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
|
|||
unsigned int cluster = info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
|
||||
/* Extend end */
|
||||
while (end < len && info[end - 1].cluster == info[end].cluster)
|
||||
|
|
@ -585,7 +555,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
|
|||
unsigned int cluster = out_info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
|
||||
cluster = hb_min (cluster, out_info[i].cluster);
|
||||
|
||||
/* Extend start */
|
||||
while (start && out_info[start - 1].cluster == out_info[start].cluster)
|
||||
|
|
@ -666,7 +636,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en
|
|||
}
|
||||
|
||||
void
|
||||
hb_buffer_t::guess_segment_properties (void)
|
||||
hb_buffer_t::guess_segment_properties ()
|
||||
{
|
||||
assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
|
||||
(!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
|
||||
|
|
@ -678,8 +648,8 @@ hb_buffer_t::guess_segment_properties (void)
|
|||
if (likely (script != HB_SCRIPT_COMMON &&
|
||||
script != HB_SCRIPT_INHERITED &&
|
||||
script != HB_SCRIPT_UNKNOWN)) {
|
||||
props.script = script;
|
||||
break;
|
||||
props.script = script;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -687,6 +657,8 @@ hb_buffer_t::guess_segment_properties (void)
|
|||
/* If direction is set to INVALID, guess from script */
|
||||
if (props.direction == HB_DIRECTION_INVALID) {
|
||||
props.direction = hb_script_get_horizontal_direction (props.script);
|
||||
if (props.direction == HB_DIRECTION_INVALID)
|
||||
props.direction = HB_DIRECTION_LTR;
|
||||
}
|
||||
|
||||
/* If language is not set, use default language from locale */
|
||||
|
|
@ -699,6 +671,29 @@ hb_buffer_t::guess_segment_properties (void)
|
|||
|
||||
/* Public API */
|
||||
|
||||
DEFINE_NULL_INSTANCE (hb_buffer_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),
|
||||
HB_BUFFER_FLAG_DEFAULT,
|
||||
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
|
||||
0, /* invisible */
|
||||
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
|
||||
HB_BUFFER_MAX_LEN_DEFAULT,
|
||||
HB_BUFFER_MAX_OPS_DEFAULT,
|
||||
|
||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||
false, /* successful */
|
||||
true, /* have_output */
|
||||
true /* have_positions */
|
||||
|
||||
/* Zero is good enough for everything else. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* hb_buffer_create: (Xconstructor)
|
||||
*
|
||||
|
|
@ -714,7 +709,7 @@ hb_buffer_t::guess_segment_properties (void)
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
hb_buffer_t *
|
||||
hb_buffer_create (void)
|
||||
hb_buffer_create ()
|
||||
{
|
||||
hb_buffer_t *buffer;
|
||||
|
||||
|
|
@ -732,36 +727,16 @@ hb_buffer_create (void)
|
|||
/**
|
||||
* hb_buffer_get_empty:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_buffer_t *
|
||||
hb_buffer_get_empty (void)
|
||||
hb_buffer_get_empty ()
|
||||
{
|
||||
static const hb_buffer_t _hb_buffer_nil = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
|
||||
HB_BUFFER_FLAG_DEFAULT,
|
||||
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
|
||||
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
|
||||
HB_BUFFER_MAX_LEN_DEFAULT,
|
||||
HB_BUFFER_MAX_OPS_DEFAULT,
|
||||
|
||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||
true, /* in_error */
|
||||
true, /* have_output */
|
||||
true /* have_positions */
|
||||
|
||||
/* Zero is good enough for everything else. */
|
||||
};
|
||||
|
||||
return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
|
||||
return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -801,8 +776,10 @@ hb_buffer_destroy (hb_buffer_t *buffer)
|
|||
|
||||
free (buffer->info);
|
||||
free (buffer->pos);
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
if (buffer->message_destroy)
|
||||
buffer->message_destroy (buffer->message_data);
|
||||
#endif
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
|
@ -810,14 +787,14 @@ hb_buffer_destroy (hb_buffer_t *buffer)
|
|||
/**
|
||||
* hb_buffer_set_user_data: (skip)
|
||||
* @buffer: an #hb_buffer_t.
|
||||
* @key:
|
||||
* @data:
|
||||
* @destroy:
|
||||
* @replace:
|
||||
* @key:
|
||||
* @data:
|
||||
* @destroy:
|
||||
* @replace:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -834,11 +811,11 @@ hb_buffer_set_user_data (hb_buffer_t *buffer,
|
|||
/**
|
||||
* hb_buffer_get_user_data: (skip)
|
||||
* @buffer: an #hb_buffer_t.
|
||||
* @key:
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -888,9 +865,9 @@ hb_buffer_get_content_type (hb_buffer_t *buffer)
|
|||
/**
|
||||
* hb_buffer_set_unicode_funcs:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
* @unicode_funcs:
|
||||
* @unicode_funcs:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -898,13 +875,12 @@ void
|
|||
hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
|
||||
hb_unicode_funcs_t *unicode_funcs)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
if (!unicode_funcs)
|
||||
unicode_funcs = hb_unicode_funcs_get_default ();
|
||||
|
||||
|
||||
hb_unicode_funcs_reference (unicode_funcs);
|
||||
hb_unicode_funcs_destroy (buffer->unicode);
|
||||
buffer->unicode = unicode_funcs;
|
||||
|
|
@ -914,9 +890,9 @@ hb_buffer_set_unicode_funcs (hb_buffer_t *buffer,
|
|||
* hb_buffer_get_unicode_funcs:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -946,7 +922,7 @@ hb_buffer_set_direction (hb_buffer_t *buffer,
|
|||
hb_direction_t direction)
|
||||
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->props.direction = direction;
|
||||
|
|
@ -990,7 +966,7 @@ void
|
|||
hb_buffer_set_script (hb_buffer_t *buffer,
|
||||
hb_script_t script)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->props.script = script;
|
||||
|
|
@ -1025,7 +1001,7 @@ hb_buffer_get_script (hb_buffer_t *buffer)
|
|||
* are orthogonal to the scripts, and though they are related, they are
|
||||
* different concepts and should not be confused with each other.
|
||||
*
|
||||
* Use hb_language_from_string() to convert from ISO 639 language codes to
|
||||
* Use hb_language_from_string() to convert from BCP 47 language tags to
|
||||
* #hb_language_t.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
|
|
@ -1034,7 +1010,7 @@ void
|
|||
hb_buffer_set_language (hb_buffer_t *buffer,
|
||||
hb_language_t language)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->props.language = language;
|
||||
|
|
@ -1072,7 +1048,7 @@ void
|
|||
hb_buffer_set_segment_properties (hb_buffer_t *buffer,
|
||||
const hb_segment_properties_t *props)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->props = *props;
|
||||
|
|
@ -1108,7 +1084,7 @@ void
|
|||
hb_buffer_set_flags (hb_buffer_t *buffer,
|
||||
hb_buffer_flags_t flags)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->flags = flags;
|
||||
|
|
@ -1120,7 +1096,7 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
|
|||
*
|
||||
* See hb_buffer_set_flags().
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* The @buffer flags.
|
||||
*
|
||||
* Since: 0.9.7
|
||||
|
|
@ -1134,9 +1110,9 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
|
|||
/**
|
||||
* hb_buffer_set_cluster_level:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
* @cluster_level:
|
||||
* @cluster_level:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.42
|
||||
**/
|
||||
|
|
@ -1144,7 +1120,7 @@ void
|
|||
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
|
||||
hb_buffer_cluster_level_t cluster_level)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->cluster_level = cluster_level;
|
||||
|
|
@ -1154,9 +1130,9 @@ hb_buffer_set_cluster_level (hb_buffer_t *buffer,
|
|||
* hb_buffer_get_cluster_level:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.42
|
||||
**/
|
||||
|
|
@ -1183,7 +1159,7 @@ void
|
|||
hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
|
||||
hb_codepoint_t replacement)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->replacement = replacement;
|
||||
|
|
@ -1195,7 +1171,7 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
|
|||
*
|
||||
* See hb_buffer_set_replacement_codepoint().
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* The @buffer replacement #hb_codepoint_t.
|
||||
*
|
||||
* Since: 0.9.31
|
||||
|
|
@ -1207,6 +1183,46 @@ hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_buffer_set_invisible_glyph:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
* @invisible: the invisible #hb_codepoint_t
|
||||
*
|
||||
* Sets the #hb_codepoint_t that replaces invisible characters in
|
||||
* the shaping result. If set to zero (default), the glyph for the
|
||||
* U+0020 SPACE character is used. Otherwise, this value is used
|
||||
* verbatim.
|
||||
*
|
||||
* Since: 2.0.0
|
||||
**/
|
||||
void
|
||||
hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
|
||||
hb_codepoint_t invisible)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->invisible = invisible;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_get_invisible_glyph:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
*
|
||||
* See hb_buffer_set_invisible_glyph().
|
||||
*
|
||||
* Return value:
|
||||
* The @buffer invisible #hb_codepoint_t.
|
||||
*
|
||||
* Since: 2.0.0
|
||||
**/
|
||||
hb_codepoint_t
|
||||
hb_buffer_get_invisible_glyph (hb_buffer_t *buffer)
|
||||
{
|
||||
return buffer->invisible;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_buffer_reset:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
|
|
@ -1269,7 +1285,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size)
|
|||
hb_bool_t
|
||||
hb_buffer_allocation_successful (hb_buffer_t *buffer)
|
||||
{
|
||||
return !buffer->in_error;
|
||||
return buffer->successful;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1306,7 +1322,7 @@ hb_buffer_add (hb_buffer_t *buffer,
|
|||
* Similar to hb_buffer_pre_allocate(), but clears any new items added at the
|
||||
* end.
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* %true if @buffer memory allocation succeeded, %false otherwise.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
|
|
@ -1315,7 +1331,7 @@ hb_bool_t
|
|||
hb_buffer_set_length (hb_buffer_t *buffer,
|
||||
unsigned int length)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return length == 0;
|
||||
|
||||
if (!buffer->ensure (length))
|
||||
|
|
@ -1374,7 +1390,7 @@ hb_buffer_get_length (hb_buffer_t *buffer)
|
|||
**/
|
||||
hb_glyph_info_t *
|
||||
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
|
||||
unsigned int *length)
|
||||
unsigned int *length)
|
||||
{
|
||||
if (length)
|
||||
*length = buffer->len;
|
||||
|
|
@ -1398,7 +1414,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
|
|||
**/
|
||||
hb_glyph_position_t *
|
||||
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
|
||||
unsigned int *length)
|
||||
unsigned int *length)
|
||||
{
|
||||
if (!buffer->have_positions)
|
||||
buffer->clear_positions ();
|
||||
|
|
@ -1489,11 +1505,15 @@ hb_buffer_reverse_clusters (hb_buffer_t *buffer)
|
|||
* Next, if buffer direction is not set (ie. is %HB_DIRECTION_INVALID),
|
||||
* it will be set to the natural horizontal direction of the
|
||||
* buffer script as returned by hb_script_get_horizontal_direction().
|
||||
* If hb_script_get_horizontal_direction() returns %HB_DIRECTION_INVALID,
|
||||
* then %HB_DIRECTION_LTR is used.
|
||||
*
|
||||
* Finally, if buffer language is not set (ie. is %HB_LANGUAGE_INVALID),
|
||||
* it will be set to the process's default language as returned by
|
||||
* hb_language_get_default(). This may change in the future by
|
||||
* taking buffer script into consideration when choosing a language.
|
||||
* Note that hb_language_get_default() is NOT threadsafe the first time
|
||||
* it is called. See documentation for that function for details.
|
||||
*
|
||||
* Since: 0.9.7
|
||||
**/
|
||||
|
|
@ -1517,7 +1537,7 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
|
|||
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
|
||||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
|
||||
|
||||
if (unlikely (hb_object_is_inert (buffer)))
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
if (text_length == -1)
|
||||
|
|
@ -1648,7 +1668,7 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer,
|
|||
unsigned int item_offset,
|
||||
int item_length)
|
||||
{
|
||||
hb_buffer_add_utf<hb_utf32_t<> > (buffer, text, text_length, item_offset, item_length);
|
||||
hb_buffer_add_utf<hb_utf32_t> (buffer, text, text_length, item_offset, item_length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1709,7 +1729,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
|
|||
unsigned int item_offset,
|
||||
int item_length)
|
||||
{
|
||||
hb_buffer_add_utf<hb_utf32_t<false> > (buffer, text, text_length, item_offset, item_length);
|
||||
hb_buffer_add_utf<hb_utf32_novalidate_t> (buffer, text, text_length, item_offset, item_length);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1750,13 +1770,13 @@ hb_buffer_append (hb_buffer_t *buffer,
|
|||
|
||||
if (buffer->len + (end - start) < buffer->len) /* Overflows. */
|
||||
{
|
||||
buffer->in_error = true;
|
||||
buffer->successful = false;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int orig_len = buffer->len;
|
||||
hb_buffer_set_length (buffer, buffer->len + (end - start));
|
||||
if (buffer->in_error)
|
||||
if (unlikely (!buffer->successful))
|
||||
return;
|
||||
|
||||
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
|
||||
|
|
@ -1882,6 +1902,10 @@ hb_buffer_t::sort (unsigned int start, unsigned int end, int(*compar)(const hb_g
|
|||
|
||||
/**
|
||||
* hb_buffer_diff:
|
||||
* @buffer: a buffer.
|
||||
* @reference: other buffer to compare to.
|
||||
* @dottedcircle_glyph: glyph id of U+25CC DOTTED CIRCLE, or (hb_codepont_t) -1.
|
||||
* @position_fuzz: allowed absolute difference in position values.
|
||||
*
|
||||
* If dottedcircle_glyph is (hb_codepoint_t) -1 then %HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
|
||||
* and %HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT are never returned. This should be used by most
|
||||
|
|
@ -1914,9 +1938,9 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (contains && info[i].codepoint == dottedcircle_glyph)
|
||||
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
|
||||
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
|
||||
if (contains && info[i].codepoint == 0)
|
||||
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
|
||||
result |= HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT;
|
||||
}
|
||||
result |= HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH;
|
||||
return hb_buffer_diff_flags_t (result);
|
||||
|
|
@ -1933,7 +1957,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH;
|
||||
if (buf_info->cluster != ref_info->cluster)
|
||||
result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH;
|
||||
if ((buf_info->mask & HB_GLYPH_FLAG_DEFINED) != (ref_info->mask & HB_GLYPH_FLAG_DEFINED))
|
||||
if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED))
|
||||
result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH;
|
||||
if (contains && ref_info->codepoint == dottedcircle_glyph)
|
||||
result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT;
|
||||
|
|
@ -1951,12 +1975,12 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if ((unsigned int) abs (buf_pos->x_advance - ref_pos->x_advance) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
|
||||
(unsigned int) abs (buf_pos->y_advance - ref_pos->y_advance) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->x_offset - ref_pos->x_offset) > position_fuzz ||
|
||||
(unsigned int) abs (buf_pos->y_offset - ref_pos->y_offset) > position_fuzz)
|
||||
{
|
||||
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
|
||||
break;
|
||||
result |= HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH;
|
||||
break;
|
||||
}
|
||||
buf_pos++;
|
||||
ref_pos++;
|
||||
|
|
@ -1971,6 +1995,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
* Debugging.
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
/**
|
||||
* hb_buffer_set_message_func:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
|
|
@ -1978,7 +2003,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.1.3
|
||||
**/
|
||||
|
|
@ -2000,11 +2025,11 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
|
|||
buffer->message_destroy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[100];
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
return (bool) this->message_func (this, font, buf, this->message_data);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ HB_BEGIN_DECLS
|
|||
* hb_glyph_info_t:
|
||||
* @codepoint: either a Unicode code point (before shaping) or a glyph index
|
||||
* (after shaping).
|
||||
* @mask:
|
||||
* @cluster: the index of the character in the original text that corresponds
|
||||
* to this #hb_glyph_info_t, or whatever the client passes to
|
||||
* hb_buffer_add(). More than one #hb_glyph_info_t can have the same
|
||||
|
|
@ -59,11 +58,13 @@ HB_BEGIN_DECLS
|
|||
*
|
||||
* The #hb_glyph_info_t is the structure that holds information about the
|
||||
* glyphs and their relation to input text.
|
||||
*
|
||||
*/
|
||||
typedef struct hb_glyph_info_t {
|
||||
typedef struct hb_glyph_info_t
|
||||
{
|
||||
hb_codepoint_t codepoint;
|
||||
hb_mask_t mask; /* Holds hb_glyph_flags_t after hb_shape(), plus other things. */
|
||||
/*< private >*/
|
||||
hb_mask_t mask;
|
||||
/*< public >*/
|
||||
uint32_t cluster;
|
||||
|
||||
/*< private >*/
|
||||
|
|
@ -71,6 +72,27 @@ typedef struct hb_glyph_info_t {
|
|||
hb_var_int_t var2;
|
||||
} hb_glyph_info_t;
|
||||
|
||||
/**
|
||||
* hb_glyph_flags_t:
|
||||
* @HB_GLYPH_FLAG_UNSAFE_TO_BREAK: Indicates that if input text is broken at the
|
||||
* beginning of the cluster this glyph is part of,
|
||||
* then both sides need to be re-shaped, as the
|
||||
* result might be different. On the flip side,
|
||||
* it means that when this flag is not present,
|
||||
* then it's safe to break the glyph-run at the
|
||||
* beginning of this cluster, and the two sides
|
||||
* represent the exact same result one would get
|
||||
* if breaking input text at the beginning of
|
||||
* this cluster and shaping the two sides
|
||||
* separately. This can be used to optimize
|
||||
* paragraph layout, by avoiding re-shaping
|
||||
* of each line after line-breaking, or limiting
|
||||
* the reshaping to a small piece around the
|
||||
* breaking point only.
|
||||
* @HB_GLYPH_FLAG_DEFINED: All the currently defined flags.
|
||||
*
|
||||
* Since: 1.5.0
|
||||
*/
|
||||
typedef enum { /*< flags >*/
|
||||
HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001,
|
||||
|
||||
|
|
@ -247,13 +269,25 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
|
|||
* of the text without the full context.
|
||||
* @HB_BUFFER_FLAG_EOT: flag indicating that special handling of the end of text
|
||||
* paragraph can be applied to this buffer, similar to
|
||||
* @HB_BUFFER_FLAG_EOT.
|
||||
* @HB_BUFFER_FLAG_BOT.
|
||||
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES:
|
||||
* flag indication that character with Default_Ignorable
|
||||
* Unicode property should use the corresponding glyph
|
||||
* from the font, instead of hiding them (currently done
|
||||
* by replacing them with the space glyph and zeroing the
|
||||
* advance width.)
|
||||
* from the font, instead of hiding them (done by
|
||||
* replacing them with the space glyph and zeroing the
|
||||
* advance width.) This flag takes precedence over
|
||||
* @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES.
|
||||
* @HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES:
|
||||
* flag indication that character with Default_Ignorable
|
||||
* Unicode property should be removed from glyph string
|
||||
* instead of hiding them (done by replacing them with the
|
||||
* space glyph and zeroing the advance width.)
|
||||
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
|
||||
* precedence over this flag. Since: 1.8.0
|
||||
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
|
||||
* flag indicating that a dotted circle should
|
||||
* not be inserted in the rendering of incorrect
|
||||
* character sequences (such at <0905 093E>). Since: 2.4
|
||||
*
|
||||
* Since: 0.9.20
|
||||
*/
|
||||
|
|
@ -261,7 +295,9 @@ typedef enum { /*< flags >*/
|
|||
HB_BUFFER_FLAG_DEFAULT = 0x00000000u,
|
||||
HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
|
||||
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
|
||||
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u
|
||||
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
|
||||
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
|
||||
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
|
||||
} hb_buffer_flags_t;
|
||||
|
||||
HB_EXTERN void
|
||||
|
|
@ -271,7 +307,15 @@ hb_buffer_set_flags (hb_buffer_t *buffer,
|
|||
HB_EXTERN hb_buffer_flags_t
|
||||
hb_buffer_get_flags (hb_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
/**
|
||||
* hb_buffer_cluster_level_t:
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES: Return cluster values grouped by graphemes into
|
||||
* monotone order.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS: Return cluster values grouped into monotone order.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_CHARACTERS: Don't group cluster values.
|
||||
* @HB_BUFFER_CLUSTER_LEVEL_DEFAULT: Default cluster level,
|
||||
* equal to @HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES.
|
||||
*
|
||||
* Since: 0.9.42
|
||||
*/
|
||||
typedef enum {
|
||||
|
|
@ -305,6 +349,13 @@ hb_buffer_set_replacement_codepoint (hb_buffer_t *buffer,
|
|||
HB_EXTERN hb_codepoint_t
|
||||
hb_buffer_get_replacement_codepoint (hb_buffer_t *buffer);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_buffer_set_invisible_glyph (hb_buffer_t *buffer,
|
||||
hb_codepoint_t invisible);
|
||||
|
||||
HB_EXTERN hb_codepoint_t
|
||||
hb_buffer_get_invisible_glyph (hb_buffer_t *buffer);
|
||||
|
||||
|
||||
HB_EXTERN void
|
||||
hb_buffer_reset (hb_buffer_t *buffer);
|
||||
|
|
@ -390,11 +441,11 @@ hb_buffer_get_length (hb_buffer_t *buffer);
|
|||
|
||||
HB_EXTERN hb_glyph_info_t *
|
||||
hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
|
||||
unsigned int *length);
|
||||
unsigned int *length);
|
||||
|
||||
HB_EXTERN hb_glyph_position_t *
|
||||
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
|
||||
unsigned int *length);
|
||||
unsigned int *length);
|
||||
|
||||
|
||||
HB_EXTERN void
|
||||
|
|
@ -412,6 +463,9 @@ hb_buffer_normalize_glyphs (hb_buffer_t *buffer);
|
|||
* @HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS: do not serialize glyph position information.
|
||||
* @HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES: do no serialize glyph name.
|
||||
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS: serialize glyph extents.
|
||||
* @HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS: serialize glyph flags. Since: 1.5.0
|
||||
* @HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES: do not serialize glyph advances,
|
||||
* glyph offsets will reflect absolute glyph positions. Since: 1.8.0
|
||||
*
|
||||
* Flags that control what glyph information are serialized in hb_buffer_serialize_glyphs().
|
||||
*
|
||||
|
|
@ -423,7 +477,8 @@ typedef enum { /*< flags >*/
|
|||
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS = 0x00000002u,
|
||||
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES = 0x00000004u,
|
||||
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS = 0x00000008u,
|
||||
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u
|
||||
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS = 0x00000010u,
|
||||
HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES = 0x00000020u
|
||||
} hb_buffer_serialize_flags_t;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -27,12 +27,11 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_BUFFER_PRIVATE_HH
|
||||
#define HB_BUFFER_PRIVATE_HH
|
||||
#ifndef HB_BUFFER_HH
|
||||
#define HB_BUFFER_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-unicode-private.hh"
|
||||
#include "hb.hh"
|
||||
#include "hb-unicode.hh"
|
||||
|
||||
|
||||
#ifndef HB_BUFFER_MAX_LEN_FACTOR
|
||||
|
|
@ -69,6 +68,7 @@ enum hb_buffer_scratch_flags_t {
|
|||
HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u,
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u,
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u,
|
||||
HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u,
|
||||
|
||||
/* Reserved for complex shapers' internal use. */
|
||||
HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u,
|
||||
|
|
@ -83,16 +83,17 @@ HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
|
|||
* hb_buffer_t
|
||||
*/
|
||||
|
||||
struct hb_buffer_t {
|
||||
struct hb_buffer_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
/* Information about how the text in the buffer should be treated */
|
||||
hb_unicode_funcs_t *unicode; /* Unicode functions */
|
||||
hb_buffer_flags_t flags; /* BOT / EOT / etc. */
|
||||
hb_buffer_cluster_level_t cluster_level;
|
||||
hb_codepoint_t replacement; /* U+FFFD or something else. */
|
||||
hb_buffer_scratch_flags_t scratch_flags; /* Have space-flallback, etc. */
|
||||
hb_codepoint_t invisible; /* 0 or something else. */
|
||||
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
|
||||
unsigned int max_len; /* Maximum allowed len. */
|
||||
int max_ops; /* Maximum allowed operations. */
|
||||
|
||||
|
|
@ -100,7 +101,7 @@ struct hb_buffer_t {
|
|||
hb_buffer_content_type_t content_type;
|
||||
hb_segment_properties_t props; /* Script, language, direction */
|
||||
|
||||
bool in_error; /* Allocation failed */
|
||||
bool successful; /* Allocations successful */
|
||||
bool have_output; /* Whether we have an output buffer going on */
|
||||
bool have_positions; /* Whether we have positions */
|
||||
|
||||
|
|
@ -118,14 +119,16 @@ struct hb_buffer_t {
|
|||
/* Text before / after the main buffer contents.
|
||||
* Always in Unicode, and ordered outward.
|
||||
* Index 0 is for "pre-context", 1 for "post-context". */
|
||||
static const unsigned int CONTEXT_LENGTH = 5;
|
||||
static constexpr unsigned CONTEXT_LENGTH = 5u;
|
||||
hb_codepoint_t context[2][CONTEXT_LENGTH];
|
||||
unsigned int context_len[2];
|
||||
|
||||
/* Debugging API */
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
hb_buffer_message_func_t message_func;
|
||||
void *message_data;
|
||||
hb_destroy_func_t message_destroy;
|
||||
#endif
|
||||
|
||||
/* Internal debugging. */
|
||||
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
|
||||
|
|
@ -136,7 +139,9 @@ struct hb_buffer_t {
|
|||
|
||||
/* Methods */
|
||||
|
||||
inline void allocate_var (unsigned int start, unsigned int count)
|
||||
bool in_error () const { return !successful; }
|
||||
|
||||
void allocate_var (unsigned int start, unsigned int count)
|
||||
{
|
||||
#ifndef HB_NDEBUG
|
||||
unsigned int end = start + count;
|
||||
|
|
@ -146,7 +151,7 @@ struct hb_buffer_t {
|
|||
allocated_var_bits |= bits;
|
||||
#endif
|
||||
}
|
||||
inline void deallocate_var (unsigned int start, unsigned int count)
|
||||
void deallocate_var (unsigned int start, unsigned int count)
|
||||
{
|
||||
#ifndef HB_NDEBUG
|
||||
unsigned int end = start + count;
|
||||
|
|
@ -156,7 +161,7 @@ struct hb_buffer_t {
|
|||
allocated_var_bits &= ~bits;
|
||||
#endif
|
||||
}
|
||||
inline void assert_var (unsigned int start, unsigned int count)
|
||||
void assert_var (unsigned int start, unsigned int count)
|
||||
{
|
||||
#ifndef HB_NDEBUG
|
||||
unsigned int end = start + count;
|
||||
|
|
@ -165,67 +170,102 @@ struct hb_buffer_t {
|
|||
assert (bits == (allocated_var_bits & bits));
|
||||
#endif
|
||||
}
|
||||
inline void deallocate_var_all (void)
|
||||
void deallocate_var_all ()
|
||||
{
|
||||
#ifndef HB_NDEBUG
|
||||
allocated_var_bits = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
|
||||
inline hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
|
||||
hb_glyph_info_t &cur (unsigned int i = 0) { return info[idx + i]; }
|
||||
hb_glyph_info_t cur (unsigned int i = 0) const { return info[idx + i]; }
|
||||
|
||||
inline hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
|
||||
inline hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
|
||||
hb_glyph_position_t &cur_pos (unsigned int i = 0) { return pos[idx + i]; }
|
||||
hb_glyph_position_t cur_pos (unsigned int i = 0) const { return pos[idx + i]; }
|
||||
|
||||
inline hb_glyph_info_t &prev (void) { return out_info[out_len ? out_len - 1 : 0]; }
|
||||
inline hb_glyph_info_t prev (void) const { return out_info[out_len ? out_len - 1 : 0]; }
|
||||
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
|
||||
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
|
||||
|
||||
inline bool has_separate_output (void) const { return info != out_info; }
|
||||
bool has_separate_output () const { return info != out_info; }
|
||||
|
||||
|
||||
HB_INTERNAL void reset (void);
|
||||
HB_INTERNAL void clear (void);
|
||||
HB_INTERNAL void reset ();
|
||||
HB_INTERNAL void clear ();
|
||||
|
||||
inline unsigned int backtrack_len (void) const
|
||||
{ return have_output? out_len : idx; }
|
||||
inline unsigned int lookahead_len (void) const
|
||||
{ return len - idx; }
|
||||
inline unsigned int next_serial (void) { return serial++; }
|
||||
unsigned int backtrack_len () const { return have_output? out_len : idx; }
|
||||
unsigned int lookahead_len () const { return len - idx; }
|
||||
unsigned int next_serial () { return serial++; }
|
||||
|
||||
HB_INTERNAL void add (hb_codepoint_t codepoint,
|
||||
unsigned int cluster);
|
||||
HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info);
|
||||
|
||||
HB_INTERNAL void reverse_range (unsigned int start, unsigned int end);
|
||||
HB_INTERNAL void reverse (void);
|
||||
HB_INTERNAL void reverse_clusters (void);
|
||||
HB_INTERNAL void guess_segment_properties (void);
|
||||
HB_INTERNAL void reverse ();
|
||||
HB_INTERNAL void reverse_clusters ();
|
||||
HB_INTERNAL void guess_segment_properties ();
|
||||
|
||||
HB_INTERNAL void swap_buffers (void);
|
||||
HB_INTERNAL void remove_output (void);
|
||||
HB_INTERNAL void clear_output (void);
|
||||
HB_INTERNAL void clear_positions (void);
|
||||
HB_INTERNAL void swap_buffers ();
|
||||
HB_INTERNAL void remove_output ();
|
||||
HB_INTERNAL void clear_output ();
|
||||
HB_INTERNAL void clear_positions ();
|
||||
|
||||
HB_INTERNAL void replace_glyphs (unsigned int num_in,
|
||||
unsigned int num_out,
|
||||
const hb_codepoint_t *glyph_data);
|
||||
|
||||
HB_INTERNAL void replace_glyph (hb_codepoint_t glyph_index);
|
||||
void replace_glyph (hb_codepoint_t glyph_index)
|
||||
{
|
||||
if (unlikely (out_info != info || out_len != idx)) {
|
||||
if (unlikely (!make_room_for (1, 1))) return;
|
||||
out_info[out_len] = info[idx];
|
||||
}
|
||||
out_info[out_len].codepoint = glyph_index;
|
||||
|
||||
idx++;
|
||||
out_len++;
|
||||
}
|
||||
/* Makes a copy of the glyph at idx to output and replace glyph_index */
|
||||
HB_INTERNAL void output_glyph (hb_codepoint_t glyph_index);
|
||||
HB_INTERNAL void output_info (const hb_glyph_info_t &glyph_info);
|
||||
hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
|
||||
|
||||
if (unlikely (idx == len && !out_len))
|
||||
return Crap(hb_glyph_info_t);
|
||||
|
||||
out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
|
||||
out_info[out_len].codepoint = glyph_index;
|
||||
|
||||
out_len++;
|
||||
|
||||
return out_info[out_len - 1];
|
||||
}
|
||||
void output_info (const hb_glyph_info_t &glyph_info)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return;
|
||||
|
||||
out_info[out_len] = glyph_info;
|
||||
|
||||
out_len++;
|
||||
}
|
||||
/* Copies glyph at idx to output but doesn't advance idx */
|
||||
HB_INTERNAL void copy_glyph (void);
|
||||
HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
|
||||
void copy_glyph ()
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return;
|
||||
|
||||
out_info[out_len] = info[idx];
|
||||
|
||||
out_len++;
|
||||
}
|
||||
/* Copies glyph at idx to output and advance idx.
|
||||
* If there's no output, just advance idx. */
|
||||
inline void
|
||||
next_glyph (void)
|
||||
void
|
||||
next_glyph ()
|
||||
{
|
||||
if (have_output)
|
||||
{
|
||||
if (unlikely (out_info != info || out_len != idx)) {
|
||||
if (out_info != info || out_len != idx)
|
||||
{
|
||||
if (unlikely (!make_room_for (1, 1))) return;
|
||||
out_info[out_len] = info[idx];
|
||||
}
|
||||
|
|
@ -234,16 +274,31 @@ struct hb_buffer_t {
|
|||
|
||||
idx++;
|
||||
}
|
||||
/* Copies n glyphs at idx to output and advance idx.
|
||||
* If there's no output, just advance idx. */
|
||||
void
|
||||
next_glyphs (unsigned int n)
|
||||
{
|
||||
if (have_output)
|
||||
{
|
||||
if (out_info != info || out_len != idx)
|
||||
{
|
||||
if (unlikely (!make_room_for (n, n))) return;
|
||||
memmove (out_info + out_len, info + idx, n * sizeof (out_info[0]));
|
||||
}
|
||||
out_len += n;
|
||||
}
|
||||
|
||||
idx += n;
|
||||
}
|
||||
/* Advance idx without copying to output. */
|
||||
inline void skip_glyph (void) { idx++; }
|
||||
|
||||
inline void reset_masks (hb_mask_t mask)
|
||||
void skip_glyph () { idx++; }
|
||||
void reset_masks (hb_mask_t mask)
|
||||
{
|
||||
for (unsigned int j = 0; j < len; j++)
|
||||
info[j].mask = mask;
|
||||
}
|
||||
inline void add_masks (hb_mask_t mask)
|
||||
void add_masks (hb_mask_t mask)
|
||||
{
|
||||
for (unsigned int j = 0; j < len; j++)
|
||||
info[j].mask |= mask;
|
||||
|
|
@ -251,7 +306,7 @@ struct hb_buffer_t {
|
|||
HB_INTERNAL void set_masks (hb_mask_t value, hb_mask_t mask,
|
||||
unsigned int cluster_start, unsigned int cluster_end);
|
||||
|
||||
inline void merge_clusters (unsigned int start, unsigned int end)
|
||||
void merge_clusters (unsigned int start, unsigned int end)
|
||||
{
|
||||
if (end - start < 2)
|
||||
return;
|
||||
|
|
@ -260,9 +315,9 @@ struct hb_buffer_t {
|
|||
HB_INTERNAL void merge_clusters_impl (unsigned int start, unsigned int end);
|
||||
HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end);
|
||||
/* Merge clusters for deleting current glyph, and skip it. */
|
||||
HB_INTERNAL void delete_glyph (void);
|
||||
HB_INTERNAL void delete_glyph ();
|
||||
|
||||
inline void unsafe_to_break (unsigned int start,
|
||||
void unsafe_to_break (unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
if (end - start < 2)
|
||||
|
|
@ -274,12 +329,14 @@ struct hb_buffer_t {
|
|||
|
||||
|
||||
/* Internal methods */
|
||||
HB_INTERNAL bool move_to (unsigned int i); /* i is output-buffer index. */
|
||||
|
||||
HB_INTERNAL bool enlarge (unsigned int size);
|
||||
|
||||
inline bool ensure (unsigned int size)
|
||||
bool ensure (unsigned int size)
|
||||
{ return likely (!size || size < allocated) ? true : enlarge (size); }
|
||||
|
||||
inline bool ensure_inplace (unsigned int size)
|
||||
bool ensure_inplace (unsigned int size)
|
||||
{ return likely (!size || size < allocated); }
|
||||
|
||||
HB_INTERNAL bool make_room_for (unsigned int num_in, unsigned int num_out);
|
||||
|
|
@ -288,13 +345,23 @@ struct hb_buffer_t {
|
|||
typedef long scratch_buffer_t;
|
||||
HB_INTERNAL scratch_buffer_t *get_scratch_buffer (unsigned int *size);
|
||||
|
||||
inline void clear_context (unsigned int side) { context_len[side] = 0; }
|
||||
void clear_context (unsigned int side) { context_len[side] = 0; }
|
||||
|
||||
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
|
||||
|
||||
inline bool messaging (void) { return unlikely (message_func); }
|
||||
inline bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
|
||||
bool messaging ()
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return false;
|
||||
#else
|
||||
return unlikely (message_func);
|
||||
#endif
|
||||
}
|
||||
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return true;
|
||||
#else
|
||||
if (!messaging ())
|
||||
return true;
|
||||
va_list ap;
|
||||
|
|
@ -302,57 +369,53 @@ struct hb_buffer_t {
|
|||
bool ret = message_impl (font, fmt, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
|
||||
|
||||
static inline void
|
||||
set_cluster (hb_glyph_info_t &info, unsigned int cluster, unsigned int mask = 0)
|
||||
static void
|
||||
set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0)
|
||||
{
|
||||
if (info.cluster != cluster)
|
||||
if (inf.cluster != cluster)
|
||||
{
|
||||
if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)
|
||||
info.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
else
|
||||
info.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
}
|
||||
info.cluster = cluster;
|
||||
inf.cluster = cluster;
|
||||
}
|
||||
|
||||
inline int
|
||||
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *info,
|
||||
int
|
||||
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
|
||||
unsigned int start, unsigned int end,
|
||||
unsigned int cluster) const
|
||||
{
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, infos[i].cluster);
|
||||
return cluster;
|
||||
}
|
||||
inline void
|
||||
_unsafe_to_break_set_mask (hb_glyph_info_t *info,
|
||||
void
|
||||
_unsafe_to_break_set_mask (hb_glyph_info_t *infos,
|
||||
unsigned int start, unsigned int end,
|
||||
unsigned int cluster)
|
||||
{
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
if (cluster != info[i].cluster)
|
||||
if (cluster != infos[i].cluster)
|
||||
{
|
||||
scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK;
|
||||
info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
unsafe_to_break_all (void)
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
info[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
}
|
||||
inline void
|
||||
safe_to_break_all (void)
|
||||
void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
|
||||
void safe_to_break_all ()
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
}
|
||||
};
|
||||
DECLARE_NULL_INSTANCE (hb_buffer_t);
|
||||
|
||||
|
||||
/* Loop over clusters. Duplicated in foreach_syllable(). */
|
||||
|
|
@ -385,4 +448,4 @@ _next_cluster (hb_buffer_t *buffer, unsigned int start)
|
|||
#define HB_BUFFER_ASSERT_VAR(b, var) HB_BUFFER_XALLOCATE_VAR (b, assert_var, var ())
|
||||
|
||||
|
||||
#endif /* HB_BUFFER_PRIVATE_HH */
|
||||
#endif /* HB_BUFFER_HH */
|
||||
|
|
@ -24,10 +24,10 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_CACHE_PRIVATE_HH
|
||||
#define HB_CACHE_PRIVATE_HH
|
||||
#ifndef HB_CACHE_HH
|
||||
#define HB_CACHE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
/* Implements a lock-free cache for int->int functions. */
|
||||
|
|
@ -35,40 +35,46 @@
|
|||
template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
|
||||
struct hb_cache_t
|
||||
{
|
||||
ASSERT_STATIC (key_bits >= cache_bits);
|
||||
ASSERT_STATIC (key_bits + value_bits - cache_bits < 8 * sizeof (unsigned int));
|
||||
static_assert ((key_bits >= cache_bits), "");
|
||||
static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), "");
|
||||
static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), "");
|
||||
|
||||
inline void clear (void)
|
||||
void init () { clear (); }
|
||||
void fini () {}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
memset (values, 255, sizeof (values));
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH (values); i++)
|
||||
values[i].set_relaxed (-1);
|
||||
}
|
||||
|
||||
inline bool get (unsigned int key, unsigned int *value)
|
||||
bool get (unsigned int key, unsigned int *value) const
|
||||
{
|
||||
unsigned int k = key & ((1u<<cache_bits)-1);
|
||||
unsigned int v = values[k];
|
||||
if ((v >> value_bits) != (key >> cache_bits))
|
||||
unsigned int v = values[k].get_relaxed ();
|
||||
if ((key_bits + value_bits - cache_bits == 8 * sizeof (hb_atomic_int_t) && v == (unsigned int) -1) ||
|
||||
(v >> value_bits) != (key >> cache_bits))
|
||||
return false;
|
||||
*value = v & ((1u<<value_bits)-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool set (unsigned int key, unsigned int value)
|
||||
bool set (unsigned int key, unsigned int value)
|
||||
{
|
||||
if (unlikely ((key >> key_bits) || (value >> value_bits)))
|
||||
return false; /* Overflows */
|
||||
unsigned int k = key & ((1u<<cache_bits)-1);
|
||||
unsigned int v = ((key>>cache_bits)<<value_bits) | value;
|
||||
values[k] = v;
|
||||
values[k].set_relaxed (v);
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int values[1u<<cache_bits];
|
||||
hb_atomic_int_t values[1u<<cache_bits];
|
||||
};
|
||||
|
||||
typedef hb_cache_t<21, 16, 8> hb_cmap_cache_t;
|
||||
typedef hb_cache_t<16, 24, 8> hb_advance_cache_t;
|
||||
|
||||
|
||||
#endif /* HB_CACHE_PRIVATE_HH */
|
||||
#endif /* HB_CACHE_HH */
|
||||
|
|
@ -0,0 +1,691 @@
|
|||
/*
|
||||
* Copyright © 2018 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
#ifndef HB_CFF_INTERP_COMMON_HH
|
||||
#define HB_CFF_INTERP_COMMON_HH
|
||||
|
||||
namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
typedef unsigned int op_code_t;
|
||||
|
||||
|
||||
/* === Dict operators === */
|
||||
|
||||
/* One byte operators (0-31) */
|
||||
#define OpCode_version 0 /* CFF Top */
|
||||
#define OpCode_Notice 1 /* CFF Top */
|
||||
#define OpCode_FullName 2 /* CFF Top */
|
||||
#define OpCode_FamilyName 3 /* CFF Top */
|
||||
#define OpCode_Weight 4 /* CFF Top */
|
||||
#define OpCode_FontBBox 5 /* CFF Top */
|
||||
#define OpCode_BlueValues 6 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_OtherBlues 7 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_FamilyBlues 8 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_FamilyOtherBlues 9 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_StdHW 10 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_StdVW 11 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_escape 12 /* All. Shared with CS */
|
||||
#define OpCode_UniqueID 13 /* CFF Top */
|
||||
#define OpCode_XUID 14 /* CFF Top */
|
||||
#define OpCode_charset 15 /* CFF Top (0) */
|
||||
#define OpCode_Encoding 16 /* CFF Top (0) */
|
||||
#define OpCode_CharStrings 17 /* CFF Top, CFF2 Top */
|
||||
#define OpCode_Private 18 /* CFF Top, CFF2 FD */
|
||||
#define OpCode_Subrs 19 /* CFF Private, CFF2 Private */
|
||||
#define OpCode_defaultWidthX 20 /* CFF Private (0) */
|
||||
#define OpCode_nominalWidthX 21 /* CFF Private (0) */
|
||||
#define OpCode_vsindexdict 22 /* CFF2 Private/CS */
|
||||
#define OpCode_blenddict 23 /* CFF2 Private/CS */
|
||||
#define OpCode_vstore 24 /* CFF2 Top */
|
||||
#define OpCode_reserved25 25
|
||||
#define OpCode_reserved26 26
|
||||
#define OpCode_reserved27 27
|
||||
|
||||
/* Numbers */
|
||||
#define OpCode_shortint 28 /* 16-bit integer, All */
|
||||
#define OpCode_longintdict 29 /* 32-bit integer, All */
|
||||
#define OpCode_BCD 30 /* Real number, CFF2 Top/FD */
|
||||
#define OpCode_reserved31 31
|
||||
|
||||
/* 1-byte integers */
|
||||
#define OpCode_OneByteIntFirst 32 /* All. beginning of the range of first byte ints */
|
||||
#define OpCode_OneByteIntLast 246 /* All. ending of the range of first byte int */
|
||||
|
||||
/* 2-byte integers */
|
||||
#define OpCode_TwoBytePosInt0 247 /* All. first byte of two byte positive int (+108 to +1131) */
|
||||
#define OpCode_TwoBytePosInt1 248
|
||||
#define OpCode_TwoBytePosInt2 249
|
||||
#define OpCode_TwoBytePosInt3 250
|
||||
|
||||
#define OpCode_TwoByteNegInt0 251 /* All. first byte of two byte negative int (-1131 to -108) */
|
||||
#define OpCode_TwoByteNegInt1 252
|
||||
#define OpCode_TwoByteNegInt2 253
|
||||
#define OpCode_TwoByteNegInt3 254
|
||||
|
||||
/* Two byte escape operators 12, (0-41) */
|
||||
#define OpCode_ESC_Base 256
|
||||
#define Make_OpCode_ESC(byte2) ((op_code_t)(OpCode_ESC_Base + (byte2)))
|
||||
|
||||
inline op_code_t Unmake_OpCode_ESC (op_code_t op) { return (op_code_t)(op - OpCode_ESC_Base); }
|
||||
inline bool Is_OpCode_ESC (op_code_t op) { return op >= OpCode_ESC_Base; }
|
||||
inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2: 1; }
|
||||
|
||||
#define OpCode_Copyright Make_OpCode_ESC(0) /* CFF Top */
|
||||
#define OpCode_isFixedPitch Make_OpCode_ESC(1) /* CFF Top (false) */
|
||||
#define OpCode_ItalicAngle Make_OpCode_ESC(2) /* CFF Top (0) */
|
||||
#define OpCode_UnderlinePosition Make_OpCode_ESC(3) /* CFF Top (-100) */
|
||||
#define OpCode_UnderlineThickness Make_OpCode_ESC(4) /* CFF Top (50) */
|
||||
#define OpCode_PaintType Make_OpCode_ESC(5) /* CFF Top (0) */
|
||||
#define OpCode_CharstringType Make_OpCode_ESC(6) /* CFF Top (2) */
|
||||
#define OpCode_FontMatrix Make_OpCode_ESC(7) /* CFF Top, CFF2 Top (.001 0 0 .001 0 0)*/
|
||||
#define OpCode_StrokeWidth Make_OpCode_ESC(8) /* CFF Top (0) */
|
||||
#define OpCode_BlueScale Make_OpCode_ESC(9) /* CFF Private, CFF2 Private (0.039625) */
|
||||
#define OpCode_BlueShift Make_OpCode_ESC(10) /* CFF Private, CFF2 Private (7) */
|
||||
#define OpCode_BlueFuzz Make_OpCode_ESC(11) /* CFF Private, CFF2 Private (1) */
|
||||
#define OpCode_StemSnapH Make_OpCode_ESC(12) /* CFF Private, CFF2 Private */
|
||||
#define OpCode_StemSnapV Make_OpCode_ESC(13) /* CFF Private, CFF2 Private */
|
||||
#define OpCode_ForceBold Make_OpCode_ESC(14) /* CFF Private (false) */
|
||||
#define OpCode_reservedESC15 Make_OpCode_ESC(15)
|
||||
#define OpCode_reservedESC16 Make_OpCode_ESC(16)
|
||||
#define OpCode_LanguageGroup Make_OpCode_ESC(17) /* CFF Private, CFF2 Private (0) */
|
||||
#define OpCode_ExpansionFactor Make_OpCode_ESC(18) /* CFF Private, CFF2 Private (0.06) */
|
||||
#define OpCode_initialRandomSeed Make_OpCode_ESC(19) /* CFF Private (0) */
|
||||
#define OpCode_SyntheticBase Make_OpCode_ESC(20) /* CFF Top */
|
||||
#define OpCode_PostScript Make_OpCode_ESC(21) /* CFF Top */
|
||||
#define OpCode_BaseFontName Make_OpCode_ESC(22) /* CFF Top */
|
||||
#define OpCode_BaseFontBlend Make_OpCode_ESC(23) /* CFF Top */
|
||||
#define OpCode_reservedESC24 Make_OpCode_ESC(24)
|
||||
#define OpCode_reservedESC25 Make_OpCode_ESC(25)
|
||||
#define OpCode_reservedESC26 Make_OpCode_ESC(26)
|
||||
#define OpCode_reservedESC27 Make_OpCode_ESC(27)
|
||||
#define OpCode_reservedESC28 Make_OpCode_ESC(28)
|
||||
#define OpCode_reservedESC29 Make_OpCode_ESC(29)
|
||||
#define OpCode_ROS Make_OpCode_ESC(30) /* CFF Top_CID */
|
||||
#define OpCode_CIDFontVersion Make_OpCode_ESC(31) /* CFF Top_CID (0) */
|
||||
#define OpCode_CIDFontRevision Make_OpCode_ESC(32) /* CFF Top_CID (0) */
|
||||
#define OpCode_CIDFontType Make_OpCode_ESC(33) /* CFF Top_CID (0) */
|
||||
#define OpCode_CIDCount Make_OpCode_ESC(34) /* CFF Top_CID (8720) */
|
||||
#define OpCode_UIDBase Make_OpCode_ESC(35) /* CFF Top_CID */
|
||||
#define OpCode_FDArray Make_OpCode_ESC(36) /* CFF Top_CID, CFF2 Top */
|
||||
#define OpCode_FDSelect Make_OpCode_ESC(37) /* CFF Top_CID, CFF2 Top */
|
||||
#define OpCode_FontName Make_OpCode_ESC(38) /* CFF Top_CID */
|
||||
|
||||
|
||||
/* === CharString operators === */
|
||||
|
||||
#define OpCode_hstem 1 /* CFF, CFF2 */
|
||||
#define OpCode_Reserved2 2
|
||||
#define OpCode_vstem 3 /* CFF, CFF2 */
|
||||
#define OpCode_vmoveto 4 /* CFF, CFF2 */
|
||||
#define OpCode_rlineto 5 /* CFF, CFF2 */
|
||||
#define OpCode_hlineto 6 /* CFF, CFF2 */
|
||||
#define OpCode_vlineto 7 /* CFF, CFF2 */
|
||||
#define OpCode_rrcurveto 8 /* CFF, CFF2 */
|
||||
#define OpCode_Reserved9 9
|
||||
#define OpCode_callsubr 10 /* CFF, CFF2 */
|
||||
#define OpCode_return 11 /* CFF */
|
||||
//#define OpCode_escape 12 /* CFF, CFF2 */
|
||||
#define OpCode_Reserved13 13
|
||||
#define OpCode_endchar 14 /* CFF */
|
||||
#define OpCode_vsindexcs 15 /* CFF2 */
|
||||
#define OpCode_blendcs 16 /* CFF2 */
|
||||
#define OpCode_Reserved17 17
|
||||
#define OpCode_hstemhm 18 /* CFF, CFF2 */
|
||||
#define OpCode_hintmask 19 /* CFF, CFF2 */
|
||||
#define OpCode_cntrmask 20 /* CFF, CFF2 */
|
||||
#define OpCode_rmoveto 21 /* CFF, CFF2 */
|
||||
#define OpCode_hmoveto 22 /* CFF, CFF2 */
|
||||
#define OpCode_vstemhm 23 /* CFF, CFF2 */
|
||||
#define OpCode_rcurveline 24 /* CFF, CFF2 */
|
||||
#define OpCode_rlinecurve 25 /* CFF, CFF2 */
|
||||
#define OpCode_vvcurveto 26 /* CFF, CFF2 */
|
||||
#define OpCode_hhcurveto 27 /* CFF, CFF2 */
|
||||
//#define OpCode_shortint 28 /* CFF, CFF2 */
|
||||
#define OpCode_callgsubr 29 /* CFF, CFF2 */
|
||||
#define OpCode_vhcurveto 30 /* CFF, CFF2 */
|
||||
#define OpCode_hvcurveto 31 /* CFF, CFF2 */
|
||||
|
||||
#define OpCode_fixedcs 255 /* 32-bit fixed */
|
||||
|
||||
/* Two byte escape operators 12, (0-41) */
|
||||
#define OpCode_dotsection Make_OpCode_ESC(0) /* CFF (obsoleted) */
|
||||
#define OpCode_ReservedESC1 Make_OpCode_ESC(1)
|
||||
#define OpCode_ReservedESC2 Make_OpCode_ESC(2)
|
||||
#define OpCode_and Make_OpCode_ESC(3) /* CFF */
|
||||
#define OpCode_or Make_OpCode_ESC(4) /* CFF */
|
||||
#define OpCode_not Make_OpCode_ESC(5) /* CFF */
|
||||
#define OpCode_ReservedESC6 Make_OpCode_ESC(6)
|
||||
#define OpCode_ReservedESC7 Make_OpCode_ESC(7)
|
||||
#define OpCode_ReservedESC8 Make_OpCode_ESC(8)
|
||||
#define OpCode_abs Make_OpCode_ESC(9) /* CFF */
|
||||
#define OpCode_add Make_OpCode_ESC(10) /* CFF */
|
||||
#define OpCode_sub Make_OpCode_ESC(11) /* CFF */
|
||||
#define OpCode_div Make_OpCode_ESC(12) /* CFF */
|
||||
#define OpCode_ReservedESC13 Make_OpCode_ESC(13)
|
||||
#define OpCode_neg Make_OpCode_ESC(14) /* CFF */
|
||||
#define OpCode_eq Make_OpCode_ESC(15) /* CFF */
|
||||
#define OpCode_ReservedESC16 Make_OpCode_ESC(16)
|
||||
#define OpCode_ReservedESC17 Make_OpCode_ESC(17)
|
||||
#define OpCode_drop Make_OpCode_ESC(18) /* CFF */
|
||||
#define OpCode_ReservedESC19 Make_OpCode_ESC(19)
|
||||
#define OpCode_put Make_OpCode_ESC(20) /* CFF */
|
||||
#define OpCode_get Make_OpCode_ESC(21) /* CFF */
|
||||
#define OpCode_ifelse Make_OpCode_ESC(22) /* CFF */
|
||||
#define OpCode_random Make_OpCode_ESC(23) /* CFF */
|
||||
#define OpCode_mul Make_OpCode_ESC(24) /* CFF */
|
||||
//#define OpCode_reservedESC25 Make_OpCode_ESC(25)
|
||||
#define OpCode_sqrt Make_OpCode_ESC(26) /* CFF */
|
||||
#define OpCode_dup Make_OpCode_ESC(27) /* CFF */
|
||||
#define OpCode_exch Make_OpCode_ESC(28) /* CFF */
|
||||
#define OpCode_index Make_OpCode_ESC(29) /* CFF */
|
||||
#define OpCode_roll Make_OpCode_ESC(30) /* CFF */
|
||||
#define OpCode_reservedESC31 Make_OpCode_ESC(31)
|
||||
#define OpCode_reservedESC32 Make_OpCode_ESC(32)
|
||||
#define OpCode_reservedESC33 Make_OpCode_ESC(33)
|
||||
#define OpCode_hflex Make_OpCode_ESC(34) /* CFF, CFF2 */
|
||||
#define OpCode_flex Make_OpCode_ESC(35) /* CFF, CFF2 */
|
||||
#define OpCode_hflex1 Make_OpCode_ESC(36) /* CFF, CFF2 */
|
||||
#define OpCode_flex1 Make_OpCode_ESC(37) /* CFF, CFF2 */
|
||||
|
||||
|
||||
#define OpCode_Invalid 0xFFFFu
|
||||
|
||||
|
||||
struct number_t
|
||||
{
|
||||
void init () { set_real (0.0); }
|
||||
void fini () {}
|
||||
|
||||
void set_int (int v) { value = v; }
|
||||
int to_int () const { return value; }
|
||||
|
||||
void set_fixed (int32_t v) { value = v / 65536.0; }
|
||||
int32_t to_fixed () const { return value * 65536.0; }
|
||||
|
||||
void set_real (double v) { value = v; }
|
||||
double to_real () const { return value; }
|
||||
|
||||
bool in_int_range () const
|
||||
{ return ((double) (int16_t) to_int () == value); }
|
||||
|
||||
bool operator > (const number_t &n) const { return value > n.to_real (); }
|
||||
bool operator < (const number_t &n) const { return n > *this; }
|
||||
bool operator >= (const number_t &n) const { return !(*this < n); }
|
||||
bool operator <= (const number_t &n) const { return !(*this > n); }
|
||||
|
||||
const number_t &operator += (const number_t &n)
|
||||
{
|
||||
set_real (to_real () + n.to_real ());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
double value;
|
||||
};
|
||||
|
||||
/* byte string */
|
||||
struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
|
||||
{
|
||||
// encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
|
||||
template <typename INTTYPE, int minVal, int maxVal>
|
||||
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (unlikely ((value < minVal || value > maxVal)))
|
||||
return_trace (false);
|
||||
|
||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
||||
if (unlikely (p == nullptr)) return_trace (false);
|
||||
*p = intOp;
|
||||
|
||||
INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
|
||||
if (unlikely (ip == nullptr)) return_trace (false);
|
||||
*ip = (unsigned int) value;
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
static bool serialize_int4 (hb_serialize_context_t *c, int value)
|
||||
{ return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); }
|
||||
|
||||
static bool serialize_int2 (hb_serialize_context_t *c, int value)
|
||||
{ return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); }
|
||||
|
||||
/* Defining null_size allows a Null object may be created. Should be safe because:
|
||||
* A descendent struct Dict uses a Null pointer to indicate a missing table,
|
||||
* checked before access.
|
||||
* byte_str_t, a wrapper struct pairing a byte pointer along with its length, always
|
||||
* checks the length before access. A Null pointer is used as the initial pointer
|
||||
* along with zero length by the default ctor.
|
||||
*/
|
||||
DEFINE_SIZE_MIN(0);
|
||||
};
|
||||
|
||||
/* Holder of a section of byte string within a CFFIndex entry */
|
||||
struct byte_str_t : hb_ubytes_t
|
||||
{
|
||||
byte_str_t ()
|
||||
: hb_ubytes_t () {}
|
||||
byte_str_t (const UnsizedByteStr& s, unsigned int l)
|
||||
: hb_ubytes_t ((const unsigned char*)&s, l) {}
|
||||
byte_str_t (const unsigned char *s, unsigned int l)
|
||||
: hb_ubytes_t (s, l) {}
|
||||
byte_str_t (const hb_ubytes_t &ub) /* conversion from hb_ubytes_t */
|
||||
: hb_ubytes_t (ub) {}
|
||||
|
||||
/* sub-string */
|
||||
byte_str_t sub_str (unsigned int offset, unsigned int len_) const
|
||||
{ return byte_str_t (hb_ubytes_t::sub_array (offset, len_)); }
|
||||
|
||||
bool check_limit (unsigned int offset, unsigned int count) const
|
||||
{ return (offset + count <= length); }
|
||||
};
|
||||
|
||||
/* A byte string associated with the current offset and an error condition */
|
||||
struct byte_str_ref_t
|
||||
{
|
||||
byte_str_ref_t () { init (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
str = byte_str_t ();
|
||||
offset = 0;
|
||||
error = false;
|
||||
}
|
||||
|
||||
void fini () {}
|
||||
|
||||
byte_str_ref_t (const byte_str_t &str_, unsigned int offset_ = 0)
|
||||
: str (str_), offset (offset_), error (false) {}
|
||||
|
||||
void reset (const byte_str_t &str_, unsigned int offset_ = 0)
|
||||
{
|
||||
str = str_;
|
||||
offset = offset_;
|
||||
error = false;
|
||||
}
|
||||
|
||||
const unsigned char& operator [] (int i) {
|
||||
if (unlikely ((unsigned int) (offset + i) >= str.length))
|
||||
{
|
||||
set_error ();
|
||||
return Null (unsigned char);
|
||||
}
|
||||
return str[offset + i];
|
||||
}
|
||||
|
||||
/* Conversion to byte_str_t */
|
||||
operator byte_str_t () const { return str.sub_str (offset, str.length - offset); }
|
||||
|
||||
byte_str_t sub_str (unsigned int offset_, unsigned int len_) const
|
||||
{ return str.sub_str (offset_, len_); }
|
||||
|
||||
bool avail (unsigned int count=1) const
|
||||
{ return (!in_error () && str.check_limit (offset, count)); }
|
||||
void inc (unsigned int count=1)
|
||||
{
|
||||
if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
|
||||
{
|
||||
offset += count;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = str.length;
|
||||
set_error ();
|
||||
}
|
||||
}
|
||||
|
||||
void set_error () { error = true; }
|
||||
bool in_error () const { return error; }
|
||||
|
||||
byte_str_t str;
|
||||
unsigned int offset; /* beginning of the sub-string within str */
|
||||
|
||||
protected:
|
||||
bool error;
|
||||
};
|
||||
|
||||
typedef hb_vector_t<byte_str_t> byte_str_array_t;
|
||||
|
||||
/* stack */
|
||||
template <typename ELEM, int LIMIT>
|
||||
struct cff_stack_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
error = false;
|
||||
count = 0;
|
||||
elements.init ();
|
||||
elements.resize (kSizeLimit);
|
||||
for (unsigned int i = 0; i < elements.length; i++)
|
||||
elements[i].init ();
|
||||
}
|
||||
void fini () { elements.fini_deep (); }
|
||||
|
||||
ELEM& operator [] (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= count)) set_error ();
|
||||
return elements[i];
|
||||
}
|
||||
|
||||
void push (const ELEM &v)
|
||||
{
|
||||
if (likely (count < elements.length))
|
||||
elements[count++] = v;
|
||||
else
|
||||
set_error ();
|
||||
}
|
||||
ELEM &push ()
|
||||
{
|
||||
if (likely (count < elements.length))
|
||||
return elements[count++];
|
||||
else
|
||||
{
|
||||
set_error ();
|
||||
return Crap(ELEM);
|
||||
}
|
||||
}
|
||||
|
||||
ELEM& pop ()
|
||||
{
|
||||
if (likely (count > 0))
|
||||
return elements[--count];
|
||||
else
|
||||
{
|
||||
set_error ();
|
||||
return Crap(ELEM);
|
||||
}
|
||||
}
|
||||
void pop (unsigned int n)
|
||||
{
|
||||
if (likely (count >= n))
|
||||
count -= n;
|
||||
else
|
||||
set_error ();
|
||||
}
|
||||
|
||||
const ELEM& peek ()
|
||||
{
|
||||
if (unlikely (count < 0))
|
||||
{
|
||||
set_error ();
|
||||
return Null(ELEM);
|
||||
}
|
||||
return elements[count - 1];
|
||||
}
|
||||
|
||||
void unpop ()
|
||||
{
|
||||
if (likely (count < elements.length))
|
||||
count++;
|
||||
else
|
||||
set_error ();
|
||||
}
|
||||
|
||||
void clear () { count = 0; }
|
||||
|
||||
bool in_error () const { return (error || elements.in_error ()); }
|
||||
void set_error () { error = true; }
|
||||
|
||||
unsigned int get_count () const { return count; }
|
||||
bool is_empty () const { return !count; }
|
||||
|
||||
static constexpr unsigned kSizeLimit = LIMIT;
|
||||
|
||||
protected:
|
||||
bool error;
|
||||
unsigned int count;
|
||||
hb_vector_t<ELEM> elements;
|
||||
};
|
||||
|
||||
/* argument stack */
|
||||
template <typename ARG=number_t>
|
||||
struct arg_stack_t : cff_stack_t<ARG, 513>
|
||||
{
|
||||
void push_int (int v)
|
||||
{
|
||||
ARG &n = S::push ();
|
||||
n.set_int (v);
|
||||
}
|
||||
|
||||
void push_fixed (int32_t v)
|
||||
{
|
||||
ARG &n = S::push ();
|
||||
n.set_fixed (v);
|
||||
}
|
||||
|
||||
void push_real (double v)
|
||||
{
|
||||
ARG &n = S::push ();
|
||||
n.set_real (v);
|
||||
}
|
||||
|
||||
ARG& pop_num () { return this->pop (); }
|
||||
|
||||
int pop_int () { return this->pop ().to_int (); }
|
||||
|
||||
unsigned int pop_uint ()
|
||||
{
|
||||
int i = pop_int ();
|
||||
if (unlikely (i < 0))
|
||||
{
|
||||
i = 0;
|
||||
S::set_error ();
|
||||
}
|
||||
return (unsigned) i;
|
||||
}
|
||||
|
||||
void push_longint_from_substr (byte_str_ref_t& str_ref)
|
||||
{
|
||||
push_int ((str_ref[0] << 24) | (str_ref[1] << 16) | (str_ref[2] << 8) | (str_ref[3]));
|
||||
str_ref.inc (4);
|
||||
}
|
||||
|
||||
bool push_fixed_from_substr (byte_str_ref_t& str_ref)
|
||||
{
|
||||
if (unlikely (!str_ref.avail (4)))
|
||||
return false;
|
||||
push_fixed ((int32_t)*(const HBUINT32*)&str_ref[0]);
|
||||
str_ref.inc (4);
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_array_t<const ARG> get_subarray (unsigned int start) const
|
||||
{ return S::elements.sub_array (start); }
|
||||
|
||||
private:
|
||||
typedef cff_stack_t<ARG, 513> S;
|
||||
};
|
||||
|
||||
/* an operator prefixed by its operands in a byte string */
|
||||
struct op_str_t
|
||||
{
|
||||
void init () {}
|
||||
void fini () {}
|
||||
|
||||
op_code_t op;
|
||||
byte_str_t str;
|
||||
};
|
||||
|
||||
/* base of OP_SERIALIZER */
|
||||
struct op_serializer_t
|
||||
{
|
||||
protected:
|
||||
bool copy_opstr (hb_serialize_context_t *c, const op_str_t& opstr) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
|
||||
if (unlikely (d == nullptr)) return_trace (false);
|
||||
memcpy (d, &opstr.str[0], opstr.str.length);
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VAL>
|
||||
struct parsed_values_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
opStart = 0;
|
||||
values.init ();
|
||||
}
|
||||
void fini () { values.fini_deep (); }
|
||||
|
||||
void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ())
|
||||
{
|
||||
VAL *val = values.push ();
|
||||
val->op = op;
|
||||
val->str = str_ref.str.sub_str (opStart, str_ref.offset - opStart);
|
||||
opStart = str_ref.offset;
|
||||
}
|
||||
|
||||
void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
|
||||
{
|
||||
VAL *val = values.push (v);
|
||||
val->op = op;
|
||||
val->str = str_ref.sub_str ( opStart, str_ref.offset - opStart);
|
||||
opStart = str_ref.offset;
|
||||
}
|
||||
|
||||
bool has_op (op_code_t op) const
|
||||
{
|
||||
for (unsigned int i = 0; i < get_count (); i++)
|
||||
if (get_value (i).op == op) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned get_count () const { return values.length; }
|
||||
const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
const VAL &operator [] (unsigned int i) const { return get_value (i); }
|
||||
|
||||
unsigned int opStart;
|
||||
hb_vector_t<VAL> values;
|
||||
};
|
||||
|
||||
template <typename ARG=number_t>
|
||||
struct interp_env_t
|
||||
{
|
||||
void init (const byte_str_t &str_)
|
||||
{
|
||||
str_ref.reset (str_);
|
||||
argStack.init ();
|
||||
error = false;
|
||||
}
|
||||
void fini () { argStack.fini (); }
|
||||
|
||||
bool in_error () const
|
||||
{ return error || str_ref.in_error () || argStack.in_error (); }
|
||||
|
||||
void set_error () { error = true; }
|
||||
|
||||
op_code_t fetch_op ()
|
||||
{
|
||||
op_code_t op = OpCode_Invalid;
|
||||
if (unlikely (!str_ref.avail ()))
|
||||
return OpCode_Invalid;
|
||||
op = (op_code_t)(unsigned char)str_ref[0];
|
||||
if (op == OpCode_escape) {
|
||||
if (unlikely (!str_ref.avail ()))
|
||||
return OpCode_Invalid;
|
||||
op = Make_OpCode_ESC(str_ref[1]);
|
||||
str_ref.inc ();
|
||||
}
|
||||
str_ref.inc ();
|
||||
return op;
|
||||
}
|
||||
|
||||
const ARG& eval_arg (unsigned int i) { return argStack[i]; }
|
||||
|
||||
ARG& pop_arg () { return argStack.pop (); }
|
||||
void pop_n_args (unsigned int n) { argStack.pop (n); }
|
||||
|
||||
void clear_args () { pop_n_args (argStack.get_count ()); }
|
||||
|
||||
byte_str_ref_t
|
||||
str_ref;
|
||||
arg_stack_t<ARG>
|
||||
argStack;
|
||||
protected:
|
||||
bool error;
|
||||
};
|
||||
|
||||
typedef interp_env_t<> num_interp_env_t;
|
||||
|
||||
template <typename ARG=number_t>
|
||||
struct opset_t
|
||||
{
|
||||
static void process_op (op_code_t op, interp_env_t<ARG>& env)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_shortint:
|
||||
env.argStack.push_int ((int16_t)((env.str_ref[0] << 8) | env.str_ref[1]));
|
||||
env.str_ref.inc (2);
|
||||
break;
|
||||
|
||||
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
|
||||
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
|
||||
env.argStack.push_int ((int16_t)((op - OpCode_TwoBytePosInt0) * 256 + env.str_ref[0] + 108));
|
||||
env.str_ref.inc ();
|
||||
break;
|
||||
|
||||
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
|
||||
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
|
||||
env.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
|
||||
env.str_ref.inc ();
|
||||
break;
|
||||
|
||||
default:
|
||||
/* 1-byte integer */
|
||||
if (likely ((OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast)))
|
||||
{
|
||||
env.argStack.push_int ((int)op - 139);
|
||||
} else {
|
||||
/* invalid unknown operator */
|
||||
env.clear_args ();
|
||||
env.set_error ();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ENV>
|
||||
struct interpreter_t
|
||||
{
|
||||
~interpreter_t() { fini (); }
|
||||
|
||||
void fini () { env.fini (); }
|
||||
|
||||
ENV env;
|
||||
};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_CFF_INTERP_COMMON_HH */
|
||||
|
|
@ -0,0 +1,906 @@
|
|||
/*
|
||||
* Copyright © 2018 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
#ifndef HB_CFF_INTERP_CS_COMMON_HH
|
||||
#define HB_CFF_INTERP_CS_COMMON_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-cff-interp-common.hh"
|
||||
|
||||
namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
enum cs_type_t {
|
||||
CSType_CharString,
|
||||
CSType_GlobalSubr,
|
||||
CSType_LocalSubr
|
||||
};
|
||||
|
||||
struct call_context_t
|
||||
{
|
||||
void init (const byte_str_ref_t substr_=byte_str_ref_t (), cs_type_t type_=CSType_CharString, unsigned int subr_num_=0)
|
||||
{
|
||||
str_ref = substr_;
|
||||
type = type_;
|
||||
subr_num = subr_num_;
|
||||
}
|
||||
|
||||
void fini () {}
|
||||
|
||||
byte_str_ref_t str_ref;
|
||||
cs_type_t type;
|
||||
unsigned int subr_num;
|
||||
};
|
||||
|
||||
/* call stack */
|
||||
const unsigned int kMaxCallLimit = 10;
|
||||
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
|
||||
|
||||
template <typename SUBRS>
|
||||
struct biased_subrs_t
|
||||
{
|
||||
void init (const SUBRS *subrs_)
|
||||
{
|
||||
subrs = subrs_;
|
||||
unsigned int nSubrs = get_count ();
|
||||
if (nSubrs < 1240)
|
||||
bias = 107;
|
||||
else if (nSubrs < 33900)
|
||||
bias = 1131;
|
||||
else
|
||||
bias = 32768;
|
||||
}
|
||||
|
||||
void fini () {}
|
||||
|
||||
unsigned int get_count () const { return (subrs == nullptr) ? 0 : subrs->count; }
|
||||
unsigned int get_bias () const { return bias; }
|
||||
|
||||
byte_str_t operator [] (unsigned int index) const
|
||||
{
|
||||
if (unlikely ((subrs == nullptr) || index >= subrs->count))
|
||||
return Null(byte_str_t);
|
||||
else
|
||||
return (*subrs)[index];
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int bias;
|
||||
const SUBRS *subrs;
|
||||
};
|
||||
|
||||
struct point_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
x.init ();
|
||||
y.init ();
|
||||
}
|
||||
|
||||
void set_int (int _x, int _y)
|
||||
{
|
||||
x.set_int (_x);
|
||||
y.set_int (_y);
|
||||
}
|
||||
|
||||
void move_x (const number_t &dx) { x += dx; }
|
||||
void move_y (const number_t &dy) { y += dy; }
|
||||
void move (const number_t &dx, const number_t &dy) { move_x (dx); move_y (dy); }
|
||||
void move (const point_t &d) { move_x (d.x); move_y (d.y); }
|
||||
|
||||
number_t x;
|
||||
number_t y;
|
||||
};
|
||||
|
||||
template <typename ARG, typename SUBRS>
|
||||
struct cs_interp_env_t : interp_env_t<ARG>
|
||||
{
|
||||
void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
|
||||
{
|
||||
interp_env_t<ARG>::init (str);
|
||||
|
||||
context.init (str, CSType_CharString);
|
||||
seen_moveto = true;
|
||||
seen_hintmask = false;
|
||||
hstem_count = 0;
|
||||
vstem_count = 0;
|
||||
hintmask_size = 0;
|
||||
pt.init ();
|
||||
callStack.init ();
|
||||
globalSubrs.init (globalSubrs_);
|
||||
localSubrs.init (localSubrs_);
|
||||
}
|
||||
void fini ()
|
||||
{
|
||||
interp_env_t<ARG>::fini ();
|
||||
|
||||
callStack.fini ();
|
||||
globalSubrs.fini ();
|
||||
localSubrs.fini ();
|
||||
}
|
||||
|
||||
bool in_error () const
|
||||
{
|
||||
return callStack.in_error () || SUPER::in_error ();
|
||||
}
|
||||
|
||||
bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
{
|
||||
subr_num = 0;
|
||||
int n = SUPER::argStack.pop_int ();
|
||||
n += biasedSubrs.get_bias ();
|
||||
if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
|
||||
return false;
|
||||
|
||||
subr_num = (unsigned int)n;
|
||||
return true;
|
||||
}
|
||||
|
||||
void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
{
|
||||
unsigned int subr_num = 0;
|
||||
|
||||
if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
|
||||
|| callStack.get_count () >= kMaxCallLimit))
|
||||
{
|
||||
SUPER::set_error ();
|
||||
return;
|
||||
}
|
||||
context.str_ref = SUPER::str_ref;
|
||||
callStack.push (context);
|
||||
|
||||
context.init ( biasedSubrs[subr_num], type, subr_num);
|
||||
SUPER::str_ref = context.str_ref;
|
||||
}
|
||||
|
||||
void return_from_subr ()
|
||||
{
|
||||
if (unlikely (SUPER::str_ref.in_error ()))
|
||||
SUPER::set_error ();
|
||||
context = callStack.pop ();
|
||||
SUPER::str_ref = context.str_ref;
|
||||
}
|
||||
|
||||
void determine_hintmask_size ()
|
||||
{
|
||||
if (!seen_hintmask)
|
||||
{
|
||||
vstem_count += SUPER::argStack.get_count() / 2;
|
||||
hintmask_size = (hstem_count + vstem_count + 7) >> 3;
|
||||
seen_hintmask = true;
|
||||
}
|
||||
}
|
||||
|
||||
void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
|
||||
bool is_endchar () const { return endchar_flag; }
|
||||
|
||||
const number_t &get_x () const { return pt.x; }
|
||||
const number_t &get_y () const { return pt.y; }
|
||||
const point_t &get_pt () const { return pt; }
|
||||
|
||||
void moveto (const point_t &pt_ ) { pt = pt_; }
|
||||
|
||||
public:
|
||||
call_context_t context;
|
||||
bool endchar_flag;
|
||||
bool seen_moveto;
|
||||
bool seen_hintmask;
|
||||
|
||||
unsigned int hstem_count;
|
||||
unsigned int vstem_count;
|
||||
unsigned int hintmask_size;
|
||||
call_stack_t callStack;
|
||||
biased_subrs_t<SUBRS> globalSubrs;
|
||||
biased_subrs_t<SUBRS> localSubrs;
|
||||
|
||||
private:
|
||||
point_t pt;
|
||||
|
||||
typedef interp_env_t<ARG> SUPER;
|
||||
};
|
||||
|
||||
template <typename ENV, typename PARAM>
|
||||
struct path_procs_null_t
|
||||
{
|
||||
static void rmoveto (ENV &env, PARAM& param) {}
|
||||
static void hmoveto (ENV &env, PARAM& param) {}
|
||||
static void vmoveto (ENV &env, PARAM& param) {}
|
||||
static void rlineto (ENV &env, PARAM& param) {}
|
||||
static void hlineto (ENV &env, PARAM& param) {}
|
||||
static void vlineto (ENV &env, PARAM& param) {}
|
||||
static void rrcurveto (ENV &env, PARAM& param) {}
|
||||
static void rcurveline (ENV &env, PARAM& param) {}
|
||||
static void rlinecurve (ENV &env, PARAM& param) {}
|
||||
static void vvcurveto (ENV &env, PARAM& param) {}
|
||||
static void hhcurveto (ENV &env, PARAM& param) {}
|
||||
static void vhcurveto (ENV &env, PARAM& param) {}
|
||||
static void hvcurveto (ENV &env, PARAM& param) {}
|
||||
static void moveto (ENV &env, PARAM& param, const point_t &pt) {}
|
||||
static void line (ENV &env, PARAM& param, const point_t &pt1) {}
|
||||
static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) {}
|
||||
static void hflex (ENV &env, PARAM& param) {}
|
||||
static void flex (ENV &env, PARAM& param) {}
|
||||
static void hflex1 (ENV &env, PARAM& param) {}
|
||||
static void flex1 (ENV &env, PARAM& param) {}
|
||||
};
|
||||
|
||||
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
|
||||
struct cs_opset_t : opset_t<ARG>
|
||||
{
|
||||
static void process_op (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
switch (op) {
|
||||
|
||||
case OpCode_return:
|
||||
env.return_from_subr ();
|
||||
break;
|
||||
case OpCode_endchar:
|
||||
OPSET::check_width (op, env, param);
|
||||
env.set_endchar (true);
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_fixedcs:
|
||||
env.argStack.push_fixed_from_substr (env.str_ref);
|
||||
break;
|
||||
|
||||
case OpCode_callsubr:
|
||||
env.call_subr (env.localSubrs, CSType_LocalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
env.call_subr (env.globalSubrs, CSType_GlobalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_hstem:
|
||||
case OpCode_hstemhm:
|
||||
OPSET::check_width (op, env, param);
|
||||
OPSET::process_hstem (op, env, param);
|
||||
break;
|
||||
case OpCode_vstem:
|
||||
case OpCode_vstemhm:
|
||||
OPSET::check_width (op, env, param);
|
||||
OPSET::process_vstem (op, env, param);
|
||||
break;
|
||||
case OpCode_hintmask:
|
||||
case OpCode_cntrmask:
|
||||
OPSET::check_width (op, env, param);
|
||||
OPSET::process_hintmask (op, env, param);
|
||||
break;
|
||||
case OpCode_rmoveto:
|
||||
OPSET::check_width (op, env, param);
|
||||
PATH::rmoveto (env, param);
|
||||
OPSET::process_post_move (op, env, param);
|
||||
break;
|
||||
case OpCode_hmoveto:
|
||||
OPSET::check_width (op, env, param);
|
||||
PATH::hmoveto (env, param);
|
||||
OPSET::process_post_move (op, env, param);
|
||||
break;
|
||||
case OpCode_vmoveto:
|
||||
OPSET::check_width (op, env, param);
|
||||
PATH::vmoveto (env, param);
|
||||
OPSET::process_post_move (op, env, param);
|
||||
break;
|
||||
case OpCode_rlineto:
|
||||
PATH::rlineto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_hlineto:
|
||||
PATH::hlineto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_vlineto:
|
||||
PATH::vlineto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_rrcurveto:
|
||||
PATH::rrcurveto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_rcurveline:
|
||||
PATH::rcurveline (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_rlinecurve:
|
||||
PATH::rlinecurve (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_vvcurveto:
|
||||
PATH::vvcurveto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_hhcurveto:
|
||||
PATH::hhcurveto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_vhcurveto:
|
||||
PATH::vhcurveto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
case OpCode_hvcurveto:
|
||||
PATH::hvcurveto (env, param);
|
||||
process_post_path (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_hflex:
|
||||
PATH::hflex (env, param);
|
||||
OPSET::process_post_flex (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_flex:
|
||||
PATH::flex (env, param);
|
||||
OPSET::process_post_flex (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_hflex1:
|
||||
PATH::hflex1 (env, param);
|
||||
OPSET::process_post_flex (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_flex1:
|
||||
PATH::flex1 (env, param);
|
||||
OPSET::process_post_flex (op, env, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
SUPER::process_op (op, env);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_hstem (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
env.hstem_count += env.argStack.get_count () / 2;
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static void process_vstem (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
env.vstem_count += env.argStack.get_count () / 2;
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static void process_hintmask (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
env.determine_hintmask_size ();
|
||||
if (likely (env.str_ref.avail (env.hintmask_size)))
|
||||
{
|
||||
OPSET::flush_hintmask (op, env, param);
|
||||
env.str_ref.inc (env.hintmask_size);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_post_flex (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static void check_width (op_code_t op, ENV &env, PARAM& param)
|
||||
{}
|
||||
|
||||
static void process_post_move (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
if (!env.seen_moveto)
|
||||
{
|
||||
env.determine_hintmask_size ();
|
||||
env.seen_moveto = true;
|
||||
}
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static void process_post_path (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static void flush_args_and_op (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
OPSET::flush_args (env, param);
|
||||
OPSET::flush_op (op, env, param);
|
||||
}
|
||||
|
||||
static void flush_args (ENV &env, PARAM& param)
|
||||
{
|
||||
env.pop_n_args (env.argStack.get_count ());
|
||||
}
|
||||
|
||||
static void flush_op (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
}
|
||||
|
||||
static void flush_hintmask (op_code_t op, ENV &env, PARAM& param)
|
||||
{
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
}
|
||||
|
||||
static bool is_number_op (op_code_t op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_shortint:
|
||||
case OpCode_fixedcs:
|
||||
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1:
|
||||
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3:
|
||||
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
|
||||
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* 1-byte integer */
|
||||
return (OpCode_OneByteIntFirst <= op) && (op <= OpCode_OneByteIntLast);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
typedef opset_t<ARG> SUPER;
|
||||
};
|
||||
|
||||
template <typename PATH, typename ENV, typename PARAM>
|
||||
struct path_procs_t
|
||||
{
|
||||
static void rmoveto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
const number_t &dy = env.pop_arg ();
|
||||
const number_t &dx = env.pop_arg ();
|
||||
pt1.move (dx, dy);
|
||||
PATH::moveto (env, param, pt1);
|
||||
}
|
||||
|
||||
static void hmoveto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move_x (env.pop_arg ());
|
||||
PATH::moveto (env, param, pt1);
|
||||
}
|
||||
|
||||
static void vmoveto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move_y (env.pop_arg ());
|
||||
PATH::moveto (env, param, pt1);
|
||||
}
|
||||
|
||||
static void rlineto (ENV &env, PARAM& param)
|
||||
{
|
||||
for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
}
|
||||
|
||||
static void hlineto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1;
|
||||
unsigned int i = 0;
|
||||
for (; i + 2 <= env.argStack.get_count (); i += 2)
|
||||
{
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_x (env.eval_arg (i));
|
||||
PATH::line (env, param, pt1);
|
||||
pt1.move_y (env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
if (i < env.argStack.get_count ())
|
||||
{
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_x (env.eval_arg (i));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
}
|
||||
|
||||
static void vlineto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1;
|
||||
unsigned int i = 0;
|
||||
for (; i + 2 <= env.argStack.get_count (); i += 2)
|
||||
{
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_y (env.eval_arg (i));
|
||||
PATH::line (env, param, pt1);
|
||||
pt1.move_x (env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
if (i < env.argStack.get_count ())
|
||||
{
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_y (env.eval_arg (i));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
}
|
||||
|
||||
static void rrcurveto (ENV &env, PARAM& param)
|
||||
{
|
||||
for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
}
|
||||
|
||||
static void rcurveline (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for (; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
for (; i + 2 <= env.argStack.get_count (); i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
}
|
||||
|
||||
static void rlinecurve (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned int line_limit = (env.argStack.get_count () % 6);
|
||||
for (; i + 2 <= line_limit; i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
for (; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
}
|
||||
|
||||
static void vvcurveto (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
point_t pt1 = env.get_pt ();
|
||||
if ((env.argStack.get_count () & 1) != 0)
|
||||
pt1.move_x (env.eval_arg (i++));
|
||||
for (; i + 4 <= env.argStack.get_count (); i += 4)
|
||||
{
|
||||
pt1.move_y (env.eval_arg (i));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move_y (env.eval_arg (i+3));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
pt1 = env.get_pt ();
|
||||
}
|
||||
}
|
||||
|
||||
static void hhcurveto (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
point_t pt1 = env.get_pt ();
|
||||
if ((env.argStack.get_count () & 1) != 0)
|
||||
pt1.move_y (env.eval_arg (i++));
|
||||
for (; i + 4 <= env.argStack.get_count (); i += 4)
|
||||
{
|
||||
pt1.move_x (env.eval_arg (i));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (i+3));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
pt1 = env.get_pt ();
|
||||
}
|
||||
}
|
||||
|
||||
static void vhcurveto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1, pt2, pt3;
|
||||
unsigned int i = 0;
|
||||
if ((env.argStack.get_count () % 8) >= 4)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move_y (env.eval_arg (i));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (i+3));
|
||||
i += 4;
|
||||
|
||||
for (; i + 8 <= env.argStack.get_count (); i += 8)
|
||||
{
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_x (env.eval_arg (i));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
pt3 = pt2;
|
||||
pt3.move_y (env.eval_arg (i+3));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
|
||||
pt1 = pt3;
|
||||
pt1.move_y (env.eval_arg (i+4));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
|
||||
pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (i+7));
|
||||
}
|
||||
if (i < env.argStack.get_count ())
|
||||
pt3.move_y (env.eval_arg (i));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; i + 8 <= env.argStack.get_count (); i += 8)
|
||||
{
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_y (env.eval_arg (i));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (i+3));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
|
||||
pt1 = pt3;
|
||||
pt1.move_x (env.eval_arg (i+4));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
|
||||
pt3 = pt2;
|
||||
pt3.move_y (env.eval_arg (i+7));
|
||||
if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
|
||||
pt3.move_x (env.eval_arg (i+8));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hvcurveto (ENV &env, PARAM& param)
|
||||
{
|
||||
point_t pt1, pt2, pt3;
|
||||
unsigned int i = 0;
|
||||
if ((env.argStack.get_count () % 8) >= 4)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move_x (env.eval_arg (i));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move_y (env.eval_arg (i+3));
|
||||
i += 4;
|
||||
|
||||
for (; i + 8 <= env.argStack.get_count (); i += 8)
|
||||
{
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_y (env.eval_arg (i));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (i+3));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
|
||||
pt1 = pt3;
|
||||
pt1.move_x (env.eval_arg (i+4));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
|
||||
pt3 = pt2;
|
||||
pt3.move_y (env.eval_arg (i+7));
|
||||
}
|
||||
if (i < env.argStack.get_count ())
|
||||
pt3.move_x (env.eval_arg (i));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; i + 8 <= env.argStack.get_count (); i += 8)
|
||||
{
|
||||
pt1 = env.get_pt ();
|
||||
pt1.move_x (env.eval_arg (i));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
|
||||
pt3 = pt2;
|
||||
pt3.move_y (env.eval_arg (i+3));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
|
||||
pt1 = pt3;
|
||||
pt1.move_y (env.eval_arg (i+4));
|
||||
pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
|
||||
pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (i+7));
|
||||
if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
|
||||
pt3.move_y (env.eval_arg (i+8));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* default actions to be overridden */
|
||||
static void moveto (ENV &env, PARAM& param, const point_t &pt)
|
||||
{ env.moveto (pt); }
|
||||
|
||||
static void line (ENV &env, PARAM& param, const point_t &pt1)
|
||||
{ PATH::moveto (env, param, pt1); }
|
||||
|
||||
static void curve (ENV &env, PARAM& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{ PATH::moveto (env, param, pt3); }
|
||||
|
||||
static void hflex (ENV &env, PARAM& param)
|
||||
{
|
||||
if (likely (env.argStack.get_count () == 7))
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move_x (env.eval_arg (0));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (1), env.eval_arg (2));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (3));
|
||||
point_t pt4 = pt3;
|
||||
pt4.move_x (env.eval_arg (4));
|
||||
point_t pt5 = pt4;
|
||||
pt5.move_x (env.eval_arg (5));
|
||||
pt5.y = pt1.y;
|
||||
point_t pt6 = pt5;
|
||||
pt6.move_x (env.eval_arg (6));
|
||||
|
||||
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
|
||||
}
|
||||
else
|
||||
env.set_error ();
|
||||
}
|
||||
|
||||
static void flex (ENV &env, PARAM& param)
|
||||
{
|
||||
if (likely (env.argStack.get_count () == 13))
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (0), env.eval_arg (1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (2), env.eval_arg (3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (4), env.eval_arg (5));
|
||||
point_t pt4 = pt3;
|
||||
pt4.move (env.eval_arg (6), env.eval_arg (7));
|
||||
point_t pt5 = pt4;
|
||||
pt5.move (env.eval_arg (8), env.eval_arg (9));
|
||||
point_t pt6 = pt5;
|
||||
pt6.move (env.eval_arg (10), env.eval_arg (11));
|
||||
|
||||
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
|
||||
}
|
||||
else
|
||||
env.set_error ();
|
||||
}
|
||||
|
||||
static void hflex1 (ENV &env, PARAM& param)
|
||||
{
|
||||
if (likely (env.argStack.get_count () == 9))
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (0), env.eval_arg (1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (2), env.eval_arg (3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move_x (env.eval_arg (4));
|
||||
point_t pt4 = pt3;
|
||||
pt4.move_x (env.eval_arg (5));
|
||||
point_t pt5 = pt4;
|
||||
pt5.move (env.eval_arg (6), env.eval_arg (7));
|
||||
point_t pt6 = pt5;
|
||||
pt6.move_x (env.eval_arg (8));
|
||||
pt6.y = env.get_pt ().y;
|
||||
|
||||
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
|
||||
}
|
||||
else
|
||||
env.set_error ();
|
||||
}
|
||||
|
||||
static void flex1 (ENV &env, PARAM& param)
|
||||
{
|
||||
if (likely (env.argStack.get_count () == 11))
|
||||
{
|
||||
point_t d;
|
||||
d.init ();
|
||||
for (unsigned int i = 0; i < 10; i += 2)
|
||||
d.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (0), env.eval_arg (1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (2), env.eval_arg (3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (4), env.eval_arg (5));
|
||||
point_t pt4 = pt3;
|
||||
pt4.move (env.eval_arg (6), env.eval_arg (7));
|
||||
point_t pt5 = pt4;
|
||||
pt5.move (env.eval_arg (8), env.eval_arg (9));
|
||||
point_t pt6 = pt5;
|
||||
|
||||
if (fabs (d.x.to_real ()) > fabs (d.y.to_real ()))
|
||||
{
|
||||
pt6.move_x (env.eval_arg (10));
|
||||
pt6.y = env.get_pt ().y;
|
||||
}
|
||||
else
|
||||
{
|
||||
pt6.x = env.get_pt ().x;
|
||||
pt6.move_y (env.eval_arg (10));
|
||||
}
|
||||
|
||||
curve2 (env, param, pt1, pt2, pt3, pt4, pt5, pt6);
|
||||
}
|
||||
else
|
||||
env.set_error ();
|
||||
}
|
||||
|
||||
protected:
|
||||
static void curve2 (ENV &env, PARAM& param,
|
||||
const point_t &pt1, const point_t &pt2, const point_t &pt3,
|
||||
const point_t &pt4, const point_t &pt5, const point_t &pt6)
|
||||
{
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
PATH::curve (env, param, pt4, pt5, pt6);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ENV, typename OPSET, typename PARAM>
|
||||
struct cs_interpreter_t : interpreter_t<ENV>
|
||||
{
|
||||
bool interpret (PARAM& param)
|
||||
{
|
||||
SUPER::env.set_endchar (false);
|
||||
|
||||
for (;;) {
|
||||
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
|
||||
if (unlikely (SUPER::env.in_error ()))
|
||||
return false;
|
||||
if (SUPER::env.is_endchar ())
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef interpreter_t<ENV> SUPER;
|
||||
};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_CFF_INTERP_CS_COMMON_HH */
|
||||
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright © 2018 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
#ifndef HB_CFF_INTERP_DICT_COMMON_HH
|
||||
#define HB_CFF_INTERP_DICT_COMMON_HH
|
||||
|
||||
#include "hb-cff-interp-common.hh"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
/* an opstr and the parsed out dict value(s) */
|
||||
struct dict_val_t : op_str_t
|
||||
{
|
||||
void init () { single_val.set_int (0); }
|
||||
void fini () {}
|
||||
|
||||
number_t single_val;
|
||||
};
|
||||
|
||||
typedef dict_val_t num_dict_val_t;
|
||||
|
||||
template <typename VAL> struct dict_values_t : parsed_values_t<VAL> {};
|
||||
|
||||
template <typename OPSTR=op_str_t>
|
||||
struct top_dict_values_t : dict_values_t<OPSTR>
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
dict_values_t<OPSTR>::init ();
|
||||
charStringsOffset = 0;
|
||||
FDArrayOffset = 0;
|
||||
}
|
||||
void fini () { dict_values_t<OPSTR>::fini (); }
|
||||
|
||||
unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
|
||||
{
|
||||
switch (opstr.op)
|
||||
{
|
||||
case OpCode_CharStrings:
|
||||
case OpCode_FDArray:
|
||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
||||
|
||||
default:
|
||||
return opstr.str.length;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int FDArrayOffset;
|
||||
};
|
||||
|
||||
struct dict_opset_t : opset_t<number_t>
|
||||
{
|
||||
static void process_op (op_code_t op, interp_env_t<number_t>& env)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_longintdict: /* 5-byte integer */
|
||||
env.argStack.push_longint_from_substr (env.str_ref);
|
||||
break;
|
||||
|
||||
case OpCode_BCD: /* real number */
|
||||
env.argStack.push_real (parse_bcd (env.str_ref));
|
||||
break;
|
||||
|
||||
default:
|
||||
opset_t<number_t>::process_op (op, env);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turns CFF's BCD format into strtod understandable string */
|
||||
static double parse_bcd (byte_str_ref_t& str_ref)
|
||||
{
|
||||
if (unlikely (str_ref.in_error ())) return .0;
|
||||
|
||||
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
|
||||
|
||||
char buf[32];
|
||||
unsigned char byte = 0;
|
||||
for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
|
||||
{
|
||||
unsigned nibble;
|
||||
if (!(i & 1))
|
||||
{
|
||||
if (unlikely (!str_ref.avail ())) break;
|
||||
|
||||
byte = str_ref[0];
|
||||
str_ref.inc ();
|
||||
nibble = byte >> 4;
|
||||
}
|
||||
else
|
||||
nibble = byte & 0x0F;
|
||||
|
||||
if (unlikely (nibble == RESERVED)) break;
|
||||
else if (nibble == END)
|
||||
{
|
||||
const char *p = buf;
|
||||
double pv;
|
||||
if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */)))
|
||||
break;
|
||||
return pv;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[count] = "0123456789.EE?-?"[nibble];
|
||||
if (nibble == EXP_NEG)
|
||||
{
|
||||
++count;
|
||||
if (unlikely (count == ARRAY_LENGTH (buf))) break;
|
||||
buf[count] = '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
str_ref.set_error ();
|
||||
return .0;
|
||||
}
|
||||
|
||||
static bool is_hint_op (op_code_t op)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_BlueValues:
|
||||
case OpCode_OtherBlues:
|
||||
case OpCode_FamilyBlues:
|
||||
case OpCode_FamilyOtherBlues:
|
||||
case OpCode_StemSnapH:
|
||||
case OpCode_StemSnapV:
|
||||
case OpCode_StdHW:
|
||||
case OpCode_StdVW:
|
||||
case OpCode_BlueScale:
|
||||
case OpCode_BlueShift:
|
||||
case OpCode_BlueFuzz:
|
||||
case OpCode_ForceBold:
|
||||
case OpCode_LanguageGroup:
|
||||
case OpCode_ExpansionFactor:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VAL=op_str_t>
|
||||
struct top_dict_opset_t : dict_opset_t
|
||||
{
|
||||
static void process_op (op_code_t op, interp_env_t<number_t>& env, top_dict_values_t<VAL> & dictval)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_CharStrings:
|
||||
dictval.charStringsOffset = env.argStack.pop_uint ();
|
||||
env.clear_args ();
|
||||
break;
|
||||
case OpCode_FDArray:
|
||||
dictval.FDArrayOffset = env.argStack.pop_uint ();
|
||||
env.clear_args ();
|
||||
break;
|
||||
case OpCode_FontMatrix:
|
||||
env.clear_args ();
|
||||
break;
|
||||
default:
|
||||
dict_opset_t::process_op (op, env);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM, typename ENV=num_interp_env_t>
|
||||
struct dict_interpreter_t : interpreter_t<ENV>
|
||||
{
|
||||
bool interpret (PARAM& param)
|
||||
{
|
||||
param.init ();
|
||||
while (SUPER::env.str_ref.avail ())
|
||||
{
|
||||
OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param);
|
||||
if (unlikely (SUPER::env.in_error ()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef interpreter_t<ENV> SUPER;
|
||||
};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_CFF_INTERP_DICT_COMMON_HH */
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright © 2018 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
#ifndef HB_CFF1_INTERP_CS_HH
|
||||
#define HB_CFF1_INTERP_CS_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-cff-interp-cs-common.hh"
|
||||
|
||||
namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
typedef biased_subrs_t<CFF1Subrs> cff1_biased_subrs_t;
|
||||
|
||||
struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
|
||||
{
|
||||
template <typename ACC>
|
||||
void init (const byte_str_t &str, ACC &acc, unsigned int fd)
|
||||
{
|
||||
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
|
||||
processed_width = false;
|
||||
has_width = false;
|
||||
arg_start = 0;
|
||||
in_seac = false;
|
||||
}
|
||||
|
||||
void fini () { SUPER::fini (); }
|
||||
|
||||
void set_width (bool has_width_)
|
||||
{
|
||||
if (likely (!processed_width && (SUPER::argStack.get_count () > 0)))
|
||||
{
|
||||
if (has_width_)
|
||||
{
|
||||
width = SUPER::argStack[0];
|
||||
has_width = true;
|
||||
arg_start = 1;
|
||||
}
|
||||
}
|
||||
processed_width = true;
|
||||
}
|
||||
|
||||
void clear_args ()
|
||||
{
|
||||
arg_start = 0;
|
||||
SUPER::clear_args ();
|
||||
}
|
||||
|
||||
void set_in_seac (bool _in_seac) { in_seac = _in_seac; }
|
||||
|
||||
bool processed_width;
|
||||
bool has_width;
|
||||
unsigned int arg_start;
|
||||
number_t width;
|
||||
bool in_seac;
|
||||
|
||||
private:
|
||||
typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM>>
|
||||
struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
|
||||
{
|
||||
/* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
|
||||
/* Type 1-originated deprecated opcodes, seac behavior of endchar and dotsection are supported */
|
||||
|
||||
static void process_op (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_dotsection:
|
||||
SUPER::flush_args_and_op (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_endchar:
|
||||
OPSET::check_width (op, env, param);
|
||||
if (env.argStack.get_count () >= 4)
|
||||
{
|
||||
OPSET::process_seac (env, param);
|
||||
}
|
||||
OPSET::flush_args_and_op (op, env, param);
|
||||
env.set_endchar (true);
|
||||
break;
|
||||
|
||||
default:
|
||||
SUPER::process_op (op, env, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_width (op_code_t op, cff1_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
if (!env.processed_width)
|
||||
{
|
||||
bool has_width = false;
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_endchar:
|
||||
case OpCode_hstem:
|
||||
case OpCode_hstemhm:
|
||||
case OpCode_vstem:
|
||||
case OpCode_vstemhm:
|
||||
case OpCode_hintmask:
|
||||
case OpCode_cntrmask:
|
||||
has_width = ((env.argStack.get_count () & 1) != 0);
|
||||
break;
|
||||
case OpCode_hmoveto:
|
||||
case OpCode_vmoveto:
|
||||
has_width = (env.argStack.get_count () > 1);
|
||||
break;
|
||||
case OpCode_rmoveto:
|
||||
has_width = (env.argStack.get_count () > 2);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
env.set_width (has_width);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_seac (cff1_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
}
|
||||
|
||||
static void flush_args (cff1_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
SUPER::flush_args (env, param);
|
||||
env.clear_args (); /* pop off width */
|
||||
}
|
||||
|
||||
private:
|
||||
typedef cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH> SUPER;
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM>
|
||||
struct cff1_cs_interpreter_t : cs_interpreter_t<cff1_cs_interp_env_t, OPSET, PARAM> {};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_CFF1_INTERP_CS_HH */
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright © 2018 Adobe Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
#ifndef HB_CFF2_INTERP_CS_HH
|
||||
#define HB_CFF2_INTERP_CS_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-cff-interp-cs-common.hh"
|
||||
|
||||
namespace CFF {
|
||||
|
||||
using namespace OT;
|
||||
|
||||
struct blend_arg_t : number_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
number_t::init ();
|
||||
deltas.init ();
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
number_t::fini ();
|
||||
deltas.fini_deep ();
|
||||
}
|
||||
|
||||
void set_int (int v) { reset_blends (); number_t::set_int (v); }
|
||||
void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); }
|
||||
void set_real (double v) { reset_blends (); number_t::set_real (v); }
|
||||
|
||||
void set_blends (unsigned int numValues_, unsigned int valueIndex_,
|
||||
unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
|
||||
{
|
||||
numValues = numValues_;
|
||||
valueIndex = valueIndex_;
|
||||
deltas.resize (numBlends);
|
||||
for (unsigned int i = 0; i < numBlends; i++)
|
||||
deltas[i] = blends_[i];
|
||||
}
|
||||
|
||||
bool blending () const { return deltas.length > 0; }
|
||||
void reset_blends ()
|
||||
{
|
||||
numValues = valueIndex = 0;
|
||||
deltas.resize (0);
|
||||
}
|
||||
|
||||
unsigned int numValues;
|
||||
unsigned int valueIndex;
|
||||
hb_vector_t<number_t> deltas;
|
||||
};
|
||||
|
||||
typedef interp_env_t<blend_arg_t> BlendInterpEnv;
|
||||
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
|
||||
|
||||
struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
{
|
||||
template <typename ACC>
|
||||
void init (const byte_str_t &str, ACC &acc, unsigned int fd,
|
||||
const int *coords_=nullptr, unsigned int num_coords_=0)
|
||||
{
|
||||
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
|
||||
|
||||
coords = coords_;
|
||||
num_coords = num_coords_;
|
||||
varStore = acc.varStore;
|
||||
seen_blend = false;
|
||||
seen_vsindex_ = false;
|
||||
scalars.init ();
|
||||
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
|
||||
set_ivs (acc.privateDicts[fd].ivs);
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
scalars.fini ();
|
||||
SUPER::fini ();
|
||||
}
|
||||
|
||||
op_code_t fetch_op ()
|
||||
{
|
||||
if (this->str_ref.avail ())
|
||||
return SUPER::fetch_op ();
|
||||
|
||||
/* make up return or endchar op */
|
||||
if (this->callStack.is_empty ())
|
||||
return OpCode_endchar;
|
||||
else
|
||||
return OpCode_return;
|
||||
}
|
||||
|
||||
const blend_arg_t& eval_arg (unsigned int i)
|
||||
{
|
||||
blend_arg_t &arg = argStack[i];
|
||||
blend_arg (arg);
|
||||
return arg;
|
||||
}
|
||||
|
||||
const blend_arg_t& pop_arg ()
|
||||
{
|
||||
blend_arg_t &arg = argStack.pop ();
|
||||
blend_arg (arg);
|
||||
return arg;
|
||||
}
|
||||
|
||||
void process_blend ()
|
||||
{
|
||||
if (!seen_blend)
|
||||
{
|
||||
region_count = varStore->varStore.get_region_index_count (get_ivs ());
|
||||
if (do_blend)
|
||||
{
|
||||
scalars.resize (region_count);
|
||||
varStore->varStore.get_scalars (get_ivs (),
|
||||
(int *)coords, num_coords,
|
||||
&scalars[0], region_count);
|
||||
}
|
||||
seen_blend = true;
|
||||
}
|
||||
}
|
||||
|
||||
void process_vsindex ()
|
||||
{
|
||||
unsigned int index = argStack.pop_uint ();
|
||||
if (unlikely (seen_vsindex () || seen_blend))
|
||||
{
|
||||
set_error ();
|
||||
}
|
||||
else
|
||||
{
|
||||
set_ivs (index);
|
||||
}
|
||||
seen_vsindex_ = true;
|
||||
}
|
||||
|
||||
unsigned int get_region_count () const { return region_count; }
|
||||
void set_region_count (unsigned int region_count_) { region_count = region_count_; }
|
||||
unsigned int get_ivs () const { return ivs; }
|
||||
void set_ivs (unsigned int ivs_) { ivs = ivs_; }
|
||||
bool seen_vsindex () const { return seen_vsindex_; }
|
||||
|
||||
protected:
|
||||
void blend_arg (blend_arg_t &arg)
|
||||
{
|
||||
if (do_blend && arg.blending ())
|
||||
{
|
||||
if (likely (scalars.length == arg.deltas.length))
|
||||
{
|
||||
double v = arg.to_real ();
|
||||
for (unsigned int i = 0; i < scalars.length; i++)
|
||||
{
|
||||
v += (double)scalars[i] * arg.deltas[i].to_real ();
|
||||
}
|
||||
arg.set_real (v);
|
||||
arg.deltas.resize (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
const int *coords;
|
||||
unsigned int num_coords;
|
||||
const CFF2VariationStore *varStore;
|
||||
unsigned int region_count;
|
||||
unsigned int ivs;
|
||||
hb_vector_t<float> scalars;
|
||||
bool do_blend;
|
||||
bool seen_vsindex_;
|
||||
bool seen_blend;
|
||||
|
||||
typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
|
||||
};
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
|
||||
struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
|
||||
{
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_callsubr:
|
||||
case OpCode_callgsubr:
|
||||
/* a subroutine number shoudln't be a blended value */
|
||||
if (unlikely (env.argStack.peek ().blending ()))
|
||||
{
|
||||
env.set_error ();
|
||||
break;
|
||||
}
|
||||
SUPER::process_op (op, env, param);
|
||||
break;
|
||||
|
||||
case OpCode_blendcs:
|
||||
OPSET::process_blend (env, param);
|
||||
break;
|
||||
|
||||
case OpCode_vsindexcs:
|
||||
if (unlikely (env.argStack.peek ().blending ()))
|
||||
{
|
||||
env.set_error ();
|
||||
break;
|
||||
}
|
||||
OPSET::process_vsindex (env, param);
|
||||
break;
|
||||
|
||||
default:
|
||||
SUPER::process_op (op, env, param);
|
||||
}
|
||||
}
|
||||
|
||||
static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
unsigned int n, k;
|
||||
|
||||
env.process_blend ();
|
||||
k = env.get_region_count ();
|
||||
n = env.argStack.pop_uint ();
|
||||
/* copy the blend values into blend array of the default values */
|
||||
unsigned int start = env.argStack.get_count () - ((k+1) * n);
|
||||
/* let an obvious error case fail, but note CFF2 spec doesn't forbid n==0 */
|
||||
if (unlikely (start > env.argStack.get_count ()))
|
||||
{
|
||||
env.set_error ();
|
||||
return;
|
||||
}
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
{
|
||||
const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k));
|
||||
env.argStack[start + i].set_blends (n, i, k, blends);
|
||||
}
|
||||
|
||||
/* pop off blend values leaving default values now adorned with blend values */
|
||||
env.argStack.pop (k * n);
|
||||
}
|
||||
|
||||
static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param)
|
||||
{
|
||||
env.process_vsindex ();
|
||||
env.clear_args ();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER;
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM>
|
||||
struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_CFF2_INTERP_CS_HH */
|
||||
|
|
@ -26,33 +26,60 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-mutex-private.hh"
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb.hh"
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
|
||||
#ifdef HB_NO_SETLOCALE
|
||||
#define setlocale(Category, Locale) "C"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION:hb-common
|
||||
* @title: hb-common
|
||||
* @short_description: Common data types
|
||||
* @include: hb.h
|
||||
*
|
||||
* Common data types used across HarfBuzz are defined here.
|
||||
**/
|
||||
|
||||
|
||||
/* hb_options_t */
|
||||
|
||||
hb_options_union_t _hb_options;
|
||||
hb_atomic_int_t _hb_options;
|
||||
|
||||
void
|
||||
_hb_options_init (void)
|
||||
_hb_options_init ()
|
||||
{
|
||||
hb_options_union_t u;
|
||||
u.i = 0;
|
||||
u.opts.initialized = 1;
|
||||
u.opts.initialized = true;
|
||||
|
||||
char *c = getenv ("HB_OPTIONS");
|
||||
u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
|
||||
const char *c = getenv ("HB_OPTIONS");
|
||||
if (c)
|
||||
{
|
||||
while (*c)
|
||||
{
|
||||
const char *p = strchr (c, ':');
|
||||
if (!p)
|
||||
p = c + strlen (c);
|
||||
|
||||
#define OPTION(name, symbol) \
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
|
||||
|
||||
OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
|
||||
OPTION ("aat", aat);
|
||||
|
||||
#undef OPTION
|
||||
|
||||
c = *p ? p + 1 : p;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* This is idempotent and threadsafe. */
|
||||
_hb_options = u;
|
||||
_hb_options.set_relaxed (u.i);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -60,12 +87,12 @@ _hb_options_init (void)
|
|||
|
||||
/**
|
||||
* hb_tag_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t):
|
||||
* @len:
|
||||
* @str: (array length=len) (element-type uint8_t):
|
||||
* @len:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -90,10 +117,10 @@ hb_tag_from_string (const char *str, int len)
|
|||
|
||||
/**
|
||||
* hb_tag_to_string:
|
||||
* @tag:
|
||||
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
|
||||
* @tag:
|
||||
* @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.5
|
||||
**/
|
||||
|
|
@ -118,12 +145,12 @@ const char direction_strings[][4] = {
|
|||
|
||||
/**
|
||||
* hb_direction_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t):
|
||||
* @len:
|
||||
* @str: (array length=len) (element-type uint8_t):
|
||||
* @len:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -146,11 +173,11 @@ hb_direction_from_string (const char *str, int len)
|
|||
|
||||
/**
|
||||
* hb_direction_to_string:
|
||||
* @direction:
|
||||
* @direction:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -176,7 +203,7 @@ static const char canon_map[256] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
|
||||
'-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
|
||||
0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
|
||||
|
|
@ -219,13 +246,12 @@ struct hb_language_item_t {
|
|||
struct hb_language_item_t *next;
|
||||
hb_language_t lang;
|
||||
|
||||
inline bool operator == (const char *s) const {
|
||||
return lang_equal (lang, s);
|
||||
}
|
||||
bool operator == (const char *s) const
|
||||
{ return lang_equal (lang, s); }
|
||||
|
||||
inline hb_language_item_t & operator = (const char *s) {
|
||||
hb_language_item_t & operator = (const char *s) {
|
||||
/* If a custom allocated is used calling strdup() pairs
|
||||
badly with a call to the custom free() in finish() below.
|
||||
badly with a call to the custom free() in fini() below.
|
||||
Therefore don't call strdup(), implement its behavior.
|
||||
*/
|
||||
size_t len = strlen(s) + 1;
|
||||
|
|
@ -240,23 +266,28 @@ struct hb_language_item_t {
|
|||
return *this;
|
||||
}
|
||||
|
||||
void finish (void) { free ((void *) lang); }
|
||||
void fini () { free ((void *) lang); }
|
||||
};
|
||||
|
||||
|
||||
/* Thread-safe lock-free language list */
|
||||
|
||||
static hb_language_item_t *langs;
|
||||
static hb_atomic_ptr_t <hb_language_item_t> langs;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
#if HB_USE_ATEXIT
|
||||
static void
|
||||
free_langs (void)
|
||||
free_langs ()
|
||||
{
|
||||
while (langs) {
|
||||
hb_language_item_t *next = langs->next;
|
||||
langs->finish ();
|
||||
free (langs);
|
||||
langs = next;
|
||||
retry:
|
||||
hb_language_item_t *first_lang = langs;
|
||||
if (unlikely (!langs.cmpexch (first_lang, nullptr)))
|
||||
goto retry;
|
||||
|
||||
while (first_lang) {
|
||||
hb_language_item_t *next = first_lang->next;
|
||||
first_lang->fini ();
|
||||
free (first_lang);
|
||||
first_lang = next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -265,7 +296,7 @@ static hb_language_item_t *
|
|||
lang_find_or_insert (const char *key)
|
||||
{
|
||||
retry:
|
||||
hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
|
||||
hb_language_item_t *first_lang = langs;
|
||||
|
||||
for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
|
||||
if (*lang == key)
|
||||
|
|
@ -283,13 +314,14 @@ retry:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
|
||||
lang->finish ();
|
||||
if (unlikely (!langs.cmpexch (first_lang, lang)))
|
||||
{
|
||||
lang->fini ();
|
||||
free (lang);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
#if HB_USE_ATEXIT
|
||||
if (!first_lang)
|
||||
atexit (free_langs); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
|
|
@ -301,14 +333,14 @@ retry:
|
|||
/**
|
||||
* hb_language_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t): a string representing
|
||||
* ISO 639 language code
|
||||
* a BCP 47 language tag
|
||||
* @len: length of the @str, or -1 if it is %NULL-terminated.
|
||||
*
|
||||
* Converts @str representing an ISO 639 language code to the corresponding
|
||||
* Converts @str representing a BCP 47 language tag to the corresponding
|
||||
* #hb_language_t.
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
* The #hb_language_t corresponding to the ISO 639 language code.
|
||||
* The #hb_language_t corresponding to the BCP 47 language tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -323,7 +355,7 @@ hb_language_from_string (const char *str, int len)
|
|||
{
|
||||
/* NUL-terminate it. */
|
||||
char strbuf[64];
|
||||
len = MIN (len, (int) sizeof (strbuf) - 1);
|
||||
len = hb_min (len, (int) sizeof (strbuf) - 1);
|
||||
memcpy (strbuf, str, len);
|
||||
strbuf[len] = '\0';
|
||||
item = lang_find_or_insert (strbuf);
|
||||
|
|
@ -349,31 +381,40 @@ hb_language_from_string (const char *str, int len)
|
|||
const char *
|
||||
hb_language_to_string (hb_language_t language)
|
||||
{
|
||||
/* This is actually nullptr-safe! */
|
||||
if (unlikely (!language)) return nullptr;
|
||||
|
||||
return language->s;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_language_get_default:
|
||||
*
|
||||
*
|
||||
* Get default language from current locale.
|
||||
*
|
||||
* Note that the first time this function is called, it calls
|
||||
* "setlocale (LC_CTYPE, nullptr)" to fetch current locale. The underlying
|
||||
* setlocale function is, in many implementations, NOT threadsafe. To avoid
|
||||
* problems, call this function once before multiple threads can call it.
|
||||
* This function is only used from hb_buffer_guess_segment_properties() by
|
||||
* HarfBuzz itself.
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_language_t
|
||||
hb_language_get_default (void)
|
||||
hb_language_get_default ()
|
||||
{
|
||||
static hb_language_t default_language = HB_LANGUAGE_INVALID;
|
||||
static hb_atomic_ptr_t <hb_language_t> default_language;
|
||||
|
||||
hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
|
||||
if (unlikely (language == HB_LANGUAGE_INVALID)) {
|
||||
hb_language_t language = default_language;
|
||||
if (unlikely (language == HB_LANGUAGE_INVALID))
|
||||
{
|
||||
language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1);
|
||||
(void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
|
||||
(void) default_language.cmpexch (HB_LANGUAGE_INVALID, language);
|
||||
}
|
||||
|
||||
return default_language;
|
||||
return language;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -385,7 +426,7 @@ hb_language_get_default (void)
|
|||
*
|
||||
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
|
|
@ -407,7 +448,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
|
|||
case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
|
||||
case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
|
||||
|
||||
/* Script variants from http://unicode.org/iso15924/ */
|
||||
/* Script variants from https://unicode.org/iso15924/ */
|
||||
case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
|
||||
case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
|
||||
case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
|
||||
|
|
@ -434,7 +475,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
|
|||
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
|
||||
* hb_script_from_iso15924_tag().
|
||||
*
|
||||
* Return value:
|
||||
* Return value:
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
|
|
@ -447,7 +488,7 @@ hb_script_from_string (const char *str, int len)
|
|||
|
||||
/**
|
||||
* hb_script_to_iso15924_tag:
|
||||
* @script: an #hb_script_ to convert.
|
||||
* @script: an #hb_script_t to convert.
|
||||
*
|
||||
* See hb_script_from_iso15924_tag().
|
||||
*
|
||||
|
|
@ -464,18 +505,18 @@ hb_script_to_iso15924_tag (hb_script_t script)
|
|||
|
||||
/**
|
||||
* hb_script_get_horizontal_direction:
|
||||
* @script:
|
||||
* @script:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_direction_t
|
||||
hb_script_get_horizontal_direction (hb_script_t script)
|
||||
{
|
||||
/* http://goo.gl/x9ilM */
|
||||
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
|
||||
switch ((hb_tag_t) script)
|
||||
{
|
||||
/* Unicode-1.1 additions */
|
||||
|
|
@ -524,12 +565,25 @@ hb_script_get_horizontal_direction (hb_script_t script)
|
|||
case HB_SCRIPT_PSALTER_PAHLAVI:
|
||||
|
||||
/* Unicode-8.0 additions */
|
||||
case HB_SCRIPT_OLD_HUNGARIAN:
|
||||
case HB_SCRIPT_HATRAN:
|
||||
|
||||
/* Unicode-9.0 additions */
|
||||
case HB_SCRIPT_ADLAM:
|
||||
|
||||
/* Unicode-11.0 additions */
|
||||
case HB_SCRIPT_HANIFI_ROHINGYA:
|
||||
case HB_SCRIPT_OLD_SOGDIAN:
|
||||
case HB_SCRIPT_SOGDIAN:
|
||||
|
||||
return HB_DIRECTION_RTL;
|
||||
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1000 */
|
||||
case HB_SCRIPT_OLD_HUNGARIAN:
|
||||
case HB_SCRIPT_OLD_ITALIC:
|
||||
case HB_SCRIPT_RUNIC:
|
||||
|
||||
return HB_DIRECTION_INVALID;
|
||||
}
|
||||
|
||||
return HB_DIRECTION_LTR;
|
||||
|
|
@ -570,6 +624,19 @@ hb_user_data_array_t::get (hb_user_data_key_t *key)
|
|||
|
||||
/* hb_version */
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-version
|
||||
* @title: hb-version
|
||||
* @short_description: Information about the version of HarfBuzz in use
|
||||
* @include: hb.h
|
||||
*
|
||||
* These functions and macros allow accessing version of the HarfBuzz
|
||||
* library used at compile- as well as run-time, and to direct code
|
||||
* conditionally based on those versions, again, at compile- or run-time.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_version:
|
||||
* @major: (out): Library major version component.
|
||||
|
|
@ -600,20 +667,20 @@ hb_version (unsigned int *major,
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
const char *
|
||||
hb_version_string (void)
|
||||
hb_version_string ()
|
||||
{
|
||||
return HB_VERSION_STRING;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_version_atleast:
|
||||
* @major:
|
||||
* @minor:
|
||||
* @micro:
|
||||
* @major:
|
||||
* @minor:
|
||||
* @micro:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.30
|
||||
**/
|
||||
|
|
@ -652,125 +719,24 @@ parse_char (const char **pp, const char *end, char c)
|
|||
static bool
|
||||
parse_uint (const char **pp, const char *end, unsigned int *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
unsigned int v;
|
||||
|
||||
/* Intentionally use strtol instead of strtoul, such that
|
||||
* -1 turns into "big number"... */
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 0);
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
|
||||
* such that -1 turns into "big number"... */
|
||||
int v;
|
||||
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
unsigned int v;
|
||||
|
||||
/* Intentionally use strtol instead of strtoul, such that
|
||||
* -1 turns into "big number"... */
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 0);
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
|
||||
* such that -1 turns into "big number"... */
|
||||
int v;
|
||||
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
|
||||
#define USE_XLOCALE 1
|
||||
#define HB_LOCALE_T locale_t
|
||||
#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
|
||||
#define HB_FREE_LOCALE(loc) freelocale (loc)
|
||||
#elif defined(_MSC_VER)
|
||||
#define USE_XLOCALE 1
|
||||
#define HB_LOCALE_T _locale_t
|
||||
#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
|
||||
#define HB_FREE_LOCALE(loc) _free_locale (loc)
|
||||
#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
|
||||
#endif
|
||||
|
||||
#ifdef USE_XLOCALE
|
||||
|
||||
static HB_LOCALE_T C_locale;
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
static void
|
||||
free_C_locale (void)
|
||||
{
|
||||
if (C_locale)
|
||||
HB_FREE_LOCALE (C_locale);
|
||||
}
|
||||
#endif
|
||||
|
||||
static HB_LOCALE_T
|
||||
get_C_locale (void)
|
||||
{
|
||||
retry:
|
||||
HB_LOCALE_T C = (HB_LOCALE_T) hb_atomic_ptr_get (&C_locale);
|
||||
|
||||
if (unlikely (!C))
|
||||
{
|
||||
C = HB_CREATE_LOCALE ("C");
|
||||
|
||||
if (!hb_atomic_ptr_cmpexch (&C_locale, nullptr, C))
|
||||
{
|
||||
HB_FREE_LOCALE (C_locale);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#ifdef HB_USE_ATEXIT
|
||||
atexit (free_C_locale); /* First person registers atexit() callback. */
|
||||
#endif
|
||||
}
|
||||
|
||||
return C;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
parse_float (const char **pp, const char *end, float *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
float v;
|
||||
|
||||
errno = 0;
|
||||
#ifdef USE_XLOCALE
|
||||
v = strtod_l (p, &pend, get_C_locale ());
|
||||
#else
|
||||
v = strtod (p, &pend);
|
||||
#endif
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -784,9 +750,14 @@ parse_bool (const char **pp, const char *end, uint32_t *pv)
|
|||
(*pp)++;
|
||||
|
||||
/* CSS allows on/off as aliases 1/0. */
|
||||
if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
|
||||
if (*pp - p == 2
|
||||
&& TOLOWER (p[0]) == 'o'
|
||||
&& TOLOWER (p[1]) == 'n')
|
||||
*pv = 1;
|
||||
else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
|
||||
else if (*pp - p == 3
|
||||
&& TOLOWER (p[0]) == 'o'
|
||||
&& TOLOWER (p[1]) == 'f'
|
||||
&& TOLOWER (p[2]) == 'f')
|
||||
*pv = 0;
|
||||
else
|
||||
return false;
|
||||
|
|
@ -823,7 +794,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
|
|||
}
|
||||
|
||||
const char *p = *pp;
|
||||
while (*pp < end && ISALNUM(**pp))
|
||||
while (*pp < end && (ISALNUM(**pp) || **pp == '_'))
|
||||
(*pp)++;
|
||||
|
||||
if (p == *pp || *pp - p > 4)
|
||||
|
|
@ -852,15 +823,15 @@ parse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
|
|||
|
||||
bool has_start;
|
||||
|
||||
feature->start = 0;
|
||||
feature->end = (unsigned int) -1;
|
||||
feature->start = HB_FEATURE_GLOBAL_START;
|
||||
feature->end = HB_FEATURE_GLOBAL_END;
|
||||
|
||||
if (!parse_char (pp, end, '['))
|
||||
return true;
|
||||
|
||||
has_start = parse_uint (pp, end, &feature->start);
|
||||
|
||||
if (parse_char (pp, end, ':')) {
|
||||
if (parse_char (pp, end, ':') || parse_char (pp, end, ';')) {
|
||||
parse_uint (pp, end, &feature->end);
|
||||
} else {
|
||||
if (has_start)
|
||||
|
|
@ -875,10 +846,10 @@ parse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *fea
|
|||
{
|
||||
bool had_equal = parse_char (pp, end, '=');
|
||||
bool had_value = parse_uint32 (pp, end, &feature->value) ||
|
||||
parse_bool (pp, end, &feature->value);
|
||||
parse_bool (pp, end, &feature->value);
|
||||
/* CSS doesn't use equal-sign between tag and value.
|
||||
* If there was an equal-sign, then there *must* be a value.
|
||||
* A value without an eqaul-sign is ok, but not required. */
|
||||
* A value without an equal-sign is ok, but not required. */
|
||||
return !had_equal || had_value;
|
||||
}
|
||||
|
||||
|
|
@ -901,7 +872,41 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
|
|||
*
|
||||
* Parses a string into a #hb_feature_t.
|
||||
*
|
||||
* TODO: document the syntax here.
|
||||
* The format for specifying feature strings follows. All valid CSS
|
||||
* font-feature-settings values other than 'normal' and the global values are
|
||||
* also accepted, though not documented below. CSS string escapes are not
|
||||
* supported.
|
||||
*
|
||||
* The range indices refer to the positions between Unicode characters. The
|
||||
* position before the first character is always 0.
|
||||
*
|
||||
* The format is Python-esque. Here is how it all works:
|
||||
*
|
||||
* <informaltable pgwide='1' align='left' frame='none'>
|
||||
* <tgroup cols='5'>
|
||||
* <thead>
|
||||
* <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <row><entry>Setting value:</entry></row>
|
||||
* <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
|
||||
* <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
|
||||
* <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry>∞</entry> <entry>Choose 2nd alternate</entry></row>
|
||||
* <row><entry>Setting index:</entry></row>
|
||||
* <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry>∞</entry> <entry>Turn feature on, partial</entry></row>
|
||||
* <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row>
|
||||
* <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row>
|
||||
* <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
|
||||
* <row><entry>Mixing it all:</entry></row>
|
||||
* <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row>
|
||||
* </tbody>
|
||||
* </tgroup>
|
||||
* </informaltable>
|
||||
*
|
||||
* Return value:
|
||||
* %true if @str is successfully parsed, %false otherwise.
|
||||
|
|
@ -959,21 +964,21 @@ hb_feature_to_string (hb_feature_t *feature,
|
|||
{
|
||||
s[len++] = '[';
|
||||
if (feature->start)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
if (feature->end != feature->start + 1) {
|
||||
s[len++] = ':';
|
||||
if (feature->end != (unsigned int) -1)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
|
||||
}
|
||||
s[len++] = ']';
|
||||
}
|
||||
if (feature->value > 1)
|
||||
{
|
||||
s[len++] = '=';
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
}
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
|
@ -984,7 +989,11 @@ static bool
|
|||
parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
|
||||
{
|
||||
parse_char (pp, end, '='); /* Optional. */
|
||||
return parse_float (pp, end, &variation->value);
|
||||
double v;
|
||||
if (unlikely (!hb_parse_double (pp, end, &v))) return false;
|
||||
|
||||
variation->value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -1040,10 +1049,76 @@ hb_variation_to_string (hb_variation_t *variation,
|
|||
while (len && s[len - 1] == ' ')
|
||||
len--;
|
||||
s[len++] = '=';
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
|
||||
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_alpha:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Alpha channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_alpha) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_alpha (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_red:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Red channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_red) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_red (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_green:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Green channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_green) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_green (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_blue:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Blue channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_blue) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_blue (color);
|
||||
}
|
||||
|
||||
|
||||
/* If there is no visibility control, then hb-static.cc will NOT
|
||||
* define anything. Instead, we get it to define one set in here
|
||||
* only, so only libharfbuzz.so defines them, not other libs. */
|
||||
#ifdef HB_NO_VISIBILITY
|
||||
#undef HB_NO_VISIBILITY
|
||||
#include "hb-static.cc"
|
||||
#define HB_NO_VISIBILITY 1
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@
|
|||
#ifndef HB_COMMON_H
|
||||
#define HB_COMMON_H
|
||||
|
||||
#ifndef HB_EXTERN
|
||||
#define HB_EXTERN extern
|
||||
#endif
|
||||
|
||||
#ifndef HB_BEGIN_DECLS
|
||||
# ifdef __cplusplus
|
||||
# define HB_BEGIN_DECLS extern "C" {
|
||||
|
|
@ -49,10 +53,39 @@
|
|||
# include <inttypes.h>
|
||||
#elif defined (_AIX)
|
||||
# include <sys/inttypes.h>
|
||||
#elif defined (_MSC_VER) && _MSC_VER < 1600
|
||||
/* VS 2010 (_MSC_VER 1600) has stdint.h */
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined (__KERNEL__)
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))
|
||||
#define HB_DEPRECATED __attribute__((__deprecated__))
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1300)
|
||||
#define HB_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#define HB_DEPRECATED
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
||||
#define HB_DEPRECATED_FOR(f) __attribute__((__deprecated__("Use '" #f "' instead")))
|
||||
#elif defined(_MSC_FULL_VER) && (_MSC_FULL_VER > 140050320)
|
||||
#define HB_DEPRECATED_FOR(f) __declspec(deprecated("is deprecated. Use '" #f "' instead"))
|
||||
#else
|
||||
#define HB_DEPRECATED_FOR(f) HB_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
|
|
@ -76,8 +109,8 @@ typedef union _hb_var_int_t {
|
|||
|
||||
typedef uint32_t hb_tag_t;
|
||||
|
||||
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint8_t)(c1))<<24)|(((uint8_t)(c2))<<16)|(((uint8_t)(c3))<<8)|((uint8_t)(c4))))
|
||||
#define HB_UNTAG(tag) ((uint8_t)((tag)>>24)), ((uint8_t)((tag)>>16)), ((uint8_t)((tag)>>8)), ((uint8_t)(tag))
|
||||
#define HB_TAG(c1,c2,c3,c4) ((hb_tag_t)((((uint32_t)(c1)&0xFF)<<24)|(((uint32_t)(c2)&0xFF)<<16)|(((uint32_t)(c3)&0xFF)<<8)|((uint32_t)(c4)&0xFF)))
|
||||
#define HB_UNTAG(tag) (uint8_t)(((tag)>>24)&0xFF), (uint8_t)(((tag)>>16)&0xFF), (uint8_t)(((tag)>>8)&0xFF), (uint8_t)((tag)&0xFF)
|
||||
|
||||
#define HB_TAG_NONE HB_TAG(0,0,0,0)
|
||||
#define HB_TAG_MAX HB_TAG(0xff,0xff,0xff,0xff)
|
||||
|
|
@ -142,8 +175,8 @@ hb_language_get_default (void);
|
|||
|
||||
/* hb_script_t */
|
||||
|
||||
/* http://unicode.org/iso15924/ */
|
||||
/* http://goo.gl/x9ilM */
|
||||
/* https://unicode.org/iso15924/ */
|
||||
/* https://docs.google.com/spreadsheets/d/1Y90M0Ie3MUJ6UVCRDOypOtijlMDLNNyyLk36T6iMu0o */
|
||||
/* Unicode Character Database property: Script (sc) */
|
||||
typedef enum
|
||||
{
|
||||
|
|
@ -315,17 +348,38 @@ typedef enum
|
|||
/*10.0*/HB_SCRIPT_SOYOMBO = HB_TAG ('S','o','y','o'),
|
||||
/*10.0*/HB_SCRIPT_ZANABAZAR_SQUARE = HB_TAG ('Z','a','n','b'),
|
||||
|
||||
/*
|
||||
* Since 1.8.0
|
||||
*/
|
||||
/*11.0*/HB_SCRIPT_DOGRA = HB_TAG ('D','o','g','r'),
|
||||
/*11.0*/HB_SCRIPT_GUNJALA_GONDI = HB_TAG ('G','o','n','g'),
|
||||
/*11.0*/HB_SCRIPT_HANIFI_ROHINGYA = HB_TAG ('R','o','h','g'),
|
||||
/*11.0*/HB_SCRIPT_MAKASAR = HB_TAG ('M','a','k','a'),
|
||||
/*11.0*/HB_SCRIPT_MEDEFAIDRIN = HB_TAG ('M','e','d','f'),
|
||||
/*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'),
|
||||
/*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'),
|
||||
|
||||
/*
|
||||
* Since 2.4.0
|
||||
*/
|
||||
/*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'),
|
||||
/*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'),
|
||||
/*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'),
|
||||
/*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'),
|
||||
|
||||
/* No script set. */
|
||||
HB_SCRIPT_INVALID = HB_TAG_NONE,
|
||||
|
||||
/* Dummy values to ensure any hb_tag_t value can be passed/stored as hb_script_t
|
||||
* without risking undefined behavior. Include both a signed and unsigned max,
|
||||
* since technically enums are int, and indeed, hb_script_t ends up being signed.
|
||||
* without risking undefined behavior. We have two, for historical reasons.
|
||||
* HB_TAG_MAX used to be unsigned, but that was invalid Ansi C, so was changed
|
||||
* to _HB_SCRIPT_MAX_VALUE to be equal to HB_TAG_MAX_SIGNED as well.
|
||||
*
|
||||
* See this thread for technicalities:
|
||||
*
|
||||
* http://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
|
||||
* https://lists.freedesktop.org/archives/harfbuzz/2014-March/004150.html
|
||||
*/
|
||||
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX, /*< skip >*/
|
||||
_HB_SCRIPT_MAX_VALUE = HB_TAG_MAX_SIGNED, /*< skip >*/
|
||||
_HB_SCRIPT_MAX_VALUE_SIGNED = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
|
||||
} hb_script_t;
|
||||
|
|
@ -358,6 +412,34 @@ typedef void (*hb_destroy_func_t) (void *user_data);
|
|||
|
||||
/* Font features and variations. */
|
||||
|
||||
/**
|
||||
* HB_FEATURE_GLOBAL_START
|
||||
*
|
||||
* Since: 2.0.0
|
||||
*/
|
||||
#define HB_FEATURE_GLOBAL_START 0
|
||||
/**
|
||||
* HB_FEATURE_GLOBAL_END
|
||||
*
|
||||
* Since: 2.0.0
|
||||
*/
|
||||
#define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
|
||||
|
||||
/**
|
||||
* hb_feature_t:
|
||||
* @tag: a feature tag
|
||||
* @value: 0 disables the feature, non-zero (usually 1) enables the feature.
|
||||
* For features implemented as lookup type 3 (like 'salt') the @value is a one
|
||||
* based index into the alternates.
|
||||
* @start: the cluster to start applying this feature setting (inclusive).
|
||||
* @end: the cluster to end applying this feature setting (exclusive).
|
||||
*
|
||||
* The #hb_feature_t is the structure that holds information about requested
|
||||
* feature application. The feature will be applied with the given value to all
|
||||
* glyphs which are in clusters between @start (inclusive) and @end (exclusive).
|
||||
* Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
|
||||
* specifies that the feature always applies to the entire buffer.
|
||||
*/
|
||||
typedef struct hb_feature_t {
|
||||
hb_tag_t tag;
|
||||
uint32_t value;
|
||||
|
|
@ -391,6 +473,32 @@ HB_EXTERN void
|
|||
hb_variation_to_string (hb_variation_t *variation,
|
||||
char *buf, unsigned int size);
|
||||
|
||||
/**
|
||||
* hb_color_t:
|
||||
*
|
||||
* Data type for holding color values.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
typedef uint32_t hb_color_t;
|
||||
|
||||
#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_alpha (hb_color_t color);
|
||||
#define hb_color_get_alpha(color) ((color) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_red (hb_color_t color);
|
||||
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_green (hb_color_t color);
|
||||
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_blue (hb_color_t color);
|
||||
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright © 2019 Facebook, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_CONFIG_HH
|
||||
#define HB_CONFIG_HH
|
||||
|
||||
#if 0 /* Make test happy. */
|
||||
#include "hb.hh"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HB_TINY
|
||||
#define HB_LEAN
|
||||
#define HB_MINI
|
||||
#define HB_NO_MT
|
||||
#define HB_NO_UCD_UNASSIGNED
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#ifndef __OPTIMIZE_SIZE__
|
||||
#define __OPTIMIZE_SIZE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HB_LEAN
|
||||
#define HB_DISABLE_DEPRECATED
|
||||
#define HB_NDEBUG
|
||||
#define HB_NO_ATEXIT
|
||||
#define HB_NO_BUFFER_MESSAGE
|
||||
#define HB_NO_BUFFER_SERIALIZE
|
||||
#define HB_NO_BITMAP
|
||||
#define HB_NO_CFF
|
||||
#define HB_NO_COLOR
|
||||
#define HB_NO_ERRNO
|
||||
#define HB_NO_FACE_COLLECT_UNICODES
|
||||
#define HB_NO_GETENV
|
||||
#define HB_NO_HINTING
|
||||
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
|
||||
#define HB_NO_LAYOUT_FEATURE_PARAMS
|
||||
#define HB_NO_LAYOUT_COLLECT_GLYPHS
|
||||
#define HB_NO_LAYOUT_UNUSED
|
||||
#define HB_NO_MATH
|
||||
#define HB_NO_META
|
||||
#define HB_NO_METRICS
|
||||
#define HB_NO_MMAP
|
||||
#define HB_NO_NAME
|
||||
#define HB_NO_OPEN
|
||||
#define HB_NO_SETLOCALE
|
||||
#define HB_NO_OT_FONT_GLYPH_NAMES
|
||||
#define HB_NO_OT_SHAPE_FRACTIONS
|
||||
#define HB_NO_STAT
|
||||
#define HB_NO_SUBSET_LAYOUT
|
||||
#define HB_NO_VAR
|
||||
#endif
|
||||
|
||||
#ifdef HB_MINI
|
||||
#define HB_NO_AAT
|
||||
#define HB_NO_LEGACY
|
||||
#endif
|
||||
|
||||
|
||||
/* Closure of options. */
|
||||
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
#define HB_IF_NOT_DEPRECATED(x)
|
||||
#else
|
||||
#define HB_IF_NOT_DEPRECATED(x) x
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_AAT
|
||||
#define HB_NO_OT_NAME_LANGUAGE_AAT
|
||||
#define HB_NO_AAT_SHAPE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_BITMAP
|
||||
#define HB_NO_OT_FONT_BITMAP
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_CFF
|
||||
#define HB_NO_OT_FONT_CFF
|
||||
#define HB_NO_SUBSET_CFF
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_GETENV
|
||||
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_LEGACY
|
||||
#define HB_NO_CMAP_LEGACY_SUBTABLES
|
||||
#define HB_NO_FALLBACK_SHAPE
|
||||
#define HB_NO_OT_KERN
|
||||
#define HB_NO_OT_LAYOUT_BLACKLIST
|
||||
#define HB_NO_OT_SHAPE_FALLBACK
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_NAME
|
||||
#define HB_NO_OT_NAME_LANGUAGE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT
|
||||
#define HB_NO_OT_FONT
|
||||
#define HB_NO_OT_LAYOUT
|
||||
#define HB_NO_OT_TAG
|
||||
#define HB_NO_OT_SHAPE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT_SHAPE
|
||||
#define HB_NO_AAT_SHAPE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT_SHAPE_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#ifndef HB_NDEBUG
|
||||
#define HB_NDEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __OPTIMIZE_SIZE__
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
#define HB_OPTIMIZE_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_OVERRIDE_H
|
||||
#include "config-override.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HB_CONFIG_HH */
|
||||
|
|
@ -26,16 +26,16 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#define HB_SHAPER coretext
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-debug.hh"
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
#ifdef HAVE_CORETEXT
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include "hb-coretext.h"
|
||||
#include "hb-aat-layout.hh"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
typedef bool (*qt_get_font_table_func_t) (void *user_data, unsigned int tag, unsigned char *buffer, unsigned int *length);
|
||||
|
||||
struct FontEngineFaceData {
|
||||
|
|
@ -49,6 +49,15 @@ struct CoreTextFontEngineData {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-coretext
|
||||
* @title: hb-coretext
|
||||
* @short_description: CoreText integration
|
||||
* @include: hb-coretext.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the CoreText fonts.
|
||||
**/
|
||||
|
||||
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
|
||||
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
|
||||
|
||||
|
|
@ -60,7 +69,7 @@ release_table_data (void *user_data)
|
|||
}
|
||||
|
||||
static hb_blob_t *
|
||||
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
|
||||
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
|
||||
|
|
@ -70,7 +79,10 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
|||
const char *data = reinterpret_cast<const char*> (CFDataGetBytePtr (cf_data));
|
||||
const size_t length = CFDataGetLength (cf_data);
|
||||
if (!data || !length)
|
||||
{
|
||||
CFRelease (cf_data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hb_blob_create (data, length, HB_MEMORY_MODE_READONLY,
|
||||
reinterpret_cast<void *> (const_cast<__CFData *> (cf_data)),
|
||||
|
|
@ -84,13 +96,8 @@ _hb_cg_font_release (void *data)
|
|||
}
|
||||
|
||||
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(coretext, face)
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE_WITH_CONDITION(coretext, font,
|
||||
fabs (CTFontGetSize ((CTFontRef) data) - font->ptem) <= .5
|
||||
)
|
||||
|
||||
static CTFontDescriptorRef
|
||||
get_last_resort_font_desc (void)
|
||||
get_last_resort_font_desc ()
|
||||
{
|
||||
// TODO Handle allocation failures?
|
||||
CTFontDescriptorRef last_resort = CTFontDescriptorCreateWithNameAndSize (CFSTR("LastResort"), 0);
|
||||
|
|
@ -112,14 +119,16 @@ get_last_resort_font_desc (void)
|
|||
return font_desc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
release_data (void *info, const void *data, size_t size)
|
||||
{
|
||||
assert (hb_blob_get_length ((hb_blob_t *) info) == size &&
|
||||
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
|
||||
hb_blob_get_data ((hb_blob_t *) info, nullptr) == data);
|
||||
|
||||
hb_blob_destroy ((hb_blob_t *) info);
|
||||
}
|
||||
#endif
|
||||
|
||||
static CGFontRef
|
||||
create_cg_font (hb_face_t *face)
|
||||
|
|
@ -167,6 +176,10 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
|||
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
|
||||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
|
||||
{
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
|
||||
# define kCTFontUIFontSystem kCTFontSystemFontType
|
||||
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
|
||||
#endif
|
||||
CTFontUIFontType font_type = kCTFontUIFontSystem;
|
||||
if (CFStringHasSuffix (cg_postscript_name, CFSTR ("-Bold")))
|
||||
font_type = kCTFontUIFontEmphasizedSystem;
|
||||
|
|
@ -205,7 +218,18 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
|||
return ct_font;
|
||||
}
|
||||
|
||||
CFURLRef original_url = (CFURLRef)CTFontCopyAttribute(ct_font, kCTFontURLAttribute);
|
||||
CFURLRef original_url = nullptr;
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
ATSFontRef atsFont;
|
||||
FSRef fsref;
|
||||
OSStatus status;
|
||||
atsFont = CTFontGetPlatformFont (ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
original_url = CFURLCreateFromFSRef (NULL, &fsref);
|
||||
#else
|
||||
original_url = (CFURLRef) CTFontCopyAttribute (ct_font, kCTFontURLAttribute);
|
||||
#endif
|
||||
|
||||
/* Create font copy with cascade list that has LastResort first; this speeds up CoreText
|
||||
* font fallback which we don't need anyway. */
|
||||
|
|
@ -224,18 +248,26 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
|||
* system locations that we cannot access from the sandboxed renderer
|
||||
* process in Blink. This can be detected by the new file URL location
|
||||
* that the newly found font points to. */
|
||||
CFURLRef new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
|
||||
CFURLRef new_url = nullptr;
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
new_url = CFURLCreateFromFSRef (NULL, &fsref);
|
||||
#else
|
||||
new_url = (CFURLRef) CTFontCopyAttribute (new_ct_font, kCTFontURLAttribute);
|
||||
#endif
|
||||
// Keep reconfigured font if URL cannot be retrieved (seems to be the case
|
||||
// on Mac OS 10.12 Sierra), speculative fix for crbug.com/625606
|
||||
if (!original_url || !new_url || CFEqual (original_url, new_url)) {
|
||||
CFRelease (ct_font);
|
||||
ct_font = new_ct_font;
|
||||
CFRelease (ct_font);
|
||||
ct_font = new_ct_font;
|
||||
} else {
|
||||
CFRelease (new_ct_font);
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
|
||||
CFRelease (new_ct_font);
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Discarding reconfigured CTFont, location changed.");
|
||||
}
|
||||
if (new_url)
|
||||
CFRelease (new_url);
|
||||
CFRelease (new_url);
|
||||
}
|
||||
else
|
||||
DEBUG_MSG (CORETEXT, ct_font, "Font copy with empty cascade list failed");
|
||||
|
|
@ -246,7 +278,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
|||
return ct_font;
|
||||
}
|
||||
|
||||
hb_coretext_shaper_face_data_t *
|
||||
hb_coretext_face_data_t *
|
||||
_hb_coretext_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
CGFontRef cg_font = create_cg_font (face);
|
||||
|
|
@ -257,11 +289,11 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return (hb_coretext_shaper_face_data_t *) cg_font;
|
||||
return (hb_coretext_face_data_t *) cg_font;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
|
||||
_hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
|
||||
{
|
||||
CFRelease ((CGFontRef) data);
|
||||
}
|
||||
|
|
@ -269,7 +301,7 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
|
|||
hb_face_t *
|
||||
hb_coretext_face_create (CGFontRef cg_font)
|
||||
{
|
||||
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
|
||||
return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -278,19 +310,19 @@ hb_coretext_face_create (CGFontRef cg_font)
|
|||
CGFontRef
|
||||
hb_coretext_face_get_cg_font (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
|
||||
return (CGFontRef) HB_SHAPER_DATA_GET (face);
|
||||
return (CGFontRef) (const void *) face->data.coretext;
|
||||
}
|
||||
|
||||
|
||||
hb_coretext_shaper_font_data_t *
|
||||
hb_coretext_font_data_t *
|
||||
_hb_coretext_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
if (unlikely (!hb_coretext_shaper_face_data_ensure (face))) return nullptr;
|
||||
CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
|
||||
const hb_coretext_face_data_t *face_data = face->data.coretext;
|
||||
if (unlikely (!face_data)) return nullptr;
|
||||
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
|
||||
|
||||
CGFloat font_size = font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem;
|
||||
CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem);
|
||||
CTFontRef ct_font = create_ct_font (cg_font, font_size);
|
||||
|
||||
if (unlikely (!ct_font))
|
||||
|
|
@ -299,34 +331,66 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return (hb_coretext_shaper_font_data_t *) ct_font;
|
||||
return (hb_coretext_font_data_t *) ct_font;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
|
||||
_hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
|
||||
{
|
||||
CFRelease ((CTFontRef) data);
|
||||
}
|
||||
|
||||
static const hb_coretext_font_data_t *
|
||||
hb_coretext_font_data_sync (hb_font_t *font)
|
||||
{
|
||||
retry:
|
||||
const hb_coretext_font_data_t *data = font->data.coretext;
|
||||
if (unlikely (!data)) return nullptr;
|
||||
|
||||
if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
|
||||
{
|
||||
/* XXX-MT-bug
|
||||
* Note that evaluating condition above can be dangerous if another thread
|
||||
* got here first and destructed data. That's, as always, bad use pattern.
|
||||
* If you modify the font (change font size), other threads must not be
|
||||
* using it at the same time. However, since this check is delayed to
|
||||
* when one actually tries to shape something, this is a XXX race condition
|
||||
* (and the only one we have that I know of) right now. Ie. you modify the
|
||||
* font size in one thread, then (supposedly safely) try to use it from two
|
||||
* or more threads and BOOM! I'm not sure how to fix this. We want RCU.
|
||||
*/
|
||||
|
||||
/* Drop and recreate. */
|
||||
/* If someone dropped it in the mean time, throw it away and don't touch it.
|
||||
* Otherwise, destruct it. */
|
||||
if (likely (font->data.coretext.cmpexch (const_cast<hb_coretext_font_data_t *> (data), nullptr)))
|
||||
_hb_coretext_shaper_font_data_destroy (const_cast<hb_coretext_font_data_t *> (data));
|
||||
else
|
||||
goto retry;
|
||||
}
|
||||
return font->data.coretext;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Since: 1.7.2
|
||||
*/
|
||||
hb_font_t *
|
||||
hb_coretext_font_create (CTFontRef ct_font)
|
||||
{
|
||||
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, 0);
|
||||
CGFontRef cg_font = CTFontCopyGraphicsFont (ct_font, nullptr);
|
||||
hb_face_t *face = hb_coretext_face_create (cg_font);
|
||||
CFRelease (cg_font);
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
if (unlikely (hb_object_is_inert (font)))
|
||||
if (unlikely (hb_object_is_immutable (font)))
|
||||
return font;
|
||||
|
||||
hb_font_set_ptem (font, CTFontGetSize (ct_font));
|
||||
|
||||
/* Let there be dragons here... */
|
||||
HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font);
|
||||
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
|
||||
|
||||
return font;
|
||||
}
|
||||
|
|
@ -334,31 +398,8 @@ hb_coretext_font_create (CTFontRef ct_font)
|
|||
CTFontRef
|
||||
hb_coretext_font_get_ct_font (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (!hb_coretext_shaper_font_data_ensure (font))) return nullptr;
|
||||
return (CTFontRef) HB_SHAPER_DATA_GET (font);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_coretext_shaper_shape_plan_data_t {};
|
||||
|
||||
hb_coretext_shaper_shape_plan_data_t *
|
||||
_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
const hb_coretext_font_data_t *data = hb_coretext_font_data_sync (font);
|
||||
return data ? (CTFontRef) data : nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -375,7 +416,7 @@ struct active_feature_t {
|
|||
feature_record_t rec;
|
||||
unsigned int order;
|
||||
|
||||
static int cmp (const void *pa, const void *pb) {
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
|
||||
const active_feature_t *a = (const active_feature_t *) pa;
|
||||
const active_feature_t *b = (const active_feature_t *) pb;
|
||||
return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
|
||||
|
|
@ -393,7 +434,7 @@ struct feature_event_t {
|
|||
bool start;
|
||||
active_feature_t feature;
|
||||
|
||||
static int cmp (const void *pa, const void *pb) {
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
|
||||
const feature_event_t *a = (const feature_event_t *) pa;
|
||||
const feature_event_t *b = (const feature_event_t *) pb;
|
||||
return a->index < b->index ? -1 : a->index > b->index ? 1 :
|
||||
|
|
@ -409,200 +450,23 @@ struct range_record_t {
|
|||
};
|
||||
|
||||
|
||||
/* The following enum members are added in OS X 10.8. */
|
||||
#define kAltHalfWidthTextSelector 6
|
||||
#define kAltProportionalTextSelector 5
|
||||
#define kAlternateHorizKanaOffSelector 1
|
||||
#define kAlternateHorizKanaOnSelector 0
|
||||
#define kAlternateKanaType 34
|
||||
#define kAlternateVertKanaOffSelector 3
|
||||
#define kAlternateVertKanaOnSelector 2
|
||||
#define kCaseSensitiveLayoutOffSelector 1
|
||||
#define kCaseSensitiveLayoutOnSelector 0
|
||||
#define kCaseSensitiveLayoutType 33
|
||||
#define kCaseSensitiveSpacingOffSelector 3
|
||||
#define kCaseSensitiveSpacingOnSelector 2
|
||||
#define kContextualAlternatesOffSelector 1
|
||||
#define kContextualAlternatesOnSelector 0
|
||||
#define kContextualAlternatesType 36
|
||||
#define kContextualLigaturesOffSelector 19
|
||||
#define kContextualLigaturesOnSelector 18
|
||||
#define kContextualSwashAlternatesOffSelector 5
|
||||
#define kContextualSwashAlternatesOnSelector 4
|
||||
#define kDefaultLowerCaseSelector 0
|
||||
#define kDefaultUpperCaseSelector 0
|
||||
#define kHistoricalLigaturesOffSelector 21
|
||||
#define kHistoricalLigaturesOnSelector 20
|
||||
#define kHojoCharactersSelector 12
|
||||
#define kJIS2004CharactersSelector 11
|
||||
#define kLowerCasePetiteCapsSelector 2
|
||||
#define kLowerCaseSmallCapsSelector 1
|
||||
#define kLowerCaseType 37
|
||||
#define kMathematicalGreekOffSelector 11
|
||||
#define kMathematicalGreekOnSelector 10
|
||||
#define kNLCCharactersSelector 13
|
||||
#define kQuarterWidthTextSelector 4
|
||||
#define kScientificInferiorsSelector 4
|
||||
#define kStylisticAltEightOffSelector 17
|
||||
#define kStylisticAltEightOnSelector 16
|
||||
#define kStylisticAltEighteenOffSelector 37
|
||||
#define kStylisticAltEighteenOnSelector 36
|
||||
#define kStylisticAltElevenOffSelector 23
|
||||
#define kStylisticAltElevenOnSelector 22
|
||||
#define kStylisticAltFifteenOffSelector 31
|
||||
#define kStylisticAltFifteenOnSelector 30
|
||||
#define kStylisticAltFiveOffSelector 11
|
||||
#define kStylisticAltFiveOnSelector 10
|
||||
#define kStylisticAltFourOffSelector 9
|
||||
#define kStylisticAltFourOnSelector 8
|
||||
#define kStylisticAltFourteenOffSelector 29
|
||||
#define kStylisticAltFourteenOnSelector 28
|
||||
#define kStylisticAltNineOffSelector 19
|
||||
#define kStylisticAltNineOnSelector 18
|
||||
#define kStylisticAltNineteenOffSelector 39
|
||||
#define kStylisticAltNineteenOnSelector 38
|
||||
#define kStylisticAltOneOffSelector 3
|
||||
#define kStylisticAltOneOnSelector 2
|
||||
#define kStylisticAltSevenOffSelector 15
|
||||
#define kStylisticAltSevenOnSelector 14
|
||||
#define kStylisticAltSeventeenOffSelector 35
|
||||
#define kStylisticAltSeventeenOnSelector 34
|
||||
#define kStylisticAltSixOffSelector 13
|
||||
#define kStylisticAltSixOnSelector 12
|
||||
#define kStylisticAltSixteenOffSelector 33
|
||||
#define kStylisticAltSixteenOnSelector 32
|
||||
#define kStylisticAltTenOffSelector 21
|
||||
#define kStylisticAltTenOnSelector 20
|
||||
#define kStylisticAltThirteenOffSelector 27
|
||||
#define kStylisticAltThirteenOnSelector 26
|
||||
#define kStylisticAltThreeOffSelector 7
|
||||
#define kStylisticAltThreeOnSelector 6
|
||||
#define kStylisticAltTwelveOffSelector 25
|
||||
#define kStylisticAltTwelveOnSelector 24
|
||||
#define kStylisticAltTwentyOffSelector 41
|
||||
#define kStylisticAltTwentyOnSelector 40
|
||||
#define kStylisticAltTwoOffSelector 5
|
||||
#define kStylisticAltTwoOnSelector 4
|
||||
#define kStylisticAlternativesType 35
|
||||
#define kSwashAlternatesOffSelector 3
|
||||
#define kSwashAlternatesOnSelector 2
|
||||
#define kThirdWidthTextSelector 3
|
||||
#define kTraditionalNamesCharactersSelector 14
|
||||
#define kUpperCasePetiteCapsSelector 2
|
||||
#define kUpperCaseSmallCapsSelector 1
|
||||
#define kUpperCaseType 38
|
||||
|
||||
/* Table data courtesy of Apple. */
|
||||
static const struct feature_mapping_t {
|
||||
FourCharCode otFeatureTag;
|
||||
uint16_t aatFeatureType;
|
||||
uint16_t selectorToEnable;
|
||||
uint16_t selectorToDisable;
|
||||
} feature_mappings[] = {
|
||||
{ 'c2pc', kUpperCaseType, kUpperCasePetiteCapsSelector, kDefaultUpperCaseSelector },
|
||||
{ 'c2sc', kUpperCaseType, kUpperCaseSmallCapsSelector, kDefaultUpperCaseSelector },
|
||||
{ 'calt', kContextualAlternatesType, kContextualAlternatesOnSelector, kContextualAlternatesOffSelector },
|
||||
{ 'case', kCaseSensitiveLayoutType, kCaseSensitiveLayoutOnSelector, kCaseSensitiveLayoutOffSelector },
|
||||
{ 'clig', kLigaturesType, kContextualLigaturesOnSelector, kContextualLigaturesOffSelector },
|
||||
{ 'cpsp', kCaseSensitiveLayoutType, kCaseSensitiveSpacingOnSelector, kCaseSensitiveSpacingOffSelector },
|
||||
{ 'cswh', kContextualAlternatesType, kContextualSwashAlternatesOnSelector, kContextualSwashAlternatesOffSelector },
|
||||
{ 'dlig', kLigaturesType, kRareLigaturesOnSelector, kRareLigaturesOffSelector },
|
||||
{ 'expt', kCharacterShapeType, kExpertCharactersSelector, 16 },
|
||||
{ 'frac', kFractionsType, kDiagonalFractionsSelector, kNoFractionsSelector },
|
||||
{ 'fwid', kTextSpacingType, kMonospacedTextSelector, 7 },
|
||||
{ 'halt', kTextSpacingType, kAltHalfWidthTextSelector, 7 },
|
||||
{ 'hist', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector },
|
||||
{ 'hkna', kAlternateKanaType, kAlternateHorizKanaOnSelector, kAlternateHorizKanaOffSelector, },
|
||||
{ 'hlig', kLigaturesType, kHistoricalLigaturesOnSelector, kHistoricalLigaturesOffSelector },
|
||||
{ 'hngl', kTransliterationType, kHanjaToHangulSelector, kNoTransliterationSelector },
|
||||
{ 'hojo', kCharacterShapeType, kHojoCharactersSelector, 16 },
|
||||
{ 'hwid', kTextSpacingType, kHalfWidthTextSelector, 7 },
|
||||
{ 'ital', kItalicCJKRomanType, kCJKItalicRomanOnSelector, kCJKItalicRomanOffSelector },
|
||||
{ 'jp04', kCharacterShapeType, kJIS2004CharactersSelector, 16 },
|
||||
{ 'jp78', kCharacterShapeType, kJIS1978CharactersSelector, 16 },
|
||||
{ 'jp83', kCharacterShapeType, kJIS1983CharactersSelector, 16 },
|
||||
{ 'jp90', kCharacterShapeType, kJIS1990CharactersSelector, 16 },
|
||||
{ 'liga', kLigaturesType, kCommonLigaturesOnSelector, kCommonLigaturesOffSelector },
|
||||
{ 'lnum', kNumberCaseType, kUpperCaseNumbersSelector, 2 },
|
||||
{ 'mgrk', kMathematicalExtrasType, kMathematicalGreekOnSelector, kMathematicalGreekOffSelector },
|
||||
{ 'nlck', kCharacterShapeType, kNLCCharactersSelector, 16 },
|
||||
{ 'onum', kNumberCaseType, kLowerCaseNumbersSelector, 2 },
|
||||
{ 'ordn', kVerticalPositionType, kOrdinalsSelector, kNormalPositionSelector },
|
||||
{ 'palt', kTextSpacingType, kAltProportionalTextSelector, 7 },
|
||||
{ 'pcap', kLowerCaseType, kLowerCasePetiteCapsSelector, kDefaultLowerCaseSelector },
|
||||
{ 'pkna', kTextSpacingType, kProportionalTextSelector, 7 },
|
||||
{ 'pnum', kNumberSpacingType, kProportionalNumbersSelector, 4 },
|
||||
{ 'pwid', kTextSpacingType, kProportionalTextSelector, 7 },
|
||||
{ 'qwid', kTextSpacingType, kQuarterWidthTextSelector, 7 },
|
||||
{ 'ruby', kRubyKanaType, kRubyKanaOnSelector, kRubyKanaOffSelector },
|
||||
{ 'sinf', kVerticalPositionType, kScientificInferiorsSelector, kNormalPositionSelector },
|
||||
{ 'smcp', kLowerCaseType, kLowerCaseSmallCapsSelector, kDefaultLowerCaseSelector },
|
||||
{ 'smpl', kCharacterShapeType, kSimplifiedCharactersSelector, 16 },
|
||||
{ 'ss01', kStylisticAlternativesType, kStylisticAltOneOnSelector, kStylisticAltOneOffSelector },
|
||||
{ 'ss02', kStylisticAlternativesType, kStylisticAltTwoOnSelector, kStylisticAltTwoOffSelector },
|
||||
{ 'ss03', kStylisticAlternativesType, kStylisticAltThreeOnSelector, kStylisticAltThreeOffSelector },
|
||||
{ 'ss04', kStylisticAlternativesType, kStylisticAltFourOnSelector, kStylisticAltFourOffSelector },
|
||||
{ 'ss05', kStylisticAlternativesType, kStylisticAltFiveOnSelector, kStylisticAltFiveOffSelector },
|
||||
{ 'ss06', kStylisticAlternativesType, kStylisticAltSixOnSelector, kStylisticAltSixOffSelector },
|
||||
{ 'ss07', kStylisticAlternativesType, kStylisticAltSevenOnSelector, kStylisticAltSevenOffSelector },
|
||||
{ 'ss08', kStylisticAlternativesType, kStylisticAltEightOnSelector, kStylisticAltEightOffSelector },
|
||||
{ 'ss09', kStylisticAlternativesType, kStylisticAltNineOnSelector, kStylisticAltNineOffSelector },
|
||||
{ 'ss10', kStylisticAlternativesType, kStylisticAltTenOnSelector, kStylisticAltTenOffSelector },
|
||||
{ 'ss11', kStylisticAlternativesType, kStylisticAltElevenOnSelector, kStylisticAltElevenOffSelector },
|
||||
{ 'ss12', kStylisticAlternativesType, kStylisticAltTwelveOnSelector, kStylisticAltTwelveOffSelector },
|
||||
{ 'ss13', kStylisticAlternativesType, kStylisticAltThirteenOnSelector, kStylisticAltThirteenOffSelector },
|
||||
{ 'ss14', kStylisticAlternativesType, kStylisticAltFourteenOnSelector, kStylisticAltFourteenOffSelector },
|
||||
{ 'ss15', kStylisticAlternativesType, kStylisticAltFifteenOnSelector, kStylisticAltFifteenOffSelector },
|
||||
{ 'ss16', kStylisticAlternativesType, kStylisticAltSixteenOnSelector, kStylisticAltSixteenOffSelector },
|
||||
{ 'ss17', kStylisticAlternativesType, kStylisticAltSeventeenOnSelector, kStylisticAltSeventeenOffSelector },
|
||||
{ 'ss18', kStylisticAlternativesType, kStylisticAltEighteenOnSelector, kStylisticAltEighteenOffSelector },
|
||||
{ 'ss19', kStylisticAlternativesType, kStylisticAltNineteenOnSelector, kStylisticAltNineteenOffSelector },
|
||||
{ 'ss20', kStylisticAlternativesType, kStylisticAltTwentyOnSelector, kStylisticAltTwentyOffSelector },
|
||||
{ 'subs', kVerticalPositionType, kInferiorsSelector, kNormalPositionSelector },
|
||||
{ 'sups', kVerticalPositionType, kSuperiorsSelector, kNormalPositionSelector },
|
||||
{ 'swsh', kContextualAlternatesType, kSwashAlternatesOnSelector, kSwashAlternatesOffSelector },
|
||||
{ 'titl', kStyleOptionsType, kTitlingCapsSelector, kNoStyleOptionsSelector },
|
||||
{ 'tnam', kCharacterShapeType, kTraditionalNamesCharactersSelector, 16 },
|
||||
{ 'tnum', kNumberSpacingType, kMonospacedNumbersSelector, 4 },
|
||||
{ 'trad', kCharacterShapeType, kTraditionalCharactersSelector, 16 },
|
||||
{ 'twid', kTextSpacingType, kThirdWidthTextSelector, 7 },
|
||||
{ 'unic', kLetterCaseType, 14, 15 },
|
||||
{ 'valt', kTextSpacingType, kAltProportionalTextSelector, 7 },
|
||||
{ 'vert', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector },
|
||||
{ 'vhal', kTextSpacingType, kAltHalfWidthTextSelector, 7 },
|
||||
{ 'vkna', kAlternateKanaType, kAlternateVertKanaOnSelector, kAlternateVertKanaOffSelector },
|
||||
{ 'vpal', kTextSpacingType, kAltProportionalTextSelector, 7 },
|
||||
{ 'vrt2', kVerticalSubstitutionType, kSubstituteVerticalFormsOnSelector, kSubstituteVerticalFormsOffSelector },
|
||||
{ 'zero', kTypographicExtrasType, kSlashedZeroOnSelector, kSlashedZeroOffSelector },
|
||||
};
|
||||
|
||||
static int
|
||||
_hb_feature_mapping_cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
unsigned int key = * (unsigned int *) key_;
|
||||
const feature_mapping_t * entry = (const feature_mapping_t *) entry_;
|
||||
return key < entry->otFeatureTag ? -1 :
|
||||
key > entry->otFeatureTag ? 1 :
|
||||
0;
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
_hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
CGFontRef cg_font = (CGFontRef) HB_SHAPER_DATA_GET (face);
|
||||
CTFontRef ct_font = (CTFontRef) HB_SHAPER_DATA_GET (font);
|
||||
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
|
||||
CTFontRef ct_font = (CTFontRef) hb_coretext_font_data_sync (font);
|
||||
|
||||
CGFloat ct_font_size = CTFontGetSize (ct_font);
|
||||
CGFloat x_mult = (CGFloat) font->x_scale / ct_font_size;
|
||||
CGFloat y_mult = (CGFloat) font->y_scale / ct_font_size;
|
||||
|
||||
/* Attach marks to their bases, to match the 'ot' shaper.
|
||||
* Adapted from hb-ot-shape:hb_form_clusters().
|
||||
* Adapted from a very old version of hb-ot-shape:hb_form_clusters().
|
||||
* Note that this only makes us be closer to the 'ot' shaper,
|
||||
* but by no means the same. For example, if there's
|
||||
* B1 M1 B2 M2, and B1-B2 form a ligature, M2's cluster will
|
||||
|
|
@ -618,8 +482,8 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
buffer->merge_clusters (i - 1, i + 1);
|
||||
}
|
||||
|
||||
hb_auto_array_t<feature_record_t> feature_records;
|
||||
hb_auto_array_t<range_record_t> range_records;
|
||||
hb_vector_t<feature_record_t> feature_records;
|
||||
hb_vector_t<range_record_t> range_records;
|
||||
|
||||
/*
|
||||
* Set up features.
|
||||
|
|
@ -628,16 +492,12 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
if (num_features)
|
||||
{
|
||||
/* Sort features by start/end events. */
|
||||
hb_auto_array_t<feature_event_t> feature_events;
|
||||
hb_vector_t<feature_event_t> feature_events;
|
||||
for (unsigned int i = 0; i < num_features; i++)
|
||||
{
|
||||
const feature_mapping_t * mapping = (const feature_mapping_t *) bsearch (&features[i].tag,
|
||||
feature_mappings,
|
||||
ARRAY_LENGTH (feature_mappings),
|
||||
sizeof (feature_mappings[0]),
|
||||
_hb_feature_mapping_cmp);
|
||||
const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
|
||||
if (!mapping)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
active_feature_t feature;
|
||||
feature.rec.feature = mapping->aatFeatureType;
|
||||
|
|
@ -647,15 +507,11 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
feature_event_t *event;
|
||||
|
||||
event = feature_events.push ();
|
||||
if (unlikely (!event))
|
||||
goto fail_features;
|
||||
event->index = features[i].start;
|
||||
event->start = true;
|
||||
event->feature = feature;
|
||||
|
||||
event = feature_events.push ();
|
||||
if (unlikely (!event))
|
||||
goto fail_features;
|
||||
event->index = features[i].end;
|
||||
event->start = false;
|
||||
event->feature = feature;
|
||||
|
|
@ -669,34 +525,30 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
feature.order = num_features + 1;
|
||||
|
||||
feature_event_t *event = feature_events.push ();
|
||||
if (unlikely (!event))
|
||||
goto fail_features;
|
||||
event->index = 0; /* This value does magic. */
|
||||
event->start = false;
|
||||
event->feature = feature;
|
||||
}
|
||||
|
||||
/* Scan events and save features for each range. */
|
||||
hb_auto_array_t<active_feature_t> active_features;
|
||||
hb_vector_t<active_feature_t> active_features;
|
||||
unsigned int last_index = 0;
|
||||
for (unsigned int i = 0; i < feature_events.len; i++)
|
||||
for (unsigned int i = 0; i < feature_events.length; i++)
|
||||
{
|
||||
feature_event_t *event = &feature_events[i];
|
||||
|
||||
if (event->index != last_index)
|
||||
{
|
||||
/* Save a snapshot of active features and the range. */
|
||||
/* Save a snapshot of active features and the range. */
|
||||
range_record_t *range = range_records.push ();
|
||||
if (unlikely (!range))
|
||||
goto fail_features;
|
||||
|
||||
if (active_features.len)
|
||||
if (active_features.length)
|
||||
{
|
||||
CFMutableArrayRef features_array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
|
||||
/* TODO sort and resolve conflicting features? */
|
||||
/* active_features.qsort (); */
|
||||
for (unsigned int j = 0; j < active_features.len; j++)
|
||||
for (unsigned int j = 0; j < active_features.length; j++)
|
||||
{
|
||||
CFStringRef keys[] = {
|
||||
kCTFontFeatureTypeIdentifierKey,
|
||||
|
|
@ -746,30 +598,23 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
last_index = event->index;
|
||||
}
|
||||
|
||||
if (event->start) {
|
||||
active_feature_t *feature = active_features.push ();
|
||||
if (unlikely (!feature))
|
||||
goto fail_features;
|
||||
*feature = event->feature;
|
||||
if (event->start)
|
||||
{
|
||||
active_features.push (event->feature);
|
||||
} else {
|
||||
active_feature_t *feature = active_features.find (&event->feature);
|
||||
active_feature_t *feature = active_features.find (&event->feature);
|
||||
if (feature)
|
||||
active_features.remove (feature - active_features.array);
|
||||
active_features.remove (feature - active_features.arrayZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fail_features:
|
||||
num_features = 0;
|
||||
}
|
||||
|
||||
unsigned int scratch_size;
|
||||
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
|
||||
#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
|
||||
Type *name = (Type *) scratch; \
|
||||
{ \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
if (unlikely (_consumed > scratch_size)) \
|
||||
{ \
|
||||
|
|
@ -778,7 +623,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
} \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
|
||||
unsigned int chars_len = 0;
|
||||
|
|
@ -810,13 +655,13 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
|||
DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
|
||||
ret = false; \
|
||||
goto fail; \
|
||||
} HB_STMT_END;
|
||||
} HB_STMT_END
|
||||
|
||||
bool ret = true;
|
||||
CFStringRef string_ref = nullptr;
|
||||
CTLineRef line = nullptr;
|
||||
|
||||
if (0)
|
||||
if (false)
|
||||
{
|
||||
resize_and_retry:
|
||||
DEBUG_MSG (CORETEXT, buffer, "Buffer resize");
|
||||
|
|
@ -872,15 +717,18 @@ resize_and_retry:
|
|||
/* What's the iOS equivalent of this check?
|
||||
* The symbols was introduced in iOS 7.0.
|
||||
* At any rate, our fallback is safe and works fine. */
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090
|
||||
# define kCTLanguageAttributeName CFSTR ("NSLanguage")
|
||||
#endif
|
||||
CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
|
||||
CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
|
||||
hb_language_to_string (buffer->props.language),
|
||||
kCFStringEncodingUTF8,
|
||||
kCFAllocatorNull);
|
||||
if (unlikely (!lang))
|
||||
{
|
||||
CFRelease (attr_string);
|
||||
FAIL ("CFStringCreateWithCStringNoCopy failed");
|
||||
}
|
||||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
|
||||
kCTLanguageAttributeName, lang);
|
||||
CFRelease (lang);
|
||||
|
|
@ -888,7 +736,7 @@ resize_and_retry:
|
|||
CFAttributedStringSetAttribute (attr_string, CFRangeMake (0, chars_len),
|
||||
kCTFontAttributeName, ct_font);
|
||||
|
||||
if (num_features && range_records.len)
|
||||
if (num_features && range_records.length)
|
||||
{
|
||||
unsigned int start = 0;
|
||||
range_record_t *last_range = &range_records[0];
|
||||
|
|
@ -929,7 +777,7 @@ resize_and_retry:
|
|||
feature.start < chars_len && feature.start < feature.end)
|
||||
{
|
||||
CFRange feature_range = CFRangeMake (feature.start,
|
||||
MIN (feature.end, chars_len) - feature.start);
|
||||
hb_min (feature.end, chars_len) - feature.start);
|
||||
if (feature.value)
|
||||
CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
|
||||
else
|
||||
|
|
@ -941,6 +789,9 @@ resize_and_retry:
|
|||
|
||||
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
|
||||
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
|
||||
#endif
|
||||
CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
|
||||
(const void **) &kCTTypesetterOptionForcedEmbeddingLevel,
|
||||
(const void **) &level_number,
|
||||
|
|
@ -949,7 +800,10 @@ resize_and_retry:
|
|||
&kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease (level_number);
|
||||
if (unlikely (!options))
|
||||
FAIL ("CFDictionaryCreate failed");
|
||||
{
|
||||
CFRelease (attr_string);
|
||||
FAIL ("CFDictionaryCreate failed");
|
||||
}
|
||||
|
||||
CTTypesetterRef typesetter = CTTypesetterCreateWithAttributedStringAndOptions (attr_string, options);
|
||||
CFRelease (options);
|
||||
|
|
@ -973,7 +827,7 @@ resize_and_retry:
|
|||
/* For right-to-left runs, CoreText returns the glyphs positioned such that
|
||||
* any trailing whitespace is to the left of (0,0). Adjust coordinate system
|
||||
* to fix for that. Test with any RTL string with trailing spaces.
|
||||
* https://code.google.com/p/chromium/issues/detail?id=469028
|
||||
* https://crbug.com/469028
|
||||
*/
|
||||
if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
|
||||
{
|
||||
|
|
@ -1026,12 +880,12 @@ resize_and_retry:
|
|||
* However, even that wouldn't work if we were passed in the CGFont to
|
||||
* construct a hb_face to begin with.
|
||||
*
|
||||
* See: http://github.com/harfbuzz/harfbuzz/pull/36
|
||||
* See: https://github.com/harfbuzz/harfbuzz/pull/36
|
||||
*
|
||||
* Also see: https://bugs.chromium.org/p/chromium/issues/detail?id=597098
|
||||
*/
|
||||
bool matched = false;
|
||||
for (unsigned int i = 0; i < range_records.len; i++)
|
||||
for (unsigned int i = 0; i < range_records.length; i++)
|
||||
if (range_records[i].font && CFEqual (run_ct_font, range_records[i].font))
|
||||
{
|
||||
matched = true;
|
||||
|
|
@ -1039,7 +893,7 @@ resize_and_retry:
|
|||
}
|
||||
if (!matched)
|
||||
{
|
||||
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, 0);
|
||||
CGFontRef run_cg_font = CTFontCopyGraphicsFont (run_ct_font, nullptr);
|
||||
if (run_cg_font)
|
||||
{
|
||||
matched = CFEqual (run_cg_font, cg_font);
|
||||
|
|
@ -1059,7 +913,7 @@ resize_and_retry:
|
|||
if (!matched)
|
||||
{
|
||||
CFRange range = CTRunGetStringRange (run);
|
||||
DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
|
||||
DEBUG_MSG (CORETEXT, run, "Run used fallback font: %ld..%ld",
|
||||
range.location, range.location + range.length);
|
||||
if (!buffer->ensure_inplace (buffer->len + range.length))
|
||||
goto resize_and_retry;
|
||||
|
|
@ -1087,7 +941,7 @@ resize_and_retry:
|
|||
continue;
|
||||
}
|
||||
if (buffer->unicode->is_default_ignorable (ch))
|
||||
continue;
|
||||
continue;
|
||||
|
||||
info->codepoint = notdef;
|
||||
info->cluster = log_clusters[j];
|
||||
|
|
@ -1129,10 +983,10 @@ resize_and_retry:
|
|||
|
||||
#define SCRATCH_RESTORE() \
|
||||
scratch_size = scratch_size_saved; \
|
||||
scratch = scratch_saved;
|
||||
scratch = scratch_saved
|
||||
|
||||
{ /* Setup glyphs */
|
||||
SCRATCH_SAVE();
|
||||
SCRATCH_SAVE();
|
||||
const CGGlyph* glyphs = USE_PTR ? CTRunGetGlyphsPtr (run) : nullptr;
|
||||
if (!glyphs) {
|
||||
ALLOCATE_ARRAY (CGGlyph, glyph_buf, num_glyphs, goto resize_and_retry);
|
||||
|
|
@ -1155,12 +1009,12 @@ resize_and_retry:
|
|||
SCRATCH_RESTORE();
|
||||
}
|
||||
{
|
||||
/* Setup positions.
|
||||
/* Setup positions.
|
||||
* Note that CoreText does not return advances for glyphs. As such,
|
||||
* for all but last glyph, we use the delta position to next glyph as
|
||||
* advance (in the advance direction only), and for last glyph we set
|
||||
* whatever is needed to make the whole run's advance add up. */
|
||||
SCRATCH_SAVE();
|
||||
SCRATCH_SAVE();
|
||||
const CGPoint* positions = USE_PTR ? CTRunGetPositionsPtr (run) : nullptr;
|
||||
if (!positions) {
|
||||
ALLOCATE_ARRAY (CGPoint, position_buf, num_glyphs, goto resize_and_retry);
|
||||
|
|
@ -1212,16 +1066,16 @@ resize_and_retry:
|
|||
}
|
||||
|
||||
/* Mac OS 10.6 doesn't have kCTTypesetterOptionForcedEmbeddingLevel,
|
||||
* or if it does, it doesn't resepct it. So we get runs with wrong
|
||||
* or if it does, it doesn't respect it. So we get runs with wrong
|
||||
* directions. As such, disable the assert... It wouldn't crash, but
|
||||
* cursoring will be off...
|
||||
*
|
||||
* http://crbug.com/419769
|
||||
* https://crbug.com/419769
|
||||
*/
|
||||
if (0)
|
||||
if (false)
|
||||
{
|
||||
/* Make sure all runs had the expected direction. */
|
||||
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
|
||||
assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
|
||||
}
|
||||
|
|
@ -1238,8 +1092,6 @@ resize_and_retry:
|
|||
pos->x_offset = info->var1.i32;
|
||||
pos->y_offset = info->var2.i32;
|
||||
|
||||
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
|
||||
info++, pos++;
|
||||
}
|
||||
else
|
||||
|
|
@ -1249,8 +1101,6 @@ resize_and_retry:
|
|||
pos->x_offset = info->var1.i32;
|
||||
pos->y_offset = info->var2.i32;
|
||||
|
||||
info->mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
|
||||
info++, pos++;
|
||||
}
|
||||
|
||||
|
|
@ -1272,7 +1122,7 @@ resize_and_retry:
|
|||
unsigned int cluster = info[count - 1].cluster;
|
||||
for (unsigned int i = count - 1; i > 0; i--)
|
||||
{
|
||||
cluster = MIN (cluster, info[i - 1].cluster);
|
||||
cluster = hb_min (cluster, info[i - 1].cluster);
|
||||
info[i - 1].cluster = cluster;
|
||||
}
|
||||
}
|
||||
|
|
@ -1281,7 +1131,7 @@ resize_and_retry:
|
|||
unsigned int cluster = info[0].cluster;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
cluster = MIN (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
info[i].cluster = cluster;
|
||||
}
|
||||
}
|
||||
|
|
@ -1298,7 +1148,7 @@ fail:
|
|||
if (line)
|
||||
CFRelease (line);
|
||||
|
||||
for (unsigned int i = 0; i < range_records.len; i++)
|
||||
for (unsigned int i = 0; i < range_records.length; i++)
|
||||
if (range_records[i].font)
|
||||
CFRelease (range_records[i].font);
|
||||
|
||||
|
|
@ -1306,94 +1156,4 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* AAT shaper
|
||||
*/
|
||||
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, face)
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_shaper_face_data_t {};
|
||||
|
||||
hb_coretext_aat_shaper_face_data_t *
|
||||
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (tags); i++)
|
||||
{
|
||||
hb_blob_t *blob = face->reference_table (tags[i]);
|
||||
if (hb_blob_get_length (blob))
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
}
|
||||
hb_blob_destroy (blob);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_shaper_font_data_t {};
|
||||
|
||||
hb_coretext_aat_shaper_font_data_t *
|
||||
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_shaper_shape_plan_data_t {};
|
||||
|
||||
hb_coretext_aat_shaper_shape_plan_data_t *
|
||||
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
return _hb_coretext_shape (shape_plan, font, buffer, features, num_features);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,13 +27,63 @@
|
|||
#ifndef HB_DEBUG_HH
|
||||
#define HB_DEBUG_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb.hh"
|
||||
#include "hb-atomic.hh"
|
||||
#include "hb-algs.hh"
|
||||
|
||||
|
||||
#ifndef HB_DEBUG
|
||||
#define HB_DEBUG 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Global runtime options.
|
||||
*/
|
||||
|
||||
struct hb_options_t
|
||||
{
|
||||
bool unused : 1; /* In-case sign bit is here. */
|
||||
bool initialized : 1;
|
||||
bool uniscribe_bug_compatible : 1;
|
||||
bool aat : 1;
|
||||
};
|
||||
|
||||
union hb_options_union_t {
|
||||
int i;
|
||||
hb_options_t opts;
|
||||
};
|
||||
static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_options_init ();
|
||||
|
||||
extern HB_INTERNAL hb_atomic_int_t _hb_options;
|
||||
|
||||
static inline hb_options_t
|
||||
hb_options ()
|
||||
{
|
||||
#ifdef HB_NO_GETENV
|
||||
return hb_options_t ();
|
||||
#endif
|
||||
/* Make a local copy, so we can access bitfield threadsafely. */
|
||||
hb_options_union_t u;
|
||||
u.i = _hb_options.get_relaxed ();
|
||||
|
||||
if (unlikely (!u.i))
|
||||
{
|
||||
_hb_options_init ();
|
||||
u.i = _hb_options.get_relaxed ();
|
||||
}
|
||||
|
||||
return u.opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Debug output (needs enabling at compile time.)
|
||||
*/
|
||||
|
||||
static inline bool
|
||||
_hb_debug (unsigned int level,
|
||||
unsigned int max_level)
|
||||
|
|
@ -111,7 +161,7 @@ _hb_debug_msg_va (const char *what,
|
|||
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
|
||||
fprintf (stderr, "%2u %s" VRBAR "%s",
|
||||
level,
|
||||
bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
|
||||
} else
|
||||
fprintf (stderr, " " VRBAR LBAR);
|
||||
|
|
@ -126,7 +176,7 @@ _hb_debug_msg_va (const char *what,
|
|||
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
template <> inline void
|
||||
template <> inline void HB_PRINTF_FUNC(7, 0)
|
||||
_hb_debug_msg_va<0> (const char *what HB_UNUSED,
|
||||
const void *obj HB_UNUSED,
|
||||
const char *func HB_UNUSED,
|
||||
|
|
@ -145,7 +195,7 @@ _hb_debug_msg (const char *what,
|
|||
int level_dir,
|
||||
const char *message,
|
||||
...) HB_PRINTF_FUNC(7, 8);
|
||||
template <int max_level> static inline void
|
||||
template <int max_level> static inline void HB_PRINTF_FUNC(7, 8)
|
||||
_hb_debug_msg (const char *what,
|
||||
const void *obj,
|
||||
const char *func,
|
||||
|
|
@ -169,7 +219,7 @@ _hb_debug_msg<0> (const char *what HB_UNUSED,
|
|||
int level_dir HB_UNUSED,
|
||||
const char *message HB_UNUSED,
|
||||
...) HB_PRINTF_FUNC(7, 8);
|
||||
template <> inline void
|
||||
template <> inline void HB_PRINTF_FUNC(7, 8)
|
||||
_hb_debug_msg<0> (const char *what HB_UNUSED,
|
||||
const void *obj HB_UNUSED,
|
||||
const char *func HB_UNUSED,
|
||||
|
|
@ -199,8 +249,8 @@ struct hb_printer_t<bool> {
|
|||
};
|
||||
|
||||
template <>
|
||||
struct hb_printer_t<hb_void_t> {
|
||||
const char *print (hb_void_t) { return ""; }
|
||||
struct hb_printer_t<hb_empty_t> {
|
||||
const char *print (hb_empty_t) { return ""; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -216,7 +266,7 @@ static inline void _hb_warn_no_return (bool returned)
|
|||
}
|
||||
}
|
||||
template <>
|
||||
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
|
||||
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
|
||||
{}
|
||||
|
||||
template <int max_level, typename ret_t>
|
||||
|
|
@ -237,7 +287,7 @@ struct hb_auto_trace_t
|
|||
_hb_debug_msg_va<max_level> (what, obj, func, true, plevel ? *plevel : 0, +1, message, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
inline ~hb_auto_trace_t (void)
|
||||
~hb_auto_trace_t ()
|
||||
{
|
||||
_hb_warn_no_return<ret_t> (returned);
|
||||
if (!returned) {
|
||||
|
|
@ -246,20 +296,23 @@ struct hb_auto_trace_t
|
|||
if (plevel) --*plevel;
|
||||
}
|
||||
|
||||
inline ret_t ret (ret_t v, unsigned int line = 0)
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func = "",
|
||||
unsigned int line = 0)
|
||||
{
|
||||
if (unlikely (returned)) {
|
||||
fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
|
||||
return v;
|
||||
return hb_forward<T> (v);
|
||||
}
|
||||
|
||||
_hb_debug_msg<max_level> (what, obj, nullptr, true, plevel ? *plevel : 1, -1,
|
||||
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
|
||||
"return %s (line %d)",
|
||||
hb_printer_t<ret_t>().print (v), line);
|
||||
hb_printer_t<decltype (v)>().print (v), line);
|
||||
if (plevel) --*plevel;
|
||||
plevel = nullptr;
|
||||
returned = true;
|
||||
return v;
|
||||
return hb_forward<T> (v);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
@ -278,17 +331,23 @@ struct hb_auto_trace_t<0, ret_t>
|
|||
const char *message,
|
||||
...) HB_PRINTF_FUNC(6, 7) {}
|
||||
|
||||
inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
/* For disabled tracing; optimize out everything.
|
||||
* https://github.com/harfbuzz/harfbuzz/pull/605 */
|
||||
template <typename ret_t>
|
||||
struct hb_no_trace_t {
|
||||
inline ret_t ret (ret_t v, unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
#define return_trace(RET) return trace.ret (RET, __LINE__)
|
||||
#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -348,30 +407,6 @@ struct hb_no_trace_t {
|
|||
#define TRACE_APPLY(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_CLOSURE
|
||||
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
|
||||
#endif
|
||||
#if HB_DEBUG_CLOSURE
|
||||
#define TRACE_CLOSURE(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_CLOSURE(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_COLLECT_GLYPHS
|
||||
#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
|
||||
#endif
|
||||
#if HB_DEBUG_COLLECT_GLYPHS
|
||||
#define TRACE_COLLECT_GLYPHS(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_COLLECT_GLYPHS(this) hb_no_trace_t<hb_void_t> trace HB_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_SANITIZE
|
||||
#define HB_DEBUG_SANITIZE (HB_DEBUG+0)
|
||||
#endif
|
||||
|
|
@ -379,7 +414,7 @@ struct hb_no_trace_t {
|
|||
#define TRACE_SANITIZE(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ");
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
|
|
@ -391,38 +426,36 @@ struct hb_no_trace_t {
|
|||
#define TRACE_SERIALIZE(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
|
||||
(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
|
||||
" ");
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_WOULD_APPLY
|
||||
#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
|
||||
#ifndef HB_DEBUG_SUBSET
|
||||
#define HB_DEBUG_SUBSET (HB_DEBUG+0)
|
||||
#endif
|
||||
#if HB_DEBUG_WOULD_APPLY
|
||||
#define TRACE_WOULD_APPLY(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
"%d glyphs", c->len);
|
||||
#if HB_DEBUG_SUBSET
|
||||
#define TRACE_SUBSET(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
|
||||
#define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_DISPATCH
|
||||
#define HB_DEBUG_DISPATCH ( \
|
||||
HB_DEBUG_APPLY + \
|
||||
HB_DEBUG_CLOSURE + \
|
||||
HB_DEBUG_COLLECT_GLYPHS + \
|
||||
HB_DEBUG_SANITIZE + \
|
||||
HB_DEBUG_SERIALIZE + \
|
||||
HB_DEBUG_WOULD_APPLY + \
|
||||
HB_DEBUG_SUBSET + \
|
||||
0)
|
||||
#endif
|
||||
#if HB_DEBUG_DISPATCH
|
||||
#define TRACE_DISPATCH(this, format) \
|
||||
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
"format %d", (int) format);
|
||||
"format %d", (int) format)
|
||||
#else
|
||||
#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -36,10 +36,23 @@
|
|||
#include "hb-font.h"
|
||||
#include "hb-set.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-deprecated
|
||||
* @title: hb-deprecated
|
||||
* @short_description: Deprecated API
|
||||
* @include: hb.h
|
||||
*
|
||||
* These API have been deprecated in favor of newer API, or because they
|
||||
* were deemed unnecessary.
|
||||
**/
|
||||
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
|
||||
|
||||
#define HB_SCRIPT_CANADIAN_ABORIGINAL HB_SCRIPT_CANADIAN_SYLLABICS
|
||||
|
||||
#define HB_BUFFER_FLAGS_DEFAULT HB_BUFFER_FLAG_DEFAULT
|
||||
|
|
@ -50,14 +63,131 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
|
|||
hb_codepoint_t *glyph,
|
||||
void *user_data);
|
||||
|
||||
HB_EXTERN void
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
|
||||
hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN void
|
||||
HB_EXTERN HB_DEPRECATED void
|
||||
hb_set_invert (hb_set_t *set);
|
||||
|
||||
/**
|
||||
* hb_unicode_eastasian_width_func_t:
|
||||
*
|
||||
* Deprecated: 2.0.0
|
||||
*/
|
||||
typedef unsigned int (*hb_unicode_eastasian_width_func_t) (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* hb_unicode_funcs_set_eastasian_width_func:
|
||||
* @ufuncs: a Unicode function structure
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
HB_EXTERN HB_DEPRECATED void
|
||||
hb_unicode_funcs_set_eastasian_width_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_eastasian_width_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_unicode_eastasian_width:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
HB_EXTERN HB_DEPRECATED unsigned int
|
||||
hb_unicode_eastasian_width (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t unicode);
|
||||
|
||||
|
||||
/**
|
||||
* hb_unicode_decompose_compatibility_func_t:
|
||||
* @ufuncs: a Unicode function structure
|
||||
* @u: codepoint to decompose
|
||||
* @decomposed: address of codepoint array (of length %HB_UNICODE_MAX_DECOMPOSITION_LEN) to write decomposition into
|
||||
* @user_data: user data pointer as passed to hb_unicode_funcs_set_decompose_compatibility_func()
|
||||
*
|
||||
* Fully decompose @u to its Unicode compatibility decomposition. The codepoints of the decomposition will be written to @decomposed.
|
||||
* The complete length of the decomposition will be returned.
|
||||
*
|
||||
* If @u has no compatibility decomposition, zero should be returned.
|
||||
*
|
||||
* The Unicode standard guarantees that a buffer of length %HB_UNICODE_MAX_DECOMPOSITION_LEN codepoints will always be sufficient for any
|
||||
* compatibility decomposition plus an terminating value of 0. Consequently, @decompose must be allocated by the caller to be at least this length. Implementations
|
||||
* of this function type must ensure that they do not write past the provided array.
|
||||
*
|
||||
* Return value: number of codepoints in the full compatibility decomposition of @u, or 0 if no decomposition available.
|
||||
*
|
||||
* Deprecated: 2.0.0
|
||||
*/
|
||||
typedef unsigned int (*hb_unicode_decompose_compatibility_func_t) (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t u,
|
||||
hb_codepoint_t *decomposed,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* HB_UNICODE_MAX_DECOMPOSITION_LEN:
|
||||
*
|
||||
* See Unicode 6.1 for details on the maximum decomposition length.
|
||||
*
|
||||
* Deprecated: 2.0.0
|
||||
*/
|
||||
#define HB_UNICODE_MAX_DECOMPOSITION_LEN (18+1) /* codepoints */
|
||||
|
||||
/**
|
||||
* hb_unicode_funcs_set_decompose_compatibility_func:
|
||||
* @ufuncs: a Unicode function structure
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
HB_EXTERN HB_DEPRECATED void
|
||||
hb_unicode_funcs_set_decompose_compatibility_func (hb_unicode_funcs_t *ufuncs,
|
||||
hb_unicode_decompose_compatibility_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN HB_DEPRECATED unsigned int
|
||||
hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t u,
|
||||
hb_codepoint_t *decomposed);
|
||||
|
||||
|
||||
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_v_kerning_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_v_kerning_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_v_kerning (hb_font_t *font,
|
||||
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
|
||||
|
||||
#endif
|
||||
|
||||
HB_END_DECLS
|
||||
|
|
|
|||
|
|
@ -0,0 +1,979 @@
|
|||
/*
|
||||
* Copyright © 2015-2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_DIRECTWRITE
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include <dwrite_1.h>
|
||||
|
||||
#include "hb-directwrite.h"
|
||||
|
||||
|
||||
/* Declare object creator for dynamic support of DWRITE */
|
||||
typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
|
||||
DWRITE_FACTORY_TYPE factoryType,
|
||||
REFIID iid,
|
||||
IUnknown **factory
|
||||
);
|
||||
|
||||
/*
|
||||
* hb-directwrite uses new/delete syntatically but as we let users
|
||||
* to override malloc/free, we will redefine new/delete so users
|
||||
* won't need to do that by their own.
|
||||
*/
|
||||
void* operator new (size_t size) { return malloc (size); }
|
||||
void* operator new [] (size_t size) { return malloc (size); }
|
||||
void operator delete (void* pointer) { free (pointer); }
|
||||
void operator delete [] (void* pointer) { free (pointer); }
|
||||
|
||||
|
||||
/*
|
||||
* DirectWrite font stream helpers
|
||||
*/
|
||||
|
||||
// This is a font loader which provides only one font (unlike its original design).
|
||||
// For a better implementation which was also source of this
|
||||
// and DWriteFontFileStream, have a look at to NativeFontResourceDWrite.cpp in Mozilla
|
||||
class DWriteFontFileLoader : public IDWriteFontFileLoader
|
||||
{
|
||||
private:
|
||||
IDWriteFontFileStream *mFontFileStream;
|
||||
public:
|
||||
DWriteFontFileLoader (IDWriteFontFileStream *fontFileStream)
|
||||
{ mFontFileStream = fontFileStream; }
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
|
||||
{ return S_OK; }
|
||||
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
|
||||
IFACEMETHOD_ (ULONG, Release) () { return 1; }
|
||||
|
||||
// IDWriteFontFileLoader methods
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
CreateStreamFromKey (void const* fontFileReferenceKey,
|
||||
uint32_t fontFileReferenceKeySize,
|
||||
OUT IDWriteFontFileStream** fontFileStream)
|
||||
{
|
||||
*fontFileStream = mFontFileStream;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual ~DWriteFontFileLoader() {}
|
||||
};
|
||||
|
||||
class DWriteFontFileStream : public IDWriteFontFileStream
|
||||
{
|
||||
private:
|
||||
uint8_t *mData;
|
||||
uint32_t mSize;
|
||||
public:
|
||||
DWriteFontFileStream (uint8_t *aData, uint32_t aSize)
|
||||
{
|
||||
mData = aData;
|
||||
mSize = aSize;
|
||||
}
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
|
||||
{ return S_OK; }
|
||||
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
|
||||
IFACEMETHOD_ (ULONG, Release) () { return 1; }
|
||||
|
||||
// IDWriteFontFileStream methods
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
ReadFileFragment (void const** fragmentStart,
|
||||
UINT64 fileOffset,
|
||||
UINT64 fragmentSize,
|
||||
OUT void** fragmentContext)
|
||||
{
|
||||
// We are required to do bounds checking.
|
||||
if (fileOffset + fragmentSize > mSize) return E_FAIL;
|
||||
|
||||
// truncate the 64 bit fileOffset to size_t sized index into mData
|
||||
size_t index = static_cast<size_t> (fileOffset);
|
||||
|
||||
// We should be alive for the duration of this.
|
||||
*fragmentStart = &mData[index];
|
||||
*fragmentContext = nullptr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual void STDMETHODCALLTYPE
|
||||
ReleaseFileFragment (void* fragmentContext) {}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetFileSize (OUT UINT64* fileSize)
|
||||
{
|
||||
*fileSize = mSize;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE
|
||||
GetLastWriteTime (OUT UINT64* lastWriteTime) { return E_NOTIMPL; }
|
||||
|
||||
virtual ~DWriteFontFileStream() {}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_directwrite_face_data_t
|
||||
{
|
||||
HMODULE dwrite_dll;
|
||||
IDWriteFactory *dwriteFactory;
|
||||
IDWriteFontFile *fontFile;
|
||||
DWriteFontFileStream *fontFileStream;
|
||||
DWriteFontFileLoader *fontFileLoader;
|
||||
IDWriteFontFace *fontFace;
|
||||
hb_blob_t *faceBlob;
|
||||
};
|
||||
|
||||
hb_directwrite_face_data_t *
|
||||
_hb_directwrite_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_directwrite_face_data_t *data = new hb_directwrite_face_data_t;
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
#define FAIL(...) \
|
||||
HB_STMT_START { \
|
||||
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
|
||||
return nullptr; \
|
||||
} HB_STMT_END
|
||||
|
||||
data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
|
||||
if (unlikely (!data->dwrite_dll))
|
||||
FAIL ("Cannot find DWrite.DLL");
|
||||
|
||||
t_DWriteCreateFactory p_DWriteCreateFactory;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
#endif
|
||||
|
||||
p_DWriteCreateFactory = (t_DWriteCreateFactory)
|
||||
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
if (unlikely (!p_DWriteCreateFactory))
|
||||
FAIL ("Cannot find DWriteCreateFactory().");
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
// TODO: factory and fontFileLoader should be cached separately
|
||||
IDWriteFactory* dwriteFactory;
|
||||
hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
|
||||
(IUnknown**) &dwriteFactory);
|
||||
|
||||
if (unlikely (hr != S_OK))
|
||||
FAIL ("Failed to run DWriteCreateFactory().");
|
||||
|
||||
hb_blob_t *blob = hb_face_reference_blob (face);
|
||||
DWriteFontFileStream *fontFileStream;
|
||||
fontFileStream = new DWriteFontFileStream ((uint8_t *) hb_blob_get_data (blob, nullptr),
|
||||
hb_blob_get_length (blob));
|
||||
|
||||
DWriteFontFileLoader *fontFileLoader = new DWriteFontFileLoader (fontFileStream);
|
||||
dwriteFactory->RegisterFontFileLoader (fontFileLoader);
|
||||
|
||||
IDWriteFontFile *fontFile;
|
||||
uint64_t fontFileKey = 0;
|
||||
hr = dwriteFactory->CreateCustomFontFileReference (&fontFileKey, sizeof (fontFileKey),
|
||||
fontFileLoader, &fontFile);
|
||||
|
||||
if (FAILED (hr))
|
||||
FAIL ("Failed to load font file from data!");
|
||||
|
||||
BOOL isSupported;
|
||||
DWRITE_FONT_FILE_TYPE fileType;
|
||||
DWRITE_FONT_FACE_TYPE faceType;
|
||||
uint32_t numberOfFaces;
|
||||
hr = fontFile->Analyze (&isSupported, &fileType, &faceType, &numberOfFaces);
|
||||
if (FAILED (hr) || !isSupported)
|
||||
FAIL ("Font file is not supported.");
|
||||
|
||||
#undef FAIL
|
||||
|
||||
IDWriteFontFace *fontFace;
|
||||
dwriteFactory->CreateFontFace (faceType, 1, &fontFile, 0,
|
||||
DWRITE_FONT_SIMULATIONS_NONE, &fontFace);
|
||||
|
||||
data->dwriteFactory = dwriteFactory;
|
||||
data->fontFile = fontFile;
|
||||
data->fontFileStream = fontFileStream;
|
||||
data->fontFileLoader = fontFileLoader;
|
||||
data->fontFace = fontFace;
|
||||
data->faceBlob = blob;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
|
||||
{
|
||||
if (data->fontFace)
|
||||
data->fontFace->Release ();
|
||||
if (data->fontFile)
|
||||
data->fontFile->Release ();
|
||||
if (data->dwriteFactory)
|
||||
{
|
||||
if (data->fontFileLoader)
|
||||
data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
|
||||
data->dwriteFactory->Release ();
|
||||
}
|
||||
if (data->fontFileLoader)
|
||||
delete data->fontFileLoader;
|
||||
if (data->fontFileStream)
|
||||
delete data->fontFileStream;
|
||||
if (data->faceBlob)
|
||||
hb_blob_destroy (data->faceBlob);
|
||||
if (data->dwrite_dll)
|
||||
FreeLibrary (data->dwrite_dll);
|
||||
if (data)
|
||||
delete data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_directwrite_font_data_t {};
|
||||
|
||||
hb_directwrite_font_data_t *
|
||||
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t;
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
|
||||
// Most of TextAnalysis is originally written by Bas Schouten for Mozilla project
|
||||
// but now is relicensed to MIT for HarfBuzz use
|
||||
class TextAnalysis : public IDWriteTextAnalysisSource, public IDWriteTextAnalysisSink
|
||||
{
|
||||
public:
|
||||
|
||||
IFACEMETHOD (QueryInterface) (IID const& iid, OUT void** ppObject)
|
||||
{ return S_OK; }
|
||||
IFACEMETHOD_ (ULONG, AddRef) () { return 1; }
|
||||
IFACEMETHOD_ (ULONG, Release) () { return 1; }
|
||||
|
||||
// A single contiguous run of characters containing the same analysis
|
||||
// results.
|
||||
struct Run
|
||||
{
|
||||
uint32_t mTextStart; // starting text position of this run
|
||||
uint32_t mTextLength; // number of contiguous code units covered
|
||||
uint32_t mGlyphStart; // starting glyph in the glyphs array
|
||||
uint32_t mGlyphCount; // number of glyphs associated with this run
|
||||
// text
|
||||
DWRITE_SCRIPT_ANALYSIS mScript;
|
||||
uint8_t mBidiLevel;
|
||||
bool mIsSideways;
|
||||
|
||||
bool ContainsTextPosition (uint32_t aTextPosition) const
|
||||
{
|
||||
return aTextPosition >= mTextStart &&
|
||||
aTextPosition < mTextStart + mTextLength;
|
||||
}
|
||||
|
||||
Run *nextRun;
|
||||
};
|
||||
|
||||
public:
|
||||
TextAnalysis (const wchar_t* text, uint32_t textLength,
|
||||
const wchar_t* localeName, DWRITE_READING_DIRECTION readingDirection)
|
||||
: mTextLength (textLength), mText (text), mLocaleName (localeName),
|
||||
mReadingDirection (readingDirection), mCurrentRun (nullptr) {}
|
||||
~TextAnalysis ()
|
||||
{
|
||||
// delete runs, except mRunHead which is part of the TextAnalysis object
|
||||
for (Run *run = mRunHead.nextRun; run;)
|
||||
{
|
||||
Run *origRun = run;
|
||||
run = run->nextRun;
|
||||
delete origRun;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
GenerateResults (IDWriteTextAnalyzer* textAnalyzer, Run **runHead)
|
||||
{
|
||||
// Analyzes the text using the script analyzer and returns
|
||||
// the result as a series of runs.
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
// Initially start out with one result that covers the entire range.
|
||||
// This result will be subdivided by the analysis processes.
|
||||
mRunHead.mTextStart = 0;
|
||||
mRunHead.mTextLength = mTextLength;
|
||||
mRunHead.mBidiLevel =
|
||||
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
||||
mRunHead.nextRun = nullptr;
|
||||
mCurrentRun = &mRunHead;
|
||||
|
||||
// Call each of the analyzers in sequence, recording their results.
|
||||
if (SUCCEEDED (hr = textAnalyzer->AnalyzeScript (this, 0, mTextLength, this)))
|
||||
*runHead = &mRunHead;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
// IDWriteTextAnalysisSource implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetTextAtPosition (uint32_t textPosition,
|
||||
OUT wchar_t const** textString,
|
||||
OUT uint32_t* textLength)
|
||||
{
|
||||
if (textPosition >= mTextLength)
|
||||
{
|
||||
// No text at this position, valid query though.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*textString = mText + textPosition;
|
||||
*textLength = mTextLength - textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetTextBeforePosition (uint32_t textPosition,
|
||||
OUT wchar_t const** textString,
|
||||
OUT uint32_t* textLength)
|
||||
{
|
||||
if (textPosition == 0 || textPosition > mTextLength)
|
||||
{
|
||||
// Either there is no text before here (== 0), or this
|
||||
// is an invalid position. The query is considered valid though.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*textString = mText;
|
||||
*textLength = textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP_ (DWRITE_READING_DIRECTION)
|
||||
GetParagraphReadingDirection () { return mReadingDirection; }
|
||||
|
||||
IFACEMETHODIMP GetLocaleName (uint32_t textPosition, uint32_t* textLength,
|
||||
wchar_t const** localeName)
|
||||
{ return S_OK; }
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetNumberSubstitution (uint32_t textPosition,
|
||||
OUT uint32_t* textLength,
|
||||
OUT IDWriteNumberSubstitution** numberSubstitution)
|
||||
{
|
||||
// We do not support number substitution.
|
||||
*numberSubstitution = nullptr;
|
||||
*textLength = mTextLength - textPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// IDWriteTextAnalysisSink implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetScriptAnalysis (uint32_t textPosition, uint32_t textLength,
|
||||
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
|
||||
{
|
||||
SetCurrentRun (textPosition);
|
||||
SplitCurrentRun (textPosition);
|
||||
while (textLength > 0)
|
||||
{
|
||||
Run *run = FetchNextRun (&textLength);
|
||||
run->mScript = *scriptAnalysis;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetLineBreakpoints (uint32_t textPosition,
|
||||
uint32_t textLength,
|
||||
const DWRITE_LINE_BREAKPOINT* lineBreakpoints)
|
||||
{ return S_OK; }
|
||||
|
||||
IFACEMETHODIMP SetBidiLevel (uint32_t textPosition, uint32_t textLength,
|
||||
uint8_t explicitLevel, uint8_t resolvedLevel)
|
||||
{ return S_OK; }
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetNumberSubstitution (uint32_t textPosition, uint32_t textLength,
|
||||
IDWriteNumberSubstitution* numberSubstitution)
|
||||
{ return S_OK; }
|
||||
|
||||
protected:
|
||||
Run *FetchNextRun (IN OUT uint32_t* textLength)
|
||||
{
|
||||
// Used by the sink setters, this returns a reference to the next run.
|
||||
// Position and length are adjusted to now point after the current run
|
||||
// being returned.
|
||||
|
||||
Run *origRun = mCurrentRun;
|
||||
// Split the tail if needed (the length remaining is less than the
|
||||
// current run's size).
|
||||
if (*textLength < mCurrentRun->mTextLength)
|
||||
SplitCurrentRun (mCurrentRun->mTextStart + *textLength);
|
||||
else
|
||||
// Just advance the current run.
|
||||
mCurrentRun = mCurrentRun->nextRun;
|
||||
*textLength -= origRun->mTextLength;
|
||||
|
||||
// Return a reference to the run that was just current.
|
||||
return origRun;
|
||||
}
|
||||
|
||||
void SetCurrentRun (uint32_t textPosition)
|
||||
{
|
||||
// Move the current run to the given position.
|
||||
// Since the analyzers generally return results in a forward manner,
|
||||
// this will usually just return early. If not, find the
|
||||
// corresponding run for the text position.
|
||||
|
||||
if (mCurrentRun && mCurrentRun->ContainsTextPosition (textPosition))
|
||||
return;
|
||||
|
||||
for (Run *run = &mRunHead; run; run = run->nextRun)
|
||||
if (run->ContainsTextPosition (textPosition))
|
||||
{
|
||||
mCurrentRun = run;
|
||||
return;
|
||||
}
|
||||
assert (0); // We should always be able to find the text position in one of our runs
|
||||
}
|
||||
|
||||
void SplitCurrentRun (uint32_t splitPosition)
|
||||
{
|
||||
if (!mCurrentRun)
|
||||
{
|
||||
assert (0); // SplitCurrentRun called without current run
|
||||
// Shouldn't be calling this when no current run is set!
|
||||
return;
|
||||
}
|
||||
// Split the current run.
|
||||
if (splitPosition <= mCurrentRun->mTextStart)
|
||||
{
|
||||
// No need to split, already the start of a run
|
||||
// or before it. Usually the first.
|
||||
return;
|
||||
}
|
||||
Run *newRun = new Run;
|
||||
|
||||
*newRun = *mCurrentRun;
|
||||
|
||||
// Insert the new run in our linked list.
|
||||
newRun->nextRun = mCurrentRun->nextRun;
|
||||
mCurrentRun->nextRun = newRun;
|
||||
|
||||
// Adjust runs' text positions and lengths.
|
||||
uint32_t splitPoint = splitPosition - mCurrentRun->mTextStart;
|
||||
newRun->mTextStart += splitPoint;
|
||||
newRun->mTextLength -= splitPoint;
|
||||
mCurrentRun->mTextLength = splitPoint;
|
||||
mCurrentRun = newRun;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Input
|
||||
// (weak references are fine here, since this class is a transient
|
||||
// stack-based helper that doesn't need to copy data)
|
||||
uint32_t mTextLength;
|
||||
const wchar_t* mText;
|
||||
const wchar_t* mLocaleName;
|
||||
DWRITE_READING_DIRECTION mReadingDirection;
|
||||
|
||||
// Current processing state.
|
||||
Run *mCurrentRun;
|
||||
|
||||
// Output is a list of runs starting here
|
||||
Run mRunHead;
|
||||
};
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
||||
static hb_bool_t
|
||||
_hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features,
|
||||
float lineWidth)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
const hb_directwrite_face_data_t *face_data = face->data.directwrite;
|
||||
IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
|
||||
IDWriteFontFace *fontFace = face_data->fontFace;
|
||||
|
||||
IDWriteTextAnalyzer* analyzer;
|
||||
dwriteFactory->CreateTextAnalyzer (&analyzer);
|
||||
|
||||
unsigned int scratch_size;
|
||||
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
#define ALLOCATE_ARRAY(Type, name, len) \
|
||||
Type *name = (Type *) scratch; \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
assert (_consumed <= scratch_size); \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
} while (0)
|
||||
|
||||
#define utf16_index() var1.u32
|
||||
|
||||
ALLOCATE_ARRAY (wchar_t, textString, buffer->len * 2);
|
||||
|
||||
unsigned int chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
buffer->info[i].utf16_index () = chars_len;
|
||||
if (likely (c <= 0xFFFFu))
|
||||
textString[chars_len++] = c;
|
||||
else if (unlikely (c > 0x10FFFFu))
|
||||
textString[chars_len++] = 0xFFFDu;
|
||||
else
|
||||
{
|
||||
textString[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
|
||||
textString[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
|
||||
/* Need log_clusters to assign features. */
|
||||
chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
unsigned int cluster = buffer->info[i].cluster;
|
||||
log_clusters[chars_len++] = cluster;
|
||||
if (hb_in_range (c, 0x10000u, 0x10FFFFu))
|
||||
log_clusters[chars_len++] = cluster; /* Surrogates. */
|
||||
}
|
||||
|
||||
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
|
||||
|
||||
DWRITE_READING_DIRECTION readingDirection;
|
||||
readingDirection = buffer->props.direction ?
|
||||
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
|
||||
DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
||||
|
||||
/*
|
||||
* There's an internal 16-bit limit on some things inside the analyzer,
|
||||
* but we never attempt to shape a word longer than 64K characters
|
||||
* in a single gfxShapedWord, so we cannot exceed that limit.
|
||||
*/
|
||||
uint32_t textLength = buffer->len;
|
||||
|
||||
TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
|
||||
TextAnalysis::Run *runHead;
|
||||
HRESULT hr;
|
||||
hr = analysis.GenerateResults (analyzer, &runHead);
|
||||
|
||||
#define FAIL(...) \
|
||||
HB_STMT_START { \
|
||||
DEBUG_MSG (DIRECTWRITE, nullptr, __VA_ARGS__); \
|
||||
return false; \
|
||||
} HB_STMT_END
|
||||
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to generate results.");
|
||||
|
||||
uint32_t maxGlyphCount = 3 * textLength / 2 + 16;
|
||||
uint32_t glyphCount;
|
||||
bool isRightToLeft = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
|
||||
const wchar_t localeName[20] = {0};
|
||||
if (buffer->props.language != nullptr)
|
||||
mbstowcs ((wchar_t*) localeName,
|
||||
hb_language_to_string (buffer->props.language), 20);
|
||||
|
||||
// TODO: it does work but doesn't care about ranges
|
||||
DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
|
||||
typographic_features.featureCount = num_features;
|
||||
if (num_features)
|
||||
{
|
||||
typographic_features.features = new DWRITE_FONT_FEATURE[num_features];
|
||||
for (unsigned int i = 0; i < num_features; ++i)
|
||||
{
|
||||
typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
|
||||
hb_uint32_swap (features[i].tag);
|
||||
typographic_features.features[i].parameter = features[i].value;
|
||||
}
|
||||
}
|
||||
const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures;
|
||||
dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
|
||||
const uint32_t featureRangeLengths[] = { textLength };
|
||||
//
|
||||
|
||||
uint16_t* clusterMap;
|
||||
clusterMap = new uint16_t[textLength];
|
||||
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
|
||||
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
|
||||
retry_getglyphs:
|
||||
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
|
||||
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
|
||||
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
|
||||
|
||||
hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
|
||||
isRightToLeft, &runHead->mScript, localeName,
|
||||
nullptr, &dwFeatures, featureRangeLengths, 1,
|
||||
maxGlyphCount, clusterMap, textProperties,
|
||||
glyphIndices, glyphProperties, &glyphCount);
|
||||
|
||||
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
|
||||
{
|
||||
delete [] glyphIndices;
|
||||
delete [] glyphProperties;
|
||||
|
||||
maxGlyphCount *= 2;
|
||||
|
||||
goto retry_getglyphs;
|
||||
}
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to get glyphs.");
|
||||
|
||||
float* glyphAdvances = new float[maxGlyphCount];
|
||||
DWRITE_GLYPH_OFFSET* glyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
|
||||
|
||||
/* The -2 in the following is to compensate for possible
|
||||
* alignment needed after the WORD array. sizeof (WORD) == 2. */
|
||||
unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
|
||||
/ (sizeof (WORD) +
|
||||
sizeof (DWRITE_SHAPING_GLYPH_PROPERTIES) +
|
||||
sizeof (int) +
|
||||
sizeof (DWRITE_GLYPH_OFFSET) +
|
||||
sizeof (uint32_t));
|
||||
ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
|
||||
|
||||
#undef ALLOCATE_ARRAY
|
||||
|
||||
int fontEmSize = font->face->get_upem ();
|
||||
if (fontEmSize < 0) fontEmSize = -fontEmSize;
|
||||
|
||||
if (fontEmSize < 0) fontEmSize = -fontEmSize;
|
||||
double x_mult = (double) font->x_scale / fontEmSize;
|
||||
double y_mult = (double) font->y_scale / fontEmSize;
|
||||
|
||||
hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties,
|
||||
textLength, glyphIndices, glyphProperties,
|
||||
glyphCount, fontFace, fontEmSize,
|
||||
false, isRightToLeft, &runHead->mScript, localeName,
|
||||
&dwFeatures, featureRangeLengths, 1,
|
||||
glyphAdvances, glyphOffsets);
|
||||
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to get glyph placements.");
|
||||
|
||||
IDWriteTextAnalyzer1* analyzer1;
|
||||
analyzer->QueryInterface (&analyzer1);
|
||||
|
||||
if (analyzer1 && lineWidth)
|
||||
{
|
||||
DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
|
||||
new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount];
|
||||
hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, runHead->mScript,
|
||||
textLength, glyphCount, textString,
|
||||
clusterMap, glyphProperties,
|
||||
justificationOpportunities);
|
||||
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to get justification opportunities.");
|
||||
|
||||
float* justifiedGlyphAdvances = new float[maxGlyphCount];
|
||||
DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount];
|
||||
hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
|
||||
glyphAdvances, glyphOffsets, justifiedGlyphAdvances,
|
||||
justifiedGlyphOffsets);
|
||||
|
||||
if (FAILED (hr)) FAIL ("Analyzer failed to get justify glyph advances.");
|
||||
|
||||
DWRITE_SCRIPT_PROPERTIES scriptProperties;
|
||||
hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
|
||||
if (FAILED (hr)) FAIL ("Analyzer failed to get script properties.");
|
||||
uint32_t justificationCharacter = scriptProperties.justificationCharacter;
|
||||
|
||||
// if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
|
||||
if (justificationCharacter != 32)
|
||||
{
|
||||
uint16_t* modifiedClusterMap = new uint16_t[textLength];
|
||||
retry_getjustifiedglyphs:
|
||||
uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount];
|
||||
float* modifiedGlyphAdvances = new float[maxGlyphCount];
|
||||
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
|
||||
uint32_t actualGlyphsCount;
|
||||
hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
|
||||
textLength, glyphCount, maxGlyphCount,
|
||||
clusterMap, glyphIndices, glyphAdvances,
|
||||
justifiedGlyphAdvances, justifiedGlyphOffsets,
|
||||
glyphProperties, &actualGlyphsCount,
|
||||
modifiedClusterMap, modifiedGlyphIndices,
|
||||
modifiedGlyphAdvances, modifiedGlyphOffsets);
|
||||
|
||||
if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
|
||||
{
|
||||
maxGlyphCount = actualGlyphsCount;
|
||||
delete [] modifiedGlyphIndices;
|
||||
delete [] modifiedGlyphAdvances;
|
||||
delete [] modifiedGlyphOffsets;
|
||||
|
||||
maxGlyphCount = actualGlyphsCount;
|
||||
|
||||
goto retry_getjustifiedglyphs;
|
||||
}
|
||||
if (FAILED (hr))
|
||||
FAIL ("Analyzer failed to get justified glyphs.");
|
||||
|
||||
delete [] clusterMap;
|
||||
delete [] glyphIndices;
|
||||
delete [] glyphAdvances;
|
||||
delete [] glyphOffsets;
|
||||
|
||||
glyphCount = actualGlyphsCount;
|
||||
clusterMap = modifiedClusterMap;
|
||||
glyphIndices = modifiedGlyphIndices;
|
||||
glyphAdvances = modifiedGlyphAdvances;
|
||||
glyphOffsets = modifiedGlyphOffsets;
|
||||
|
||||
delete [] justifiedGlyphAdvances;
|
||||
delete [] justifiedGlyphOffsets;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete [] glyphAdvances;
|
||||
delete [] glyphOffsets;
|
||||
|
||||
glyphAdvances = justifiedGlyphAdvances;
|
||||
glyphOffsets = justifiedGlyphOffsets;
|
||||
}
|
||||
|
||||
delete [] justificationOpportunities;
|
||||
}
|
||||
|
||||
/* Ok, we've got everything we need, now compose output buffer,
|
||||
* very, *very*, carefully! */
|
||||
|
||||
/* Calculate visual-clusters. That's what we ship. */
|
||||
for (unsigned int i = 0; i < glyphCount; i++)
|
||||
vis_clusters[i] = (uint32_t) -1;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
uint32_t *p =
|
||||
&vis_clusters[log_clusters[buffer->info[i].utf16_index ()]];
|
||||
*p = hb_min (*p, buffer->info[i].cluster);
|
||||
}
|
||||
for (unsigned int i = 1; i < glyphCount; i++)
|
||||
if (vis_clusters[i] == (uint32_t) -1)
|
||||
vis_clusters[i] = vis_clusters[i - 1];
|
||||
|
||||
#undef utf16_index
|
||||
|
||||
if (unlikely (!buffer->ensure (glyphCount)))
|
||||
FAIL ("Buffer in error");
|
||||
|
||||
#undef FAIL
|
||||
|
||||
/* Set glyph infos */
|
||||
buffer->len = 0;
|
||||
for (unsigned int i = 0; i < glyphCount; i++)
|
||||
{
|
||||
hb_glyph_info_t *info = &buffer->info[buffer->len++];
|
||||
|
||||
info->codepoint = glyphIndices[i];
|
||||
info->cluster = vis_clusters[i];
|
||||
|
||||
/* The rest is crap. Let's store position info there for now. */
|
||||
info->mask = glyphAdvances[i];
|
||||
info->var1.i32 = glyphOffsets[i].advanceOffset;
|
||||
info->var2.i32 = glyphOffsets[i].ascenderOffset;
|
||||
}
|
||||
|
||||
/* Set glyph positions */
|
||||
buffer->clear_positions ();
|
||||
for (unsigned int i = 0; i < glyphCount; i++)
|
||||
{
|
||||
hb_glyph_info_t *info = &buffer->info[i];
|
||||
hb_glyph_position_t *pos = &buffer->pos[i];
|
||||
|
||||
/* TODO vertical */
|
||||
pos->x_advance = x_mult * (int32_t) info->mask;
|
||||
pos->x_offset = x_mult * (isRightToLeft ? -info->var1.i32 : info->var1.i32);
|
||||
pos->y_offset = y_mult * info->var2.i32;
|
||||
}
|
||||
|
||||
if (isRightToLeft) hb_buffer_reverse (buffer);
|
||||
|
||||
delete [] clusterMap;
|
||||
delete [] glyphIndices;
|
||||
delete [] textProperties;
|
||||
delete [] glyphProperties;
|
||||
delete [] glyphAdvances;
|
||||
delete [] glyphOffsets;
|
||||
|
||||
if (num_features)
|
||||
delete [] typographic_features.features;
|
||||
|
||||
/* Wow, done! */
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_bool_t
|
||||
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
return _hb_directwrite_shape_full (shape_plan, font, buffer,
|
||||
features, num_features, 0);
|
||||
}
|
||||
|
||||
HB_UNUSED static bool
|
||||
_hb_directwrite_shape_experimental_width (hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features,
|
||||
float width)
|
||||
{
|
||||
static const char *shapers = "directwrite";
|
||||
hb_shape_plan_t *shape_plan;
|
||||
shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
|
||||
features, num_features, &shapers);
|
||||
hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
|
||||
features, num_features, width);
|
||||
|
||||
buffer->unsafe_to_break_all ();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct _hb_directwrite_font_table_context {
|
||||
IDWriteFontFace *face;
|
||||
void *table_context;
|
||||
};
|
||||
|
||||
static void
|
||||
_hb_directwrite_table_data_release (void *data)
|
||||
{
|
||||
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
|
||||
context->face->ReleaseFontTable (context->table_context);
|
||||
delete context;
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
IDWriteFontFace *dw_face = ((IDWriteFontFace *) user_data);
|
||||
const void *data;
|
||||
uint32_t length;
|
||||
void *table_context;
|
||||
BOOL exists;
|
||||
if (!dw_face || FAILED (dw_face->TryGetFontTable (hb_uint32_swap (tag), &data,
|
||||
&length, &table_context, &exists)))
|
||||
return nullptr;
|
||||
|
||||
if (!data || !exists || !length)
|
||||
{
|
||||
dw_face->ReleaseFontTable (table_context);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
|
||||
context->face = dw_face;
|
||||
context->table_context = table_context;
|
||||
|
||||
return hb_blob_create ((const char *) data, length, HB_MEMORY_MODE_READONLY,
|
||||
context, _hb_directwrite_table_data_release);
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_directwrite_font_release (void *data)
|
||||
{
|
||||
if (data)
|
||||
((IDWriteFontFace *) data)->Release ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_directwrite_face_create:
|
||||
* @font_face: a DirectWrite IDWriteFontFace object.
|
||||
*
|
||||
* Return value: #hb_face_t object corresponding to the given input
|
||||
*
|
||||
* Since: 2.4.0
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_directwrite_face_create (IDWriteFontFace *font_face)
|
||||
{
|
||||
if (font_face)
|
||||
font_face->AddRef ();
|
||||
return hb_face_create_for_tables (_hb_directwrite_reference_table, font_face,
|
||||
_hb_directwrite_font_release);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_directwrite_face_get_font_face:
|
||||
* @face: a #hb_face_t object
|
||||
*
|
||||
* Return value: DirectWrite IDWriteFontFace object corresponding to the given input
|
||||
*
|
||||
* Since: 2.5.0
|
||||
**/
|
||||
IDWriteFontFace *
|
||||
hb_directwrite_face_get_font_face (hb_face_t *face)
|
||||
{
|
||||
return face->data.directwrite->fontFace;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright © 2015-2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_DIRECTWRITE_H
|
||||
#define HB_DIRECTWRITE_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_directwrite_face_create (IDWriteFontFace *font_face);
|
||||
|
||||
HB_EXTERN IDWriteFontFace *
|
||||
hb_directwrite_face_get_font_face (hb_face_t *face);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_DIRECTWRITE_H */
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
||||
* Copyright © 2012,2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_DISPATCH_HH
|
||||
#define HB_DISPATCH_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
/*
|
||||
* Dispatch
|
||||
*/
|
||||
|
||||
template <typename Context, typename Return, unsigned int MaxDebugDepth>
|
||||
struct hb_dispatch_context_t
|
||||
{
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
const Context* thiz () const { return static_cast<const Context *> (this); }
|
||||
Context* thiz () { return static_cast< Context *> (this); }
|
||||
public:
|
||||
static constexpr unsigned max_debug_depth = MaxDebugDepth;
|
||||
typedef Return return_t;
|
||||
template <typename T, typename F>
|
||||
bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
|
||||
template <typename T, typename ...Ts>
|
||||
return_t dispatch (const T &obj, Ts&&... ds)
|
||||
{ return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
|
||||
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
|
||||
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_DISPATCH_HH */
|
||||
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2017 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_DSALGS_HH
|
||||
#define HB_DSALGS_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#if defined(__ghs)
|
||||
// GHS compiler doesn't support the __restrict keyword
|
||||
#define __restrict
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static inline void *
|
||||
hb_bsearch_r (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
int (*compar)(const void *_key, const void *_item, void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p, arg);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
return (void *) p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* From https://github.com/noporpoise/sort_r */
|
||||
|
||||
/* Isaac Turner 29 April 2014 Public Domain */
|
||||
|
||||
/*
|
||||
|
||||
hb_sort_r function to be exported.
|
||||
|
||||
Parameters:
|
||||
base is the array to be sorted
|
||||
nel is the number of elements in the array
|
||||
width is the size in bytes of each element of the array
|
||||
compar is the comparison function
|
||||
arg is a pointer to be passed to the comparison function
|
||||
|
||||
void hb_sort_r(void *base, size_t nel, size_t width,
|
||||
int (*compar)(const void *_a, const void *_b, void *_arg),
|
||||
void *arg);
|
||||
*/
|
||||
|
||||
|
||||
/* swap a, b iff a>b */
|
||||
/* __restrict is same as restrict but better support on old machines */
|
||||
static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
|
||||
int (*compar)(const void *_a, const void *_b,
|
||||
void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
char tmp, *end = a+w;
|
||||
if(compar(a, b, arg) > 0) {
|
||||
for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note: quicksort is not stable, equivalent values may be swapped */
|
||||
static inline void sort_r_simple(void *base, size_t nel, size_t w,
|
||||
int (*compar)(const void *_a, const void *_b,
|
||||
void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
char *b = (char *)base, *end = b + nel*w;
|
||||
if(nel < 7) {
|
||||
/* Insertion sort for arbitrarily small inputs */
|
||||
char *pi, *pj;
|
||||
for(pi = b+w; pi < end; pi += w) {
|
||||
for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nel > 6; Quicksort */
|
||||
|
||||
/* Use median of first, middle and last items as pivot */
|
||||
char *x, *y, *xend, ch;
|
||||
char *pl, *pr;
|
||||
char *last = b+w*(nel-1), *tmp;
|
||||
char *l[3];
|
||||
l[0] = b;
|
||||
l[1] = b+w*(nel/2);
|
||||
l[2] = last;
|
||||
|
||||
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
|
||||
if(compar(l[1],l[2],arg) > 0) {
|
||||
tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
|
||||
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
|
||||
}
|
||||
|
||||
/* swap l[id], l[2] to put pivot as last element */
|
||||
for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
|
||||
ch = *x; *x = *y; *y = ch;
|
||||
}
|
||||
|
||||
pl = b;
|
||||
pr = last;
|
||||
|
||||
while(pl < pr) {
|
||||
for(; pl < pr; pl += w) {
|
||||
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
|
||||
pr -= w; /* pivot now at pl */
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(; pl < pr; pr -= w) {
|
||||
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
|
||||
pl += w; /* pivot now at pr */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort_r_simple(b, (pl-b)/w, w, compar, arg);
|
||||
sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hb_sort_r(void *base, size_t nel, size_t width,
|
||||
int (*compar)(const void *_a, const void *_b, void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
sort_r_simple(base, nel, width, compar, arg);
|
||||
}
|
||||
|
||||
#endif /* HB_DSALGS_HH */
|
||||
|
|
@ -26,48 +26,81 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-face-private.hh"
|
||||
#include "hb-open-file-private.hh"
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-maxp-table.hh"
|
||||
#include "hb-face.hh"
|
||||
#include "hb-blob.hh"
|
||||
#include "hb-open-file.hh"
|
||||
#include "hb-ot-face.hh"
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-face
|
||||
* @title: hb-face
|
||||
* @short_description: Font face objects
|
||||
* @include: hb.h
|
||||
*
|
||||
* Font face is objects represent a single face in a font family.
|
||||
* More exactly, a font face represents a single face in a binary font file.
|
||||
* Font faces are typically built from a binary blob and a face index.
|
||||
* Font faces are used to create fonts.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_count:
|
||||
* @blob: a blob.
|
||||
*
|
||||
* Get number of faces in a blob.
|
||||
*
|
||||
* Return value: Number of faces in @blob
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_count (hb_blob_t *blob)
|
||||
{
|
||||
if (unlikely (!blob))
|
||||
return 0;
|
||||
|
||||
/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
|
||||
/* Make API signature const after. */
|
||||
hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
|
||||
const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
|
||||
unsigned int ret = ot.get_face_count ();
|
||||
hb_blob_destroy (sanitized);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* hb_face_t
|
||||
*/
|
||||
|
||||
const hb_face_t _hb_face_nil = {
|
||||
DEFINE_NULL_INSTANCE (hb_face_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
||||
nullptr, /* reference_table_func */
|
||||
nullptr, /* user_data */
|
||||
nullptr, /* destroy */
|
||||
|
||||
0, /* index */
|
||||
1000, /* upem */
|
||||
0, /* num_glyphs */
|
||||
HB_ATOMIC_INT_INIT (1000), /* upem */
|
||||
HB_ATOMIC_INT_INIT (0), /* num_glyphs */
|
||||
|
||||
{
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
},
|
||||
|
||||
nullptr, /* shape_plans */
|
||||
/* Zero for the rest is fine. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_create_for_tables:
|
||||
* @reference_table_func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full)
|
||||
*
|
||||
|
|
@ -90,8 +123,10 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func,
|
|||
face->user_data = user_data;
|
||||
face->destroy = destroy;
|
||||
|
||||
face->upem = 0;
|
||||
face->num_glyphs = (unsigned int) -1;
|
||||
face->num_glyphs.set_relaxed (-1);
|
||||
|
||||
face->data.init0 (face);
|
||||
face->table.init0 (face);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
|
@ -134,22 +169,23 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
|
|||
if (tag == HB_TAG_NONE)
|
||||
return hb_blob_reference (data->blob);
|
||||
|
||||
const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
|
||||
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
|
||||
const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
|
||||
unsigned int base_offset;
|
||||
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index, &base_offset);
|
||||
|
||||
const OT::OpenTypeTable &table = ot_face.get_table_by_tag (tag);
|
||||
|
||||
hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, table.offset, table.length);
|
||||
hb_blob_t *blob = hb_blob_create_sub_blob (data->blob, base_offset + table.offset, table.length);
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_create: (Xconstructor)
|
||||
* @blob:
|
||||
* @index:
|
||||
* @blob:
|
||||
* @index:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
|
|
@ -164,7 +200,7 @@ hb_face_create (hb_blob_t *blob,
|
|||
if (unlikely (!blob))
|
||||
blob = hb_blob_get_empty ();
|
||||
|
||||
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (hb_blob_reference (blob)), index);
|
||||
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index);
|
||||
|
||||
if (unlikely (!closure))
|
||||
return hb_face_get_empty ();
|
||||
|
|
@ -181,16 +217,16 @@ hb_face_create (hb_blob_t *blob,
|
|||
/**
|
||||
* hb_face_get_empty:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full)
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_face_get_empty (void)
|
||||
hb_face_get_empty ()
|
||||
{
|
||||
return const_cast<hb_face_t *> (&_hb_face_nil);
|
||||
return const_cast<hb_face_t *> (&Null(hb_face_t));
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -198,9 +234,9 @@ hb_face_get_empty (void)
|
|||
* hb_face_reference: (skip)
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -214,7 +250,7 @@ hb_face_reference (hb_face_t *face)
|
|||
* hb_face_destroy: (skip)
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -231,9 +267,8 @@ hb_face_destroy (hb_face_t *face)
|
|||
node = next;
|
||||
}
|
||||
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_DESTROY(shaper, face);
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
face->data.fini ();
|
||||
face->table.fini ();
|
||||
|
||||
if (face->destroy)
|
||||
face->destroy (face->user_data);
|
||||
|
|
@ -244,14 +279,14 @@ hb_face_destroy (hb_face_t *face)
|
|||
/**
|
||||
* hb_face_set_user_data: (skip)
|
||||
* @face: a face.
|
||||
* @key:
|
||||
* @data:
|
||||
* @destroy:
|
||||
* @replace:
|
||||
* @key:
|
||||
* @data:
|
||||
* @destroy:
|
||||
* @replace:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -268,16 +303,16 @@ hb_face_set_user_data (hb_face_t *face,
|
|||
/**
|
||||
* hb_face_get_user_data: (skip)
|
||||
* @face: a face.
|
||||
* @key:
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
void *
|
||||
hb_face_get_user_data (hb_face_t *face,
|
||||
hb_face_get_user_data (const hb_face_t *face,
|
||||
hb_user_data_key_t *key)
|
||||
{
|
||||
return hb_object_get_user_data (face, key);
|
||||
|
|
@ -287,51 +322,54 @@ hb_face_get_user_data (hb_face_t *face,
|
|||
* hb_face_make_immutable:
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
void
|
||||
hb_face_make_immutable (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (hb_object_is_inert (face)))
|
||||
if (hb_object_is_immutable (face))
|
||||
return;
|
||||
|
||||
face->immutable = true;
|
||||
hb_object_make_immutable (face);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_is_immutable:
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_face_is_immutable (hb_face_t *face)
|
||||
hb_face_is_immutable (const hb_face_t *face)
|
||||
{
|
||||
return face->immutable;
|
||||
return hb_object_is_immutable (face);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_reference_table:
|
||||
* @face: a face.
|
||||
* @tag:
|
||||
* @tag:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_blob_t *
|
||||
hb_face_reference_table (hb_face_t *face,
|
||||
hb_tag_t tag)
|
||||
hb_face_reference_table (const hb_face_t *face,
|
||||
hb_tag_t tag)
|
||||
{
|
||||
if (unlikely (tag == HB_TAG_NONE))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
return face->reference_table (tag);
|
||||
}
|
||||
|
||||
|
|
@ -339,7 +377,7 @@ hb_face_reference_table (hb_face_t *face,
|
|||
* hb_face_reference_blob:
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
|
|
@ -354,9 +392,9 @@ hb_face_reference_blob (hb_face_t *face)
|
|||
/**
|
||||
* hb_face_set_index:
|
||||
* @face: a face.
|
||||
* @index:
|
||||
* @index:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -364,7 +402,7 @@ void
|
|||
hb_face_set_index (hb_face_t *face,
|
||||
unsigned int index)
|
||||
{
|
||||
if (face->immutable)
|
||||
if (hb_object_is_immutable (face))
|
||||
return;
|
||||
|
||||
face->index = index;
|
||||
|
|
@ -374,14 +412,14 @@ hb_face_set_index (hb_face_t *face,
|
|||
* hb_face_get_index:
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_index (hb_face_t *face)
|
||||
hb_face_get_index (const hb_face_t *face)
|
||||
{
|
||||
return face->index;
|
||||
}
|
||||
|
|
@ -389,9 +427,9 @@ hb_face_get_index (hb_face_t *face)
|
|||
/**
|
||||
* hb_face_set_upem:
|
||||
* @face: a face.
|
||||
* @upem:
|
||||
* @upem:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -399,43 +437,34 @@ void
|
|||
hb_face_set_upem (hb_face_t *face,
|
||||
unsigned int upem)
|
||||
{
|
||||
if (face->immutable)
|
||||
if (hb_object_is_immutable (face))
|
||||
return;
|
||||
|
||||
face->upem = upem;
|
||||
face->upem.set_relaxed (upem);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_get_upem:
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_upem (hb_face_t *face)
|
||||
hb_face_get_upem (const hb_face_t *face)
|
||||
{
|
||||
return face->get_upem ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_face_t::load_upem (void) const
|
||||
{
|
||||
hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (reference_table (HB_OT_TAG_head));
|
||||
const OT::head *head_table = OT::Sanitizer<OT::head>::lock_instance (head_blob);
|
||||
upem = head_table->get_upem ();
|
||||
hb_blob_destroy (head_blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_set_glyph_count:
|
||||
* @face: a face.
|
||||
* @glyph_count:
|
||||
* @glyph_count:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.7
|
||||
**/
|
||||
|
|
@ -443,40 +472,34 @@ void
|
|||
hb_face_set_glyph_count (hb_face_t *face,
|
||||
unsigned int glyph_count)
|
||||
{
|
||||
if (face->immutable)
|
||||
if (hb_object_is_immutable (face))
|
||||
return;
|
||||
|
||||
face->num_glyphs = glyph_count;
|
||||
face->num_glyphs.set_relaxed (glyph_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_get_glyph_count:
|
||||
* @face: a face.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.7
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_glyph_count (hb_face_t *face)
|
||||
hb_face_get_glyph_count (const hb_face_t *face)
|
||||
{
|
||||
return face->get_num_glyphs ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_face_t::load_num_glyphs (void) const
|
||||
{
|
||||
hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>::sanitize (reference_table (HB_OT_TAG_maxp));
|
||||
const OT::maxp *maxp_table = OT::Sanitizer<OT::maxp>::lock_instance (maxp_blob);
|
||||
num_glyphs = maxp_table->get_num_glyphs ();
|
||||
hb_blob_destroy (maxp_blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_get_table_tags:
|
||||
* @face: a face.
|
||||
* @start_offset: index of first tag to return.
|
||||
* @table_count: input length of @table_tags array, output number of items written.
|
||||
* @table_tags: array to write tags into.
|
||||
*
|
||||
* Retrieves table tags for a face, if possible.
|
||||
*
|
||||
|
|
@ -485,12 +508,12 @@ hb_face_t::load_num_glyphs (void) const
|
|||
* Since: 1.6.0
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_table_tags (hb_face_t *face,
|
||||
hb_face_get_table_tags (const hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */)
|
||||
{
|
||||
if (face->destroy != _hb_face_for_data_closure_destroy)
|
||||
if (face->destroy != (hb_destroy_func_t) _hb_face_for_data_closure_destroy)
|
||||
{
|
||||
if (table_count)
|
||||
*table_count = 0;
|
||||
|
|
@ -499,8 +522,204 @@ hb_face_get_table_tags (hb_face_t *face,
|
|||
|
||||
hb_face_for_data_closure_t *data = (hb_face_for_data_closure_t *) face->user_data;
|
||||
|
||||
const OT::OpenTypeFontFile &ot_file = *OT::Sanitizer<OT::OpenTypeFontFile>::lock_instance (data->blob);
|
||||
const OT::OpenTypeFontFile &ot_file = *data->blob->as<OT::OpenTypeFontFile> ();
|
||||
const OT::OpenTypeFontFace &ot_face = ot_file.get_face (data->index);
|
||||
|
||||
return ot_face.get_table_tags (start_offset, table_count, table_tags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Character set.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HB_NO_FACE_COLLECT_UNICODES
|
||||
/**
|
||||
* hb_face_collect_unicodes:
|
||||
* @face: font face.
|
||||
* @out: set to add Unicode characters covered by @face to.
|
||||
*
|
||||
* Since: 1.9.0
|
||||
*/
|
||||
void
|
||||
hb_face_collect_unicodes (hb_face_t *face,
|
||||
hb_set_t *out)
|
||||
{
|
||||
face->table.cmap->collect_unicodes (out);
|
||||
}
|
||||
/**
|
||||
* hb_face_collect_variation_selectors:
|
||||
* @face: font face.
|
||||
* @out: set to add Variation Selector characters covered by @face to.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.9.0
|
||||
*/
|
||||
void
|
||||
hb_face_collect_variation_selectors (hb_face_t *face,
|
||||
hb_set_t *out)
|
||||
{
|
||||
face->table.cmap->collect_variation_selectors (out);
|
||||
}
|
||||
/**
|
||||
* hb_face_collect_variation_unicodes:
|
||||
* @face: font face.
|
||||
* @out: set to add Unicode characters for @variation_selector covered by @face to.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.9.0
|
||||
*/
|
||||
void
|
||||
hb_face_collect_variation_unicodes (hb_face_t *face,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_set_t *out)
|
||||
{
|
||||
face->table.cmap->collect_variation_unicodes (variation_selector, out);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* face-builder: A face that has add_table().
|
||||
*/
|
||||
|
||||
struct hb_face_builder_data_t
|
||||
{
|
||||
struct table_entry_t
|
||||
{
|
||||
int cmp (hb_tag_t t) const
|
||||
{
|
||||
if (t < tag) return -1;
|
||||
if (t > tag) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
hb_tag_t tag;
|
||||
hb_blob_t *blob;
|
||||
};
|
||||
|
||||
hb_vector_t<table_entry_t> tables;
|
||||
};
|
||||
|
||||
static hb_face_builder_data_t *
|
||||
_hb_face_builder_data_create ()
|
||||
{
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
data->tables.init ();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_face_builder_data_destroy (void *user_data)
|
||||
{
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
||||
|
||||
for (unsigned int i = 0; i < data->tables.length; i++)
|
||||
hb_blob_destroy (data->tables[i].blob);
|
||||
|
||||
data->tables.fini ();
|
||||
|
||||
free (data);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
||||
{
|
||||
|
||||
unsigned int table_count = data->tables.length;
|
||||
unsigned int face_length = table_count * 16 + 12;
|
||||
|
||||
for (unsigned int i = 0; i < table_count; i++)
|
||||
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
|
||||
|
||||
char *buf = (char *) malloc (face_length);
|
||||
if (unlikely (!buf))
|
||||
return nullptr;
|
||||
|
||||
hb_serialize_context_t c (buf, face_length);
|
||||
c.propagate_error (data->tables);
|
||||
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
|
||||
|
||||
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
|
||||
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
|
||||
|
||||
bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
|
||||
|
||||
c.end_serialize ();
|
||||
|
||||
if (unlikely (!ret))
|
||||
{
|
||||
free (buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
||||
|
||||
if (!tag)
|
||||
return _hb_face_builder_data_reference_blob (data);
|
||||
|
||||
hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
|
||||
if (entry)
|
||||
return hb_blob_reference (entry->blob);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_face_builder_create:
|
||||
*
|
||||
* Creates a #hb_face_t that can be used with hb_face_builder_add_table().
|
||||
* After tables are added to the face, it can be compiled to a binary
|
||||
* font file by calling hb_face_reference_blob().
|
||||
*
|
||||
* Return value: (transfer full): New face.
|
||||
*
|
||||
* Since: 1.9.0
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_face_builder_create ()
|
||||
{
|
||||
hb_face_builder_data_t *data = _hb_face_builder_data_create ();
|
||||
if (unlikely (!data)) return hb_face_get_empty ();
|
||||
|
||||
return hb_face_create_for_tables (_hb_face_builder_reference_table,
|
||||
data,
|
||||
_hb_face_builder_data_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_builder_add_table:
|
||||
*
|
||||
* Add table for @tag with data provided by @blob to the face. @face must
|
||||
* be created using hb_face_builder_create().
|
||||
*
|
||||
* Since: 1.9.0
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
||||
{
|
||||
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
|
||||
return false;
|
||||
|
||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
|
||||
hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
|
||||
|
||||
entry->tag = tag;
|
||||
entry->blob = hb_blob_reference (blob);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,10 +33,15 @@
|
|||
|
||||
#include "hb-common.h"
|
||||
#include "hb-blob.h"
|
||||
#include "hb-set.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_count (hb_blob_t *blob);
|
||||
|
||||
|
||||
/*
|
||||
* hb_face_t
|
||||
*/
|
||||
|
|
@ -71,21 +76,20 @@ hb_face_set_user_data (hb_face_t *face,
|
|||
hb_destroy_func_t destroy,
|
||||
hb_bool_t replace);
|
||||
|
||||
|
||||
HB_EXTERN void *
|
||||
hb_face_get_user_data (hb_face_t *face,
|
||||
hb_face_get_user_data (const hb_face_t *face,
|
||||
hb_user_data_key_t *key);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_make_immutable (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_face_is_immutable (hb_face_t *face);
|
||||
hb_face_is_immutable (const hb_face_t *face);
|
||||
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_face_reference_table (hb_face_t *face,
|
||||
hb_tag_t tag);
|
||||
hb_face_reference_table (const hb_face_t *face,
|
||||
hb_tag_t tag);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_face_reference_blob (hb_face_t *face);
|
||||
|
|
@ -95,28 +99,60 @@ hb_face_set_index (hb_face_t *face,
|
|||
unsigned int index);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_index (hb_face_t *face);
|
||||
hb_face_get_index (const hb_face_t *face);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_set_upem (hb_face_t *face,
|
||||
unsigned int upem);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_upem (hb_face_t *face);
|
||||
hb_face_get_upem (const hb_face_t *face);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_set_glyph_count (hb_face_t *face,
|
||||
unsigned int glyph_count);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_glyph_count (hb_face_t *face);
|
||||
hb_face_get_glyph_count (const hb_face_t *face);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_table_tags (hb_face_t *face,
|
||||
hb_face_get_table_tags (const hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */);
|
||||
|
||||
|
||||
/*
|
||||
* Character set.
|
||||
*/
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_collect_unicodes (hb_face_t *face,
|
||||
hb_set_t *out);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_collect_variation_selectors (hb_face_t *face,
|
||||
hb_set_t *out);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_collect_variation_unicodes (hb_face_t *face,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_set_t *out);
|
||||
|
||||
|
||||
/*
|
||||
* Builder face.
|
||||
*/
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_face_builder_create (void);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_face_builder_add_table (hb_face_t *face,
|
||||
hb_tag_t tag,
|
||||
hb_blob_t *blob);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_FACE_H */
|
||||
|
|
|
|||
|
|
@ -26,47 +26,48 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_FACE_PRIVATE_HH
|
||||
#define HB_FACE_PRIVATE_HH
|
||||
#ifndef HB_FACE_HH
|
||||
#define HB_FACE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
#include "hb-shape-plan-private.hh"
|
||||
#include "hb-shaper.hh"
|
||||
#include "hb-shape-plan.hh"
|
||||
#include "hb-ot-face.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_face_t
|
||||
*/
|
||||
|
||||
struct hb_face_t {
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, face);
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
|
||||
hb_bool_t immutable;
|
||||
struct hb_face_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
|
||||
hb_reference_table_func_t reference_table_func;
|
||||
void *user_data;
|
||||
hb_destroy_func_t destroy;
|
||||
|
||||
unsigned int index; /* Face index in a collection, zero-based. */
|
||||
mutable unsigned int upem; /* Units-per-EM. */
|
||||
mutable unsigned int num_glyphs; /* Number of glyphs. */
|
||||
mutable hb_atomic_int_t upem; /* Units-per-EM. */
|
||||
mutable hb_atomic_int_t num_glyphs; /* Number of glyphs. */
|
||||
|
||||
struct hb_shaper_data_t shaper_data; /* Various shaper data. */
|
||||
|
||||
/* Various non-shaping data. */
|
||||
/* ... */
|
||||
hb_shaper_object_dataset_t<hb_face_t> data;/* Various shaper data. */
|
||||
hb_ot_face_t table; /* All the face's tables. */
|
||||
|
||||
/* Cache */
|
||||
struct plan_node_t {
|
||||
struct plan_node_t
|
||||
{
|
||||
hb_shape_plan_t *shape_plan;
|
||||
plan_node_t *next;
|
||||
} *shape_plans;
|
||||
};
|
||||
hb_atomic_ptr_t<plan_node_t> shape_plans;
|
||||
|
||||
|
||||
inline hb_blob_t *reference_table (hb_tag_t tag) const
|
||||
hb_blob_t *reference_table (hb_tag_t tag) const
|
||||
{
|
||||
hb_blob_t *blob;
|
||||
|
||||
|
|
@ -80,32 +81,29 @@ struct hb_face_t {
|
|||
return blob;
|
||||
}
|
||||
|
||||
inline HB_PURE_FUNC unsigned int get_upem (void) const
|
||||
HB_PURE_FUNC unsigned int get_upem () const
|
||||
{
|
||||
if (unlikely (!upem))
|
||||
load_upem ();
|
||||
return upem;
|
||||
unsigned int ret = upem.get_relaxed ();
|
||||
if (unlikely (!ret))
|
||||
{
|
||||
return load_upem ();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline unsigned int get_num_glyphs (void) const
|
||||
unsigned int get_num_glyphs () const
|
||||
{
|
||||
if (unlikely (num_glyphs == (unsigned int) -1))
|
||||
load_num_glyphs ();
|
||||
return num_glyphs;
|
||||
unsigned int ret = num_glyphs.get_relaxed ();
|
||||
if (unlikely (ret == (unsigned int) -1))
|
||||
return load_num_glyphs ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
HB_INTERNAL void load_upem (void) const;
|
||||
HB_INTERNAL void load_num_glyphs (void) const;
|
||||
HB_INTERNAL unsigned int load_upem () const;
|
||||
HB_INTERNAL unsigned int load_num_glyphs () const;
|
||||
};
|
||||
|
||||
extern HB_INTERNAL const hb_face_t _hb_face_nil;
|
||||
|
||||
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
|
||||
DECLARE_NULL_INSTANCE (hb_face_t);
|
||||
|
||||
|
||||
#endif /* HB_FACE_PRIVATE_HH */
|
||||
#endif /* HB_FACE_HH */
|
||||
|
|
@ -24,28 +24,24 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#define HB_SHAPER fallback
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
|
||||
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, face)
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font)
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#ifndef HB_NO_FALLBACK_SHAPE
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_fallback_shaper_face_data_t {};
|
||||
struct hb_fallback_face_data_t {};
|
||||
|
||||
hb_fallback_shaper_face_data_t *
|
||||
hb_fallback_face_data_t *
|
||||
_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
|
||||
{
|
||||
return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_fallback_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
|
||||
_hb_fallback_shaper_face_data_destroy (hb_fallback_face_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -54,38 +50,16 @@ _hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_U
|
|||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_fallback_shaper_font_data_t {};
|
||||
struct hb_fallback_font_data_t {};
|
||||
|
||||
hb_fallback_shaper_font_data_t *
|
||||
hb_fallback_font_data_t *
|
||||
_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_fallback_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_fallback_shaper_shape_plan_data_t {};
|
||||
|
||||
hb_fallback_shaper_shape_plan_data_t *
|
||||
_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_fallback_shaper_font_data_destroy (hb_fallback_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -147,3 +121,5 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -110,7 +110,7 @@ typedef struct hb_glyph_extents_t
|
|||
/* func types */
|
||||
|
||||
typedef hb_bool_t (*hb_font_get_font_extents_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_font_extents_t *metrics,
|
||||
hb_font_extents_t *extents,
|
||||
void *user_data);
|
||||
typedef hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t;
|
||||
typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t;
|
||||
|
|
@ -125,6 +125,14 @@ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *
|
|||
hb_codepoint_t *glyph,
|
||||
void *user_data);
|
||||
|
||||
typedef unsigned int (*hb_font_get_nominal_glyphs_func_t) (hb_font_t *font, void *font_data,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
void *user_data);
|
||||
|
||||
|
||||
typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
|
|
@ -132,6 +140,16 @@ typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void
|
|||
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
|
||||
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
|
||||
|
||||
typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride,
|
||||
void *user_data);
|
||||
typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t;
|
||||
typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
|
||||
|
||||
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y,
|
||||
|
|
@ -143,7 +161,6 @@ typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void
|
|||
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
void *user_data);
|
||||
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
|
||||
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
|
||||
|
||||
|
||||
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
|
||||
|
|
@ -207,7 +224,7 @@ hb_font_funcs_set_font_v_extents_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.2.3
|
||||
**/
|
||||
|
|
@ -216,6 +233,22 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
|
|||
hb_font_get_nominal_glyph_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_nominal_glyphs_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.0.0
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_nominal_glyphs_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_nominal_glyphs_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_variation_glyph_func:
|
||||
* @ffuncs: font functions.
|
||||
|
|
@ -223,7 +256,7 @@ hb_font_funcs_set_nominal_glyph_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.2.3
|
||||
**/
|
||||
|
|
@ -239,7 +272,7 @@ hb_font_funcs_set_variation_glyph_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -255,7 +288,7 @@ hb_font_funcs_set_glyph_h_advance_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -264,6 +297,38 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
|
|||
hb_font_get_glyph_v_advance_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_h_advances_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_h_advances_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_v_advances_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_v_advances_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_h_origin_func:
|
||||
* @ffuncs: font functions.
|
||||
|
|
@ -271,7 +336,7 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -287,7 +352,7 @@ hb_font_funcs_set_glyph_h_origin_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -303,7 +368,7 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -312,22 +377,6 @@ hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
|
|||
hb_font_get_glyph_h_kerning_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_v_kerning_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_v_kerning_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_extents_func:
|
||||
* @ffuncs: font functions.
|
||||
|
|
@ -335,7 +384,7 @@ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -351,7 +400,7 @@ hb_font_funcs_set_glyph_extents_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -367,7 +416,7 @@ hb_font_funcs_set_glyph_contour_point_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -383,7 +432,7 @@ hb_font_funcs_set_glyph_name_func (hb_font_funcs_t *ffuncs,
|
|||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
|
|
@ -410,6 +459,14 @@ hb_font_get_variation_glyph (hb_font_t *font,
|
|||
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_font_get_nominal_glyphs (hb_font_t *font,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride);
|
||||
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_h_advance (hb_font_t *font,
|
||||
hb_codepoint_t glyph);
|
||||
|
|
@ -417,6 +474,21 @@ HB_EXTERN hb_position_t
|
|||
hb_font_get_glyph_v_advance (hb_font_t *font,
|
||||
hb_codepoint_t glyph);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_h_advances (hb_font_t* font,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride);
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_v_advances (hb_font_t* font,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_get_glyph_h_origin (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
|
|
@ -429,9 +501,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
|
|||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_h_kerning (hb_font_t *font,
|
||||
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_v_kerning (hb_font_t *font,
|
||||
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_get_glyph_extents (hb_font_t *font,
|
||||
|
|
@ -456,7 +525,7 @@ hb_font_get_glyph_from_name (hb_font_t *font,
|
|||
/* high-level funcs, with fallback */
|
||||
|
||||
/* Calls either hb_font_get_nominal_glyph() if variation_selector is 0,
|
||||
* otherwise callse hb_font_get_variation_glyph(). */
|
||||
* otherwise calls hb_font_get_variation_glyph(). */
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_get_glyph (hb_font_t *font,
|
||||
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
|
||||
|
|
@ -472,6 +541,14 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
|
|||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y);
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_advances_for_direction (hb_font_t* font,
|
||||
hb_direction_t direction,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride);
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_origin_for_direction (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
|
|
@ -580,8 +657,8 @@ hb_font_set_funcs (hb_font_t *font,
|
|||
/* Be *very* careful with this function! */
|
||||
HB_EXTERN void
|
||||
hb_font_set_funcs_data (hb_font_t *font,
|
||||
void *font_data,
|
||||
hb_destroy_func_t destroy);
|
||||
void *font_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
|
||||
HB_EXTERN void
|
||||
|
|
@ -636,6 +713,10 @@ HB_EXTERN const int *
|
|||
hb_font_get_var_coords_normalized (hb_font_t *font,
|
||||
unsigned int *length);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_set_var_named_instance (hb_font_t *font,
|
||||
unsigned instance_index);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_FONT_H */
|
||||
|
|
|
|||
|
|
@ -26,15 +26,13 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_FONT_PRIVATE_HH
|
||||
#define HB_FONT_PRIVATE_HH
|
||||
#ifndef HB_FONT_HH
|
||||
#define HB_FONT_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-object-private.hh"
|
||||
#include "hb-face-private.hh"
|
||||
#include "hb-shaper-private.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-face.hh"
|
||||
#include "hb-shaper.hh"
|
||||
|
||||
|
||||
/*
|
||||
|
|
@ -45,24 +43,25 @@
|
|||
HB_FONT_FUNC_IMPLEMENT (font_h_extents) \
|
||||
HB_FONT_FUNC_IMPLEMENT (font_v_extents) \
|
||||
HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \
|
||||
HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \
|
||||
HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
|
||||
HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
|
||||
/* ^--- Add new callbacks here */
|
||||
|
||||
struct hb_font_funcs_t {
|
||||
struct hb_font_funcs_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
hb_bool_t immutable;
|
||||
|
||||
struct {
|
||||
#define HB_FONT_FUNC_IMPLEMENT(name) void *name;
|
||||
|
|
@ -83,27 +82,35 @@ struct hb_font_funcs_t {
|
|||
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
||||
#undef HB_FONT_FUNC_IMPLEMENT
|
||||
} f;
|
||||
void (*array[VAR]) (void);
|
||||
void (*array[0
|
||||
#define HB_FONT_FUNC_IMPLEMENT(name) +1
|
||||
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
||||
#undef HB_FONT_FUNC_IMPLEMENT
|
||||
]) ();
|
||||
} get;
|
||||
};
|
||||
|
||||
DECLARE_NULL_INSTANCE (hb_font_funcs_t);
|
||||
|
||||
|
||||
/*
|
||||
* hb_font_t
|
||||
*/
|
||||
|
||||
struct hb_font_t {
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INSTANTIATE_SHAPERS(shaper, font);
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
|
||||
hb_bool_t immutable;
|
||||
struct hb_font_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
|
||||
hb_font_t *parent;
|
||||
hb_face_t *face;
|
||||
|
||||
int x_scale;
|
||||
int y_scale;
|
||||
int32_t x_scale;
|
||||
int32_t y_scale;
|
||||
int64_t x_mult;
|
||||
int64_t y_mult;
|
||||
|
||||
unsigned int x_ppem;
|
||||
unsigned int y_ppem;
|
||||
|
|
@ -118,42 +125,46 @@ struct hb_font_t {
|
|||
void *user_data;
|
||||
hb_destroy_func_t destroy;
|
||||
|
||||
struct hb_shaper_data_t shaper_data;
|
||||
hb_shaper_object_dataset_t<hb_font_t> data; /* Various shaper data. */
|
||||
|
||||
|
||||
/* Convert from font-space to user-space */
|
||||
inline int dir_scale (hb_direction_t direction)
|
||||
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
|
||||
inline hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
|
||||
inline hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
|
||||
inline hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
|
||||
inline hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
|
||||
inline hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
|
||||
{ return em_scale (v, dir_scale (direction)); }
|
||||
int64_t dir_mult (hb_direction_t direction)
|
||||
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
|
||||
hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
|
||||
hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
|
||||
hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
|
||||
hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
|
||||
float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
|
||||
float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
|
||||
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
|
||||
{ return em_mult (v, dir_mult (direction)); }
|
||||
|
||||
/* Convert from parent-font user-space to our user-space */
|
||||
inline hb_position_t parent_scale_x_distance (hb_position_t v) {
|
||||
hb_position_t parent_scale_x_distance (hb_position_t v)
|
||||
{
|
||||
if (unlikely (parent && parent->x_scale != x_scale))
|
||||
return (hb_position_t) (v * (int64_t) this->x_scale / this->parent->x_scale);
|
||||
return v;
|
||||
}
|
||||
inline hb_position_t parent_scale_y_distance (hb_position_t v) {
|
||||
hb_position_t parent_scale_y_distance (hb_position_t v)
|
||||
{
|
||||
if (unlikely (parent && parent->y_scale != y_scale))
|
||||
return (hb_position_t) (v * (int64_t) this->y_scale / this->parent->y_scale);
|
||||
return v;
|
||||
}
|
||||
inline hb_position_t parent_scale_x_position (hb_position_t v) {
|
||||
return parent_scale_x_distance (v);
|
||||
}
|
||||
inline hb_position_t parent_scale_y_position (hb_position_t v) {
|
||||
return parent_scale_y_distance (v);
|
||||
}
|
||||
hb_position_t parent_scale_x_position (hb_position_t v)
|
||||
{ return parent_scale_x_distance (v); }
|
||||
hb_position_t parent_scale_y_position (hb_position_t v)
|
||||
{ return parent_scale_y_distance (v); }
|
||||
|
||||
inline void parent_scale_distance (hb_position_t *x, hb_position_t *y) {
|
||||
void parent_scale_distance (hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = parent_scale_x_distance (*x);
|
||||
*y = parent_scale_y_distance (*y);
|
||||
}
|
||||
inline void parent_scale_position (hb_position_t *x, hb_position_t *y) {
|
||||
void parent_scale_position (hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = parent_scale_x_position (*x);
|
||||
*y = parent_scale_y_position (*y);
|
||||
}
|
||||
|
|
@ -162,27 +173,35 @@ struct hb_font_t {
|
|||
/* Public getters */
|
||||
|
||||
HB_INTERNAL bool has_func (unsigned int i);
|
||||
HB_INTERNAL bool has_func_set (unsigned int i);
|
||||
|
||||
/* has_* ... */
|
||||
#define HB_FONT_FUNC_IMPLEMENT(name) \
|
||||
bool \
|
||||
has_##name##_func (void) \
|
||||
has_##name##_func () \
|
||||
{ \
|
||||
hb_font_funcs_t *funcs = this->klass; \
|
||||
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
|
||||
return has_func (i); \
|
||||
} \
|
||||
bool \
|
||||
has_##name##_func_set () \
|
||||
{ \
|
||||
hb_font_funcs_t *funcs = this->klass; \
|
||||
unsigned int i = offsetof (hb_font_funcs_t::get_t::get_funcs_t, name) / sizeof (funcs->get.array[0]); \
|
||||
return has_func_set (i); \
|
||||
}
|
||||
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
||||
#undef HB_FONT_FUNC_IMPLEMENT
|
||||
|
||||
inline hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
|
||||
hb_bool_t get_font_h_extents (hb_font_extents_t *extents)
|
||||
{
|
||||
memset (extents, 0, sizeof (*extents));
|
||||
return klass->get.f.font_h_extents (this, user_data,
|
||||
extents,
|
||||
klass->user_data.font_h_extents);
|
||||
}
|
||||
inline hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
|
||||
hb_bool_t get_font_v_extents (hb_font_extents_t *extents)
|
||||
{
|
||||
memset (extents, 0, sizeof (*extents));
|
||||
return klass->get.f.font_v_extents (this, user_data,
|
||||
|
|
@ -190,23 +209,35 @@ struct hb_font_t {
|
|||
klass->user_data.font_v_extents);
|
||||
}
|
||||
|
||||
inline bool has_glyph (hb_codepoint_t unicode)
|
||||
bool has_glyph (hb_codepoint_t unicode)
|
||||
{
|
||||
hb_codepoint_t glyph;
|
||||
return get_nominal_glyph (unicode, &glyph);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph)
|
||||
hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph)
|
||||
{
|
||||
*glyph = 0;
|
||||
return klass->get.f.nominal_glyph (this, user_data,
|
||||
unicode, glyph,
|
||||
klass->user_data.nominal_glyph);
|
||||
}
|
||||
unsigned int get_nominal_glyphs (unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride)
|
||||
{
|
||||
return klass->get.f.nominal_glyphs (this, user_data,
|
||||
count,
|
||||
first_unicode, unicode_stride,
|
||||
first_glyph, glyph_stride,
|
||||
klass->user_data.nominal_glyphs);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph)
|
||||
hb_bool_t get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph)
|
||||
{
|
||||
*glyph = 0;
|
||||
return klass->get.f.variation_glyph (this, user_data,
|
||||
|
|
@ -214,22 +245,48 @@ struct hb_font_t {
|
|||
klass->user_data.variation_glyph);
|
||||
}
|
||||
|
||||
inline hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
|
||||
hb_position_t get_glyph_h_advance (hb_codepoint_t glyph)
|
||||
{
|
||||
return klass->get.f.glyph_h_advance (this, user_data,
|
||||
glyph,
|
||||
klass->user_data.glyph_h_advance);
|
||||
}
|
||||
|
||||
inline hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
|
||||
hb_position_t get_glyph_v_advance (hb_codepoint_t glyph)
|
||||
{
|
||||
return klass->get.f.glyph_v_advance (this, user_data,
|
||||
glyph,
|
||||
klass->user_data.glyph_v_advance);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void get_glyph_h_advances (unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned int advance_stride)
|
||||
{
|
||||
return klass->get.f.glyph_h_advances (this, user_data,
|
||||
count,
|
||||
first_glyph, glyph_stride,
|
||||
first_advance, advance_stride,
|
||||
klass->user_data.glyph_h_advances);
|
||||
}
|
||||
|
||||
void get_glyph_v_advances (unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned int advance_stride)
|
||||
{
|
||||
return klass->get.f.glyph_v_advances (this, user_data,
|
||||
count,
|
||||
first_glyph, glyph_stride,
|
||||
first_advance, advance_stride,
|
||||
klass->user_data.glyph_v_advances);
|
||||
}
|
||||
|
||||
hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = *y = 0;
|
||||
return klass->get.f.glyph_h_origin (this, user_data,
|
||||
|
|
@ -237,8 +294,8 @@ struct hb_font_t {
|
|||
klass->user_data.glyph_h_origin);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
hb_bool_t get_glyph_v_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = *y = 0;
|
||||
return klass->get.f.glyph_v_origin (this, user_data,
|
||||
|
|
@ -246,22 +303,32 @@ struct hb_font_t {
|
|||
klass->user_data.glyph_v_origin);
|
||||
}
|
||||
|
||||
inline hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph)
|
||||
hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph)
|
||||
{
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
return 0;
|
||||
#else
|
||||
return klass->get.f.glyph_h_kerning (this, user_data,
|
||||
left_glyph, right_glyph,
|
||||
klass->user_data.glyph_h_kerning);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph)
|
||||
hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
|
||||
hb_codepoint_t bottom_glyph)
|
||||
{
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
return 0;
|
||||
#else
|
||||
return klass->get.f.glyph_v_kerning (this, user_data,
|
||||
top_glyph, bottom_glyph,
|
||||
klass->user_data.glyph_v_kerning);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents)
|
||||
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents)
|
||||
{
|
||||
memset (extents, 0, sizeof (*extents));
|
||||
return klass->get.f.glyph_extents (this, user_data,
|
||||
|
|
@ -270,7 +337,7 @@ struct hb_font_t {
|
|||
klass->user_data.glyph_extents);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
|
||||
hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = *y = 0;
|
||||
|
|
@ -280,8 +347,8 @@ struct hb_font_t {
|
|||
klass->user_data.glyph_contour_point);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_name (hb_codepoint_t glyph,
|
||||
char *name, unsigned int size)
|
||||
hb_bool_t get_glyph_name (hb_codepoint_t glyph,
|
||||
char *name, unsigned int size)
|
||||
{
|
||||
if (size) *name = '\0';
|
||||
return klass->get.f.glyph_name (this, user_data,
|
||||
|
|
@ -290,8 +357,8 @@ struct hb_font_t {
|
|||
klass->user_data.glyph_name);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph)
|
||||
hb_bool_t get_glyph_from_name (const char *name, int len, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph)
|
||||
{
|
||||
*glyph = 0;
|
||||
if (len == -1) len = strlen (name);
|
||||
|
|
@ -304,7 +371,7 @@ struct hb_font_t {
|
|||
|
||||
/* A bit higher-level, and with fallback */
|
||||
|
||||
inline void get_h_extents_with_fallback (hb_font_extents_t *extents)
|
||||
void get_h_extents_with_fallback (hb_font_extents_t *extents)
|
||||
{
|
||||
if (!get_font_h_extents (extents))
|
||||
{
|
||||
|
|
@ -313,7 +380,7 @@ struct hb_font_t {
|
|||
extents->line_gap = 0;
|
||||
}
|
||||
}
|
||||
inline void get_v_extents_with_fallback (hb_font_extents_t *extents)
|
||||
void get_v_extents_with_fallback (hb_font_extents_t *extents)
|
||||
{
|
||||
if (!get_font_v_extents (extents))
|
||||
{
|
||||
|
|
@ -323,8 +390,8 @@ struct hb_font_t {
|
|||
}
|
||||
}
|
||||
|
||||
inline void get_extents_for_direction (hb_direction_t direction,
|
||||
hb_font_extents_t *extents)
|
||||
void get_extents_for_direction (hb_direction_t direction,
|
||||
hb_font_extents_t *extents)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
|
||||
get_h_extents_with_fallback (extents);
|
||||
|
|
@ -332,21 +399,31 @@ struct hb_font_t {
|
|||
get_v_extents_with_fallback (extents);
|
||||
}
|
||||
|
||||
inline void get_glyph_advance_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void get_glyph_advance_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
|
||||
*x = *y = 0;
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
|
||||
*x = get_glyph_h_advance (glyph);
|
||||
*y = 0;
|
||||
} else {
|
||||
*x = 0;
|
||||
else
|
||||
*y = get_glyph_v_advance (glyph);
|
||||
}
|
||||
}
|
||||
void get_glyph_advances_for_direction (hb_direction_t direction,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
|
||||
get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
else
|
||||
get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
}
|
||||
|
||||
inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = get_glyph_h_advance (glyph) / 2;
|
||||
|
||||
|
|
@ -356,8 +433,8 @@ struct hb_font_t {
|
|||
*y = extents.ascender;
|
||||
}
|
||||
|
||||
inline void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void get_glyph_h_origin_with_fallback (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
if (!get_glyph_h_origin (glyph, x, y) &&
|
||||
get_glyph_v_origin (glyph, x, y))
|
||||
|
|
@ -367,8 +444,8 @@ struct hb_font_t {
|
|||
*x -= dx; *y -= dy;
|
||||
}
|
||||
}
|
||||
inline void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void get_glyph_v_origin_with_fallback (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
if (!get_glyph_v_origin (glyph, x, y) &&
|
||||
get_glyph_h_origin (glyph, x, y))
|
||||
|
|
@ -379,9 +456,9 @@ struct hb_font_t {
|
|||
}
|
||||
}
|
||||
|
||||
inline void get_glyph_origin_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void get_glyph_origin_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
|
||||
get_glyph_h_origin_with_fallback (glyph, x, y);
|
||||
|
|
@ -389,8 +466,8 @@ struct hb_font_t {
|
|||
get_glyph_v_origin_with_fallback (glyph, x, y);
|
||||
}
|
||||
|
||||
inline void add_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void add_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_position_t origin_x, origin_y;
|
||||
|
||||
|
|
@ -399,8 +476,8 @@ struct hb_font_t {
|
|||
*x += origin_x;
|
||||
*y += origin_y;
|
||||
}
|
||||
inline void add_glyph_v_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void add_glyph_v_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_position_t origin_x, origin_y;
|
||||
|
||||
|
|
@ -409,9 +486,9 @@ struct hb_font_t {
|
|||
*x += origin_x;
|
||||
*y += origin_y;
|
||||
}
|
||||
inline void add_glyph_origin_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void add_glyph_origin_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_position_t origin_x, origin_y;
|
||||
|
||||
|
|
@ -421,8 +498,8 @@ struct hb_font_t {
|
|||
*y += origin_y;
|
||||
}
|
||||
|
||||
inline void subtract_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void subtract_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_position_t origin_x, origin_y;
|
||||
|
||||
|
|
@ -431,8 +508,8 @@ struct hb_font_t {
|
|||
*x -= origin_x;
|
||||
*y -= origin_y;
|
||||
}
|
||||
inline void subtract_glyph_v_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void subtract_glyph_v_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_position_t origin_x, origin_y;
|
||||
|
||||
|
|
@ -441,9 +518,9 @@ struct hb_font_t {
|
|||
*x -= origin_x;
|
||||
*y -= origin_y;
|
||||
}
|
||||
inline void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void subtract_glyph_origin_for_direction (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_position_t origin_x, origin_y;
|
||||
|
||||
|
|
@ -453,22 +530,22 @@ struct hb_font_t {
|
|||
*y -= origin_y;
|
||||
}
|
||||
|
||||
inline void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
void get_glyph_kerning_for_direction (hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
|
||||
*x = get_glyph_h_kerning (first_glyph, second_glyph);
|
||||
*y = 0;
|
||||
*x = get_glyph_h_kerning (first_glyph, second_glyph);
|
||||
} else {
|
||||
*x = 0;
|
||||
*y = get_glyph_v_kerning (first_glyph, second_glyph);
|
||||
}
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_glyph_extents_t *extents)
|
||||
hb_bool_t get_glyph_extents_for_origin (hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
hb_glyph_extents_t *extents)
|
||||
{
|
||||
hb_bool_t ret = get_glyph_extents (glyph, extents);
|
||||
|
||||
|
|
@ -478,9 +555,9 @@ struct hb_font_t {
|
|||
return ret;
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
hb_bool_t get_glyph_contour_point_for_origin (hb_codepoint_t glyph, unsigned int point_index,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
hb_bool_t ret = get_glyph_contour_point (glyph, point_index, x, y);
|
||||
|
||||
|
|
@ -491,7 +568,7 @@ struct hb_font_t {
|
|||
}
|
||||
|
||||
/* Generates gidDDD if glyph has no name. */
|
||||
inline void
|
||||
void
|
||||
glyph_to_string (hb_codepoint_t glyph,
|
||||
char *s, unsigned int size)
|
||||
{
|
||||
|
|
@ -502,7 +579,7 @@ struct hb_font_t {
|
|||
}
|
||||
|
||||
/* Parses gidDDD and uniUUUU strings automatically. */
|
||||
inline hb_bool_t
|
||||
hb_bool_t
|
||||
glyph_from_string (const char *s, int len, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph)
|
||||
{
|
||||
|
|
@ -532,24 +609,23 @@ struct hb_font_t {
|
|||
return false;
|
||||
}
|
||||
|
||||
inline hb_position_t em_scale (int16_t v, int scale)
|
||||
void mults_changed ()
|
||||
{
|
||||
int upem = face->get_upem ();
|
||||
int64_t scaled = v * (int64_t) scale;
|
||||
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
|
||||
return (hb_position_t) (scaled / upem);
|
||||
signed upem = face->get_upem ();
|
||||
x_mult = ((int64_t) x_scale << 16) / upem;
|
||||
y_mult = ((int64_t) y_scale << 16) / upem;
|
||||
}
|
||||
inline hb_position_t em_scalef (float v, int scale)
|
||||
|
||||
hb_position_t em_mult (int16_t v, int64_t mult)
|
||||
{
|
||||
return (hb_position_t) (v * scale / face->get_upem ());
|
||||
return (hb_position_t) ((v * mult) >> 16);
|
||||
}
|
||||
hb_position_t em_scalef (float v, int scale)
|
||||
{ return (hb_position_t) roundf (v * scale / face->get_upem ()); }
|
||||
float em_fscale (int16_t v, int scale)
|
||||
{ return (float) v * scale / face->get_upem (); }
|
||||
};
|
||||
|
||||
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
#undef HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
|
||||
DECLARE_NULL_INSTANCE (hb_font_t);
|
||||
|
||||
|
||||
#endif /* HB_FONT_PRIVATE_HH */
|
||||
#endif /* HB_FONT_HH */
|
||||
|
|
@ -0,0 +1,884 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2009 Keith Stribley
|
||||
* Copyright © 2015 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
|
||||
#include "hb-ft.h"
|
||||
|
||||
#include "hb-font.hh"
|
||||
#include "hb-machinery.hh"
|
||||
#include "hb-cache.hh"
|
||||
|
||||
#include FT_ADVANCES_H
|
||||
#include FT_MULTIPLE_MASTERS_H
|
||||
#include FT_TRUETYPE_TABLES_H
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ft
|
||||
* @title: hb-ft
|
||||
* @short_description: FreeType integration
|
||||
* @include: hb-ft.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the FreeType library to provide face and
|
||||
* font data.
|
||||
**/
|
||||
|
||||
|
||||
/* TODO:
|
||||
*
|
||||
* In general, this file does a fine job of what it's supposed to do.
|
||||
* There are, however, things that need more work:
|
||||
*
|
||||
* - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
|
||||
* would work fine. However, we also abuse this API for performing in font-space,
|
||||
* but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
|
||||
* for that, such that no rounding etc happens. As such, we don't set ppem, and
|
||||
* pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
|
||||
* ourselves.
|
||||
*
|
||||
* - We don't handle / allow for emboldening / obliqueing.
|
||||
*
|
||||
* - In the future, we should add constructors to create fonts in font space?
|
||||
*/
|
||||
|
||||
|
||||
struct hb_ft_font_t
|
||||
{
|
||||
mutable hb_mutex_t lock;
|
||||
FT_Face ft_face;
|
||||
int load_flags;
|
||||
bool symbol; /* Whether selected cmap is symbol cmap. */
|
||||
bool unref; /* Whether to destroy ft_face when done. */
|
||||
|
||||
mutable hb_atomic_int_t cached_x_scale;
|
||||
mutable hb_advance_cache_t advance_cache;
|
||||
};
|
||||
|
||||
static hb_ft_font_t *
|
||||
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
|
||||
{
|
||||
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
|
||||
|
||||
if (unlikely (!ft_font))
|
||||
return nullptr;
|
||||
|
||||
ft_font->lock.init ();
|
||||
ft_font->ft_face = ft_face;
|
||||
ft_font->symbol = symbol;
|
||||
ft_font->unref = unref;
|
||||
|
||||
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
|
||||
|
||||
ft_font->cached_x_scale.set_relaxed (0);
|
||||
ft_font->advance_cache.init ();
|
||||
|
||||
return ft_font;
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ft_face_destroy (void *data)
|
||||
{
|
||||
FT_Done_Face ((FT_Face) data);
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ft_font_destroy (void *data)
|
||||
{
|
||||
hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
|
||||
|
||||
ft_font->advance_cache.fini ();
|
||||
|
||||
if (ft_font->unref)
|
||||
_hb_ft_face_destroy (ft_font->ft_face);
|
||||
|
||||
ft_font->lock.fini ();
|
||||
|
||||
free (ft_font);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_set_load_flags:
|
||||
* @font:
|
||||
* @load_flags:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.0.5
|
||||
**/
|
||||
void
|
||||
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
|
||||
{
|
||||
if (hb_object_is_immutable (font))
|
||||
return;
|
||||
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
return;
|
||||
|
||||
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
|
||||
|
||||
ft_font->load_flags = load_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_get_load_flags:
|
||||
* @font:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
* Since: 1.0.5
|
||||
**/
|
||||
int
|
||||
hb_ft_font_get_load_flags (hb_font_t *font)
|
||||
{
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
return 0;
|
||||
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
|
||||
|
||||
return ft_font->load_flags;
|
||||
}
|
||||
|
||||
FT_Face
|
||||
hb_ft_font_get_face (hb_font_t *font)
|
||||
{
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
return nullptr;
|
||||
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
|
||||
|
||||
return ft_font->ft_face;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_nominal_glyph (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
|
||||
|
||||
if (unlikely (!g))
|
||||
{
|
||||
if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
|
||||
{
|
||||
/* For symbol-encoded OpenType fonts, we duplicate the
|
||||
* U+F000..F0FF range at U+0000..U+00FF. That's what
|
||||
* Windows seems to do, and that's hinted about at:
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/recom
|
||||
* under "Non-Standard (Symbol) Fonts". */
|
||||
g = FT_Get_Char_Index (ft_font->ft_face, 0xF000u + unicode);
|
||||
if (!g)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
*glyph = g;
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
unsigned int done;
|
||||
for (done = 0;
|
||||
done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
|
||||
done++)
|
||||
{
|
||||
first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
|
||||
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
}
|
||||
/* We don't need to do ft_font->symbol dance here, since HB calls the singular
|
||||
* nominal_glyph() for what we don't handle here. */
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_variation_glyph (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
|
||||
|
||||
if (unlikely (!g))
|
||||
return false;
|
||||
|
||||
*glyph = g;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
|
||||
unsigned count,
|
||||
const hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
int load_flags = ft_font->load_flags;
|
||||
int mult = font->x_scale < 0 ? -1 : +1;
|
||||
|
||||
if (font->x_scale != ft_font->cached_x_scale.get ())
|
||||
{
|
||||
ft_font->advance_cache.clear ();
|
||||
ft_font->cached_x_scale.set (font->x_scale);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
FT_Fixed v = 0;
|
||||
hb_codepoint_t glyph = *first_glyph;
|
||||
|
||||
unsigned int cv;
|
||||
if (ft_font->advance_cache.get (glyph, &cv))
|
||||
v = cv;
|
||||
else
|
||||
{
|
||||
FT_Get_Advance (ft_face, glyph, load_flags, &v);
|
||||
ft_font->advance_cache.set (glyph, v);
|
||||
}
|
||||
|
||||
*first_advance = (v * mult + (1<<9)) >> 10;
|
||||
first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
}
|
||||
|
||||
static hb_position_t
|
||||
hb_ft_get_glyph_v_advance (hb_font_t *font,
|
||||
void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Fixed v;
|
||||
|
||||
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
|
||||
return 0;
|
||||
|
||||
if (font->y_scale < 0)
|
||||
v = -v;
|
||||
|
||||
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
|
||||
* have a Y growing upward. Hence the extra negation. */
|
||||
return (-v + (1<<9)) >> 10;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_glyph_v_origin (hb_font_t *font,
|
||||
void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
|
||||
return false;
|
||||
|
||||
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
|
||||
* have a Y growing upward. Hence the extra negation. */
|
||||
*x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX;
|
||||
*y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
|
||||
|
||||
if (font->x_scale < 0)
|
||||
*x = -*x;
|
||||
if (font->y_scale < 0)
|
||||
*y = -*y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_OT_SHAPE_FALLBACK
|
||||
static hb_position_t
|
||||
hb_ft_get_glyph_h_kerning (hb_font_t *font,
|
||||
void *font_data,
|
||||
hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
FT_Vector kerningv;
|
||||
|
||||
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
|
||||
if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
|
||||
return 0;
|
||||
|
||||
return kerningv.x;
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_glyph_extents (hb_font_t *font,
|
||||
void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
|
||||
return false;
|
||||
|
||||
extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
|
||||
extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
|
||||
extents->width = ft_face->glyph->metrics.width;
|
||||
extents->height = -ft_face->glyph->metrics.height;
|
||||
if (font->x_scale < 0)
|
||||
{
|
||||
extents->x_bearing = -extents->x_bearing;
|
||||
extents->width = -extents->width;
|
||||
}
|
||||
if (font->y_scale < 0)
|
||||
{
|
||||
extents->y_bearing = -extents->y_bearing;
|
||||
extents->height = -extents->height;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int point_index,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
|
||||
return false;
|
||||
|
||||
if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
|
||||
return false;
|
||||
|
||||
if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
|
||||
return false;
|
||||
|
||||
*x = ft_face->glyph->outline.points[point_index].x;
|
||||
*y = ft_face->glyph->outline.points[point_index].y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
char *name, unsigned int size,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
|
||||
if (ret && (size && !*name))
|
||||
ret = false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
const char *name, int len, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
if (len < 0)
|
||||
*glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
|
||||
else {
|
||||
/* Make a nul-terminated version. */
|
||||
char buf[128];
|
||||
len = hb_min (len, (int) sizeof (buf) - 1);
|
||||
strncpy (buf, name, len);
|
||||
buf[len] = '\0';
|
||||
*glyph = FT_Get_Name_Index (ft_face, buf);
|
||||
}
|
||||
|
||||
if (*glyph == 0)
|
||||
{
|
||||
/* Check whether the given name was actually the name of glyph 0. */
|
||||
char buf[128];
|
||||
if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
|
||||
len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
|
||||
return true;
|
||||
}
|
||||
|
||||
return *glyph != 0;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
hb_lock_t lock (ft_font->lock);
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
|
||||
metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
|
||||
metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
|
||||
if (font->y_scale < 0)
|
||||
{
|
||||
metrics->ascender = -metrics->ascender;
|
||||
metrics->descender = -metrics->descender;
|
||||
metrics->line_gap = -metrics->line_gap;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static void free_static_ft_funcs ();
|
||||
#endif
|
||||
|
||||
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
|
||||
{
|
||||
static hb_font_funcs_t *create ()
|
||||
{
|
||||
hb_font_funcs_t *funcs = hb_font_funcs_create ();
|
||||
|
||||
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
|
||||
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
|
||||
hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
|
||||
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
|
||||
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
|
||||
#ifndef HB_NO_OT_SHAPE_FALLBACK
|
||||
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
|
||||
#endif
|
||||
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
|
||||
|
||||
hb_font_funcs_make_immutable (funcs);
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
atexit (free_static_ft_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_ft_funcs;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_ft_funcs ()
|
||||
{
|
||||
static_ft_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_font_funcs_t *
|
||||
_hb_ft_get_font_funcs ()
|
||||
{
|
||||
return static_ft_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
|
||||
{
|
||||
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
|
||||
|
||||
hb_font_set_funcs (font,
|
||||
_hb_ft_get_font_funcs (),
|
||||
_hb_ft_font_create (ft_face, symbol, unref),
|
||||
_hb_ft_font_destroy);
|
||||
}
|
||||
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face) user_data;
|
||||
FT_Byte *buffer;
|
||||
FT_ULong length = 0;
|
||||
FT_Error error;
|
||||
|
||||
/* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
|
||||
|
||||
error = FT_Load_Sfnt_Table (ft_face, tag, 0, nullptr, &length);
|
||||
if (error)
|
||||
return nullptr;
|
||||
|
||||
buffer = (FT_Byte *) malloc (length);
|
||||
if (!buffer)
|
||||
return nullptr;
|
||||
|
||||
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
|
||||
if (error)
|
||||
{
|
||||
free (buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hb_blob_create ((const char *) buffer, length,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
buffer, free);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_face_create:
|
||||
* @ft_face: (destroy destroy) (scope notified):
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_ft_face_create (FT_Face ft_face,
|
||||
hb_destroy_func_t destroy)
|
||||
{
|
||||
hb_face_t *face;
|
||||
|
||||
if (!ft_face->stream->read) {
|
||||
hb_blob_t *blob;
|
||||
|
||||
blob = hb_blob_create ((const char *) ft_face->stream->base,
|
||||
(unsigned int) ft_face->stream->size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
ft_face, destroy);
|
||||
face = hb_face_create (blob, ft_face->face_index);
|
||||
hb_blob_destroy (blob);
|
||||
} else {
|
||||
face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
|
||||
}
|
||||
|
||||
hb_face_set_index (face, ft_face->face_index);
|
||||
hb_face_set_upem (face, ft_face->units_per_EM);
|
||||
|
||||
return face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_face_create_referenced:
|
||||
* @ft_face:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.38
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_ft_face_create_referenced (FT_Face ft_face)
|
||||
{
|
||||
FT_Reference_Face (ft_face);
|
||||
return hb_ft_face_create (ft_face, _hb_ft_face_destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
hb_ft_face_finalize (FT_Face ft_face)
|
||||
{
|
||||
hb_face_destroy ((hb_face_t *) ft_face->generic.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_face_create_cached:
|
||||
* @ft_face:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_ft_face_create_cached (FT_Face ft_face)
|
||||
{
|
||||
if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
|
||||
{
|
||||
if (ft_face->generic.finalizer)
|
||||
ft_face->generic.finalizer (ft_face);
|
||||
|
||||
ft_face->generic.data = hb_ft_face_create (ft_face, nullptr);
|
||||
ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
|
||||
}
|
||||
|
||||
return hb_face_reference ((hb_face_t *) ft_face->generic.data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_ft_font_create:
|
||||
* @ft_face: (destroy destroy) (scope notified):
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_font_t *
|
||||
hb_ft_font_create (FT_Face ft_face,
|
||||
hb_destroy_func_t destroy)
|
||||
{
|
||||
hb_font_t *font;
|
||||
hb_face_t *face;
|
||||
|
||||
face = hb_ft_face_create (ft_face, destroy);
|
||||
font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
_hb_ft_font_set_funcs (font, ft_face, false);
|
||||
hb_ft_font_changed (font);
|
||||
return font;
|
||||
}
|
||||
|
||||
void
|
||||
hb_ft_font_changed (hb_font_t *font)
|
||||
{
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
return;
|
||||
|
||||
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
hb_font_set_scale (font,
|
||||
(int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16),
|
||||
(int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1u<<15)) >> 16));
|
||||
#if 0 /* hb-ft works in no-hinting model */
|
||||
hb_font_set_ppem (font,
|
||||
ft_face->size->metrics.x_ppem,
|
||||
ft_face->size->metrics.y_ppem);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
|
||||
FT_MM_Var *mm_var = nullptr;
|
||||
if (!FT_Get_MM_Var (ft_face, &mm_var))
|
||||
{
|
||||
FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
|
||||
int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
|
||||
if (coords && ft_coords)
|
||||
{
|
||||
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
|
||||
{
|
||||
bool nonzero = false;
|
||||
|
||||
for (unsigned int i = 0; i < mm_var->num_axis; ++i)
|
||||
{
|
||||
coords[i] = ft_coords[i] >>= 2;
|
||||
nonzero = nonzero || coords[i];
|
||||
}
|
||||
|
||||
if (nonzero)
|
||||
hb_font_set_var_coords_normalized (font, coords, mm_var->num_axis);
|
||||
else
|
||||
hb_font_set_var_coords_normalized (font, nullptr, 0);
|
||||
}
|
||||
}
|
||||
free (coords);
|
||||
free (ft_coords);
|
||||
#ifdef HAVE_FT_DONE_MM_VAR
|
||||
FT_Done_MM_Var (ft_face->glyph->library, mm_var);
|
||||
#else
|
||||
free (mm_var);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_create_referenced:
|
||||
* @ft_face:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.38
|
||||
**/
|
||||
hb_font_t *
|
||||
hb_ft_font_create_referenced (FT_Face ft_face)
|
||||
{
|
||||
FT_Reference_Face (ft_face);
|
||||
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
|
||||
}
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static void free_static_ft_library ();
|
||||
#endif
|
||||
|
||||
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
|
||||
hb_ft_library_lazy_loader_t>
|
||||
{
|
||||
static FT_Library create ()
|
||||
{
|
||||
FT_Library l;
|
||||
if (FT_Init_FreeType (&l))
|
||||
return nullptr;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
atexit (free_static_ft_library);
|
||||
#endif
|
||||
|
||||
return l;
|
||||
}
|
||||
static void destroy (FT_Library l)
|
||||
{
|
||||
FT_Done_FreeType (l);
|
||||
}
|
||||
static FT_Library get_null ()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} static_ft_library;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_ft_library ()
|
||||
{
|
||||
static_ft_library.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static FT_Library
|
||||
get_ft_library ()
|
||||
{
|
||||
return static_ft_library.get_unconst ();
|
||||
}
|
||||
|
||||
static void
|
||||
_release_blob (FT_Face ft_face)
|
||||
{
|
||||
hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
|
||||
}
|
||||
|
||||
void
|
||||
hb_ft_font_set_funcs (hb_font_t *font)
|
||||
{
|
||||
hb_blob_t *blob = hb_face_reference_blob (font->face);
|
||||
unsigned int blob_length;
|
||||
const char *blob_data = hb_blob_get_data (blob, &blob_length);
|
||||
if (unlikely (!blob_length))
|
||||
DEBUG_MSG (FT, font, "Font face has empty blob");
|
||||
|
||||
FT_Face ft_face = nullptr;
|
||||
FT_Error err = FT_New_Memory_Face (get_ft_library (),
|
||||
(const FT_Byte *) blob_data,
|
||||
blob_length,
|
||||
hb_face_get_index (font->face),
|
||||
&ft_face);
|
||||
|
||||
if (unlikely (err)) {
|
||||
hb_blob_destroy (blob);
|
||||
DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
|
||||
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
|
||||
|
||||
FT_Set_Char_Size (ft_face,
|
||||
abs (font->x_scale), abs (font->y_scale),
|
||||
0, 0);
|
||||
#if 0
|
||||
font->x_ppem * 72 * 64 / font->x_scale,
|
||||
font->y_ppem * 72 * 64 / font->y_scale);
|
||||
#endif
|
||||
if (font->x_scale < 0 || font->y_scale < 0)
|
||||
{
|
||||
FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
|
||||
0, font->y_scale < 0 ? -1 : +1};
|
||||
FT_Set_Transform (ft_face, &matrix, nullptr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
|
||||
unsigned int num_coords;
|
||||
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
|
||||
if (num_coords)
|
||||
{
|
||||
FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
|
||||
if (ft_coords)
|
||||
{
|
||||
for (unsigned int i = 0; i < num_coords; i++)
|
||||
ft_coords[i] = coords[i] * 4;
|
||||
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
|
||||
free (ft_coords);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ft_face->generic.data = blob;
|
||||
ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;
|
||||
|
||||
_hb_ft_font_set_funcs (font, ft_face, true);
|
||||
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2015 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_FT_H
|
||||
#define HB_FT_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
/*
|
||||
* Note: FreeType is not thread-safe.
|
||||
* Hence, these functions are not either.
|
||||
*/
|
||||
|
||||
/*
|
||||
* hb-face from ft-face.
|
||||
*/
|
||||
|
||||
/* This one creates a new hb-face for given ft-face.
|
||||
* When the returned hb-face is destroyed, the destroy
|
||||
* callback is called (if not NULL), with the ft-face passed
|
||||
* to it.
|
||||
*
|
||||
* The client is responsible to make sure that ft-face is
|
||||
* destroyed after hb-face is destroyed.
|
||||
*
|
||||
* Most often you don't want this function. You should use either
|
||||
* hb_ft_face_create_cached(), or hb_ft_face_create_referenced().
|
||||
* In particular, if you are going to pass NULL as destroy, you
|
||||
* probably should use (the more recent) hb_ft_face_create_referenced()
|
||||
* instead.
|
||||
*/
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_ft_face_create (FT_Face ft_face,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
/* This version is like hb_ft_face_create(), except that it caches
|
||||
* the hb-face using the generic pointer of the ft-face. This means
|
||||
* that subsequent calls to this function with the same ft-face will
|
||||
* return the same hb-face (correctly referenced).
|
||||
*
|
||||
* Client is still responsible for making sure that ft-face is destroyed
|
||||
* after hb-face is.
|
||||
*/
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_ft_face_create_cached (FT_Face ft_face);
|
||||
|
||||
/* This version is like hb_ft_face_create(), except that it calls
|
||||
* FT_Reference_Face() on ft-face, as such keeping ft-face alive
|
||||
* as long as the hb-face is.
|
||||
*
|
||||
* This is the most convenient version to use. Use it unless you have
|
||||
* very good reasons not to.
|
||||
*/
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_ft_face_create_referenced (FT_Face ft_face);
|
||||
|
||||
|
||||
/*
|
||||
* hb-font from ft-face.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note:
|
||||
*
|
||||
* Set face size on ft-face before creating hb-font from it.
|
||||
* Otherwise hb-ft would NOT pick up the font size correctly.
|
||||
*/
|
||||
|
||||
/* See notes on hb_ft_face_create(). Same issues re lifecycle-management
|
||||
* apply here. Use hb_ft_font_create_referenced() if you can. */
|
||||
HB_EXTERN hb_font_t *
|
||||
hb_ft_font_create (FT_Face ft_face,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
/* See notes on hb_ft_face_create_referenced() re lifecycle-management
|
||||
* issues. */
|
||||
HB_EXTERN hb_font_t *
|
||||
hb_ft_font_create_referenced (FT_Face ft_face);
|
||||
|
||||
HB_EXTERN FT_Face
|
||||
hb_ft_font_get_face (hb_font_t *font);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
|
||||
|
||||
HB_EXTERN int
|
||||
hb_ft_font_get_load_flags (hb_font_t *font);
|
||||
|
||||
/* Call when size or variations settings on underlying FT_Face change. */
|
||||
HB_EXTERN void
|
||||
hb_ft_font_changed (hb_font_t *font);
|
||||
|
||||
/* Makes an hb_font_t use FreeType internally to implement font functions.
|
||||
* Note: this internally creates an FT_Face. Use it when you create your
|
||||
* hb_face_t using hb_face_create(). */
|
||||
HB_EXTERN void
|
||||
hb_ft_font_set_funcs (hb_font_t *font);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_FT_H */
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_GDI
|
||||
|
||||
#include "hb-gdi.h"
|
||||
|
||||
static hb_blob_t *
|
||||
_hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
char *buffer = nullptr;
|
||||
DWORD length = 0;
|
||||
|
||||
HDC hdc = GetDC (nullptr);
|
||||
if (unlikely (!SelectObject (hdc, (HFONT) user_data))) goto fail;
|
||||
|
||||
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
|
||||
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
|
||||
|
||||
buffer = (char *) malloc (length);
|
||||
if (unlikely (!buffer)) goto fail_with_releasedc;
|
||||
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
|
||||
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
|
||||
ReleaseDC (nullptr, hdc);
|
||||
|
||||
return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free);
|
||||
|
||||
fail_with_releasedc_and_free:
|
||||
free (buffer);
|
||||
fail_with_releasedc:
|
||||
ReleaseDC (nullptr, hdc);
|
||||
fail:
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_gdi_face_create:
|
||||
* @hfont: a HFONT object.
|
||||
*
|
||||
* Return value: #hb_face_t object corresponding to the given input
|
||||
*
|
||||
* Since: 2.6.0
|
||||
**/
|
||||
hb_face_t *
|
||||
hb_gdi_face_create (HFONT hfont)
|
||||
{
|
||||
return hb_face_create_for_tables (_hb_gdi_reference_table, (void *) hfont, nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_GDI_H
|
||||
#define HB_GDI_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
HB_EXTERN hb_face_t *
|
||||
hb_gdi_face_create (HFONT hfont);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_GDI_H */
|
||||
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
|
||||
#include "hb-glib.h"
|
||||
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-glib
|
||||
* @title: hb-glib
|
||||
* @short_description: GLib integration
|
||||
* @include: hb-glib.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the GLib library to provide Unicode data.
|
||||
**/
|
||||
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2,29,14)
|
||||
static const hb_script_t
|
||||
glib_script_to_script[] =
|
||||
{
|
||||
HB_SCRIPT_COMMON,
|
||||
HB_SCRIPT_INHERITED,
|
||||
HB_SCRIPT_ARABIC,
|
||||
HB_SCRIPT_ARMENIAN,
|
||||
HB_SCRIPT_BENGALI,
|
||||
HB_SCRIPT_BOPOMOFO,
|
||||
HB_SCRIPT_CHEROKEE,
|
||||
HB_SCRIPT_COPTIC,
|
||||
HB_SCRIPT_CYRILLIC,
|
||||
HB_SCRIPT_DESERET,
|
||||
HB_SCRIPT_DEVANAGARI,
|
||||
HB_SCRIPT_ETHIOPIC,
|
||||
HB_SCRIPT_GEORGIAN,
|
||||
HB_SCRIPT_GOTHIC,
|
||||
HB_SCRIPT_GREEK,
|
||||
HB_SCRIPT_GUJARATI,
|
||||
HB_SCRIPT_GURMUKHI,
|
||||
HB_SCRIPT_HAN,
|
||||
HB_SCRIPT_HANGUL,
|
||||
HB_SCRIPT_HEBREW,
|
||||
HB_SCRIPT_HIRAGANA,
|
||||
HB_SCRIPT_KANNADA,
|
||||
HB_SCRIPT_KATAKANA,
|
||||
HB_SCRIPT_KHMER,
|
||||
HB_SCRIPT_LAO,
|
||||
HB_SCRIPT_LATIN,
|
||||
HB_SCRIPT_MALAYALAM,
|
||||
HB_SCRIPT_MONGOLIAN,
|
||||
HB_SCRIPT_MYANMAR,
|
||||
HB_SCRIPT_OGHAM,
|
||||
HB_SCRIPT_OLD_ITALIC,
|
||||
HB_SCRIPT_ORIYA,
|
||||
HB_SCRIPT_RUNIC,
|
||||
HB_SCRIPT_SINHALA,
|
||||
HB_SCRIPT_SYRIAC,
|
||||
HB_SCRIPT_TAMIL,
|
||||
HB_SCRIPT_TELUGU,
|
||||
HB_SCRIPT_THAANA,
|
||||
HB_SCRIPT_THAI,
|
||||
HB_SCRIPT_TIBETAN,
|
||||
HB_SCRIPT_CANADIAN_SYLLABICS,
|
||||
HB_SCRIPT_YI,
|
||||
HB_SCRIPT_TAGALOG,
|
||||
HB_SCRIPT_HANUNOO,
|
||||
HB_SCRIPT_BUHID,
|
||||
HB_SCRIPT_TAGBANWA,
|
||||
|
||||
/* Unicode-4.0 additions */
|
||||
HB_SCRIPT_BRAILLE,
|
||||
HB_SCRIPT_CYPRIOT,
|
||||
HB_SCRIPT_LIMBU,
|
||||
HB_SCRIPT_OSMANYA,
|
||||
HB_SCRIPT_SHAVIAN,
|
||||
HB_SCRIPT_LINEAR_B,
|
||||
HB_SCRIPT_TAI_LE,
|
||||
HB_SCRIPT_UGARITIC,
|
||||
|
||||
/* Unicode-4.1 additions */
|
||||
HB_SCRIPT_NEW_TAI_LUE,
|
||||
HB_SCRIPT_BUGINESE,
|
||||
HB_SCRIPT_GLAGOLITIC,
|
||||
HB_SCRIPT_TIFINAGH,
|
||||
HB_SCRIPT_SYLOTI_NAGRI,
|
||||
HB_SCRIPT_OLD_PERSIAN,
|
||||
HB_SCRIPT_KHAROSHTHI,
|
||||
|
||||
/* Unicode-5.0 additions */
|
||||
HB_SCRIPT_UNKNOWN,
|
||||
HB_SCRIPT_BALINESE,
|
||||
HB_SCRIPT_CUNEIFORM,
|
||||
HB_SCRIPT_PHOENICIAN,
|
||||
HB_SCRIPT_PHAGS_PA,
|
||||
HB_SCRIPT_NKO,
|
||||
|
||||
/* Unicode-5.1 additions */
|
||||
HB_SCRIPT_KAYAH_LI,
|
||||
HB_SCRIPT_LEPCHA,
|
||||
HB_SCRIPT_REJANG,
|
||||
HB_SCRIPT_SUNDANESE,
|
||||
HB_SCRIPT_SAURASHTRA,
|
||||
HB_SCRIPT_CHAM,
|
||||
HB_SCRIPT_OL_CHIKI,
|
||||
HB_SCRIPT_VAI,
|
||||
HB_SCRIPT_CARIAN,
|
||||
HB_SCRIPT_LYCIAN,
|
||||
HB_SCRIPT_LYDIAN,
|
||||
|
||||
/* Unicode-5.2 additions */
|
||||
HB_SCRIPT_AVESTAN,
|
||||
HB_SCRIPT_BAMUM,
|
||||
HB_SCRIPT_EGYPTIAN_HIEROGLYPHS,
|
||||
HB_SCRIPT_IMPERIAL_ARAMAIC,
|
||||
HB_SCRIPT_INSCRIPTIONAL_PAHLAVI,
|
||||
HB_SCRIPT_INSCRIPTIONAL_PARTHIAN,
|
||||
HB_SCRIPT_JAVANESE,
|
||||
HB_SCRIPT_KAITHI,
|
||||
HB_SCRIPT_TAI_THAM,
|
||||
HB_SCRIPT_LISU,
|
||||
HB_SCRIPT_MEETEI_MAYEK,
|
||||
HB_SCRIPT_OLD_SOUTH_ARABIAN,
|
||||
HB_SCRIPT_OLD_TURKIC,
|
||||
HB_SCRIPT_SAMARITAN,
|
||||
HB_SCRIPT_TAI_VIET,
|
||||
|
||||
/* Unicode-6.0 additions */
|
||||
HB_SCRIPT_BATAK,
|
||||
HB_SCRIPT_BRAHMI,
|
||||
HB_SCRIPT_MANDAIC,
|
||||
|
||||
/* Unicode-6.1 additions */
|
||||
HB_SCRIPT_CHAKMA,
|
||||
HB_SCRIPT_MEROITIC_CURSIVE,
|
||||
HB_SCRIPT_MEROITIC_HIEROGLYPHS,
|
||||
HB_SCRIPT_MIAO,
|
||||
HB_SCRIPT_SHARADA,
|
||||
HB_SCRIPT_SORA_SOMPENG,
|
||||
HB_SCRIPT_TAKRI
|
||||
};
|
||||
#endif
|
||||
|
||||
hb_script_t
|
||||
hb_glib_script_to_script (GUnicodeScript script)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2,29,14)
|
||||
return (hb_script_t) g_unicode_script_to_iso15924 (script);
|
||||
#else
|
||||
if (likely ((unsigned int) script < ARRAY_LENGTH (glib_script_to_script)))
|
||||
return glib_script_to_script[script];
|
||||
|
||||
if (unlikely (script == G_UNICODE_SCRIPT_INVALID_CODE))
|
||||
return HB_SCRIPT_INVALID;
|
||||
|
||||
return HB_SCRIPT_UNKNOWN;
|
||||
#endif
|
||||
}
|
||||
|
||||
GUnicodeScript
|
||||
hb_glib_script_from_script (hb_script_t script)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2,29,14)
|
||||
return g_unicode_script_from_iso15924 (script);
|
||||
#else
|
||||
unsigned int count = ARRAY_LENGTH (glib_script_to_script);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (glib_script_to_script[i] == script)
|
||||
return (GUnicodeScript) i;
|
||||
|
||||
if (unlikely (script == HB_SCRIPT_INVALID))
|
||||
return G_UNICODE_SCRIPT_INVALID_CODE;
|
||||
|
||||
return G_UNICODE_SCRIPT_UNKNOWN;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static hb_unicode_combining_class_t
|
||||
hb_glib_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
|
||||
{
|
||||
return (hb_unicode_combining_class_t) g_unichar_combining_class (unicode);
|
||||
}
|
||||
|
||||
static hb_unicode_general_category_t
|
||||
hb_glib_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
|
||||
{
|
||||
/* hb_unicode_general_category_t and GUnicodeType are identical */
|
||||
return (hb_unicode_general_category_t) g_unichar_type (unicode);
|
||||
}
|
||||
|
||||
static hb_codepoint_t
|
||||
hb_glib_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
g_unichar_get_mirror_char (unicode, &unicode);
|
||||
return unicode;
|
||||
}
|
||||
|
||||
static hb_script_t
|
||||
hb_glib_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return hb_glib_script_to_script (g_unichar_get_script (unicode));
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t a,
|
||||
hb_codepoint_t b,
|
||||
hb_codepoint_t *ab,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2,29,12)
|
||||
return g_unichar_compose (a, b, ab);
|
||||
#endif
|
||||
|
||||
/* We don't ifdef-out the fallback code such that compiler always
|
||||
* sees it and makes sure it's compilable. */
|
||||
|
||||
gchar utf8[12];
|
||||
gchar *normalized;
|
||||
int len;
|
||||
hb_bool_t ret;
|
||||
|
||||
len = g_unichar_to_utf8 (a, utf8);
|
||||
len += g_unichar_to_utf8 (b, utf8 + len);
|
||||
normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFC);
|
||||
len = g_utf8_strlen (normalized, -1);
|
||||
if (unlikely (!len))
|
||||
return false;
|
||||
|
||||
if (len == 1) {
|
||||
*ab = g_utf8_get_char (normalized);
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
g_free (normalized);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t ab,
|
||||
hb_codepoint_t *a,
|
||||
hb_codepoint_t *b,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
#if GLIB_CHECK_VERSION(2,29,12)
|
||||
return g_unichar_decompose (ab, a, b);
|
||||
#endif
|
||||
|
||||
/* We don't ifdef-out the fallback code such that compiler always
|
||||
* sees it and makes sure it's compilable. */
|
||||
|
||||
gchar utf8[6];
|
||||
gchar *normalized;
|
||||
int len;
|
||||
hb_bool_t ret;
|
||||
|
||||
len = g_unichar_to_utf8 (ab, utf8);
|
||||
normalized = g_utf8_normalize (utf8, len, G_NORMALIZE_NFD);
|
||||
len = g_utf8_strlen (normalized, -1);
|
||||
if (unlikely (!len))
|
||||
return false;
|
||||
|
||||
if (len == 1) {
|
||||
*a = g_utf8_get_char (normalized);
|
||||
*b = 0;
|
||||
ret = *a != ab;
|
||||
} else if (len == 2) {
|
||||
*a = g_utf8_get_char (normalized);
|
||||
*b = g_utf8_get_char (g_utf8_next_char (normalized));
|
||||
/* Here's the ugly part: if ab decomposes to a single character and
|
||||
* that character decomposes again, we have to detect that and undo
|
||||
* the second part :-(. */
|
||||
gchar *recomposed = g_utf8_normalize (normalized, -1, G_NORMALIZE_NFC);
|
||||
hb_codepoint_t c = g_utf8_get_char (recomposed);
|
||||
if (c != ab && c != *a) {
|
||||
*a = c;
|
||||
*b = 0;
|
||||
}
|
||||
g_free (recomposed);
|
||||
ret = true;
|
||||
} else {
|
||||
/* If decomposed to more than two characters, take the last one,
|
||||
* and recompose the rest to get the first component. */
|
||||
gchar *end = g_utf8_offset_to_pointer (normalized, len - 1);
|
||||
gchar *recomposed;
|
||||
*b = g_utf8_get_char (end);
|
||||
recomposed = g_utf8_normalize (normalized, end - normalized, G_NORMALIZE_NFC);
|
||||
/* We expect that recomposed has exactly one character now. */
|
||||
*a = g_utf8_get_char (recomposed);
|
||||
g_free (recomposed);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
g_free (normalized);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static void free_static_glib_funcs ();
|
||||
#endif
|
||||
|
||||
static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
|
||||
{
|
||||
static hb_unicode_funcs_t *create ()
|
||||
{
|
||||
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
|
||||
|
||||
hb_unicode_funcs_set_combining_class_func (funcs, hb_glib_unicode_combining_class, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_general_category_func (funcs, hb_glib_unicode_general_category, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_mirroring_func (funcs, hb_glib_unicode_mirroring, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_script_func (funcs, hb_glib_unicode_script, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_compose_func (funcs, hb_glib_unicode_compose, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_decompose_func (funcs, hb_glib_unicode_decompose, nullptr, nullptr);
|
||||
|
||||
hb_unicode_funcs_make_immutable (funcs);
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
atexit (free_static_glib_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_glib_funcs;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_glib_funcs ()
|
||||
{
|
||||
static_glib_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_glib_get_unicode_funcs ()
|
||||
{
|
||||
return static_glib_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,31,10)
|
||||
|
||||
static void
|
||||
_hb_g_bytes_unref (void *data)
|
||||
{
|
||||
g_bytes_unref ((GBytes *) data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_glib_blob_create:
|
||||
*
|
||||
* Since: 0.9.38
|
||||
**/
|
||||
hb_blob_t *
|
||||
hb_glib_blob_create (GBytes *gbytes)
|
||||
{
|
||||
gsize size = 0;
|
||||
gconstpointer data = g_bytes_get_data (gbytes, &size);
|
||||
return hb_blob_create ((const char *) data,
|
||||
size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
g_bytes_ref (gbytes),
|
||||
_hb_g_bytes_unref);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
|
|
@ -22,38 +23,34 @@
|
|||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_H_IN
|
||||
#error "Include <hb-ot.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_OT_TAG_H
|
||||
#define HB_OT_TAG_H
|
||||
#ifndef HB_GLIB_H
|
||||
#define HB_GLIB_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
#define HB_OT_TAG_DEFAULT_SCRIPT HB_TAG ('D', 'F', 'L', 'T')
|
||||
#define HB_OT_TAG_DEFAULT_LANGUAGE HB_TAG ('d', 'f', 'l', 't')
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_tags_from_script (hb_script_t script,
|
||||
hb_tag_t *script_tag_1,
|
||||
hb_tag_t *script_tag_2);
|
||||
|
||||
HB_EXTERN hb_script_t
|
||||
hb_ot_tag_to_script (hb_tag_t tag);
|
||||
hb_glib_script_to_script (GUnicodeScript script);
|
||||
|
||||
HB_EXTERN hb_tag_t
|
||||
hb_ot_tag_from_language (hb_language_t language);
|
||||
HB_EXTERN GUnicodeScript
|
||||
hb_glib_script_from_script (hb_script_t script);
|
||||
|
||||
HB_EXTERN hb_language_t
|
||||
hb_ot_tag_to_language (hb_tag_t tag);
|
||||
|
||||
HB_EXTERN hb_unicode_funcs_t *
|
||||
hb_glib_get_unicode_funcs (void);
|
||||
|
||||
#if GLIB_CHECK_VERSION(2,31,10)
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_glib_blob_create (GBytes *gbytes);
|
||||
#endif
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_OT_TAG_H */
|
||||
#endif /* HB_GLIB_H */
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*** BEGIN file-header ***/
|
||||
/*
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_GOBJECT
|
||||
|
||||
/* g++ didn't like older gtype.h gcc-only code path. */
|
||||
#include <glib.h>
|
||||
#if !GLIB_CHECK_VERSION(2,29,16)
|
||||
#undef __GNUC__
|
||||
#undef __GNUC_MINOR__
|
||||
#define __GNUC__ 2
|
||||
#define __GNUC_MINOR__ 6
|
||||
#endif
|
||||
|
||||
#include "hb-gobject.h"
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@filename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
|
||||
#endif
|
||||
/*** END file-tail ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type ()
|
||||
{
|
||||
static gsize type_id = 0;
|
||||
|
||||
if (g_once_init_enter (&type_id))
|
||||
{
|
||||
static const G@Type@Value values[] = {
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN value-production ***/
|
||||
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
|
||||
/*** END value-production ***/
|
||||
|
||||
/*** BEGIN value-tail ***/
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
GType id =
|
||||
g_@type@_register_static (g_intern_static_string ("@EnumName@"), values);
|
||||
g_once_init_leave (&type_id, id);
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
/*** END value-tail ***/
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*** BEGIN file-header ***/
|
||||
/*
|
||||
* Copyright © 2013 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_GOBJECT_H_IN
|
||||
#error "Include <hb-gobject.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_GOBJECT_ENUMS_H
|
||||
#define HB_GOBJECT_ENUMS_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
HB_EXTERN GType
|
||||
@enum_name@_get_type () G_GNUC_CONST;
|
||||
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
|
||||
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_GOBJECT_ENUMS_H */
|
||||
/*** END file-tail ***/
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_GOBJECT
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-gobject
|
||||
* @title: hb-gobject
|
||||
* @short_description: GObject integration
|
||||
* @include: hb-gobject.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the GObject library to provide
|
||||
* type data.
|
||||
**/
|
||||
|
||||
|
||||
/* g++ didn't like older gtype.h gcc-only code path. */
|
||||
#include <glib.h>
|
||||
#if !GLIB_CHECK_VERSION(2,29,16)
|
||||
#undef __GNUC__
|
||||
#undef __GNUC_MINOR__
|
||||
#define __GNUC__ 2
|
||||
#define __GNUC_MINOR__ 6
|
||||
#endif
|
||||
|
||||
#include "hb-gobject.h"
|
||||
|
||||
#define HB_DEFINE_BOXED_TYPE(name,copy_func,free_func) \
|
||||
GType \
|
||||
hb_gobject_##name##_get_type () \
|
||||
{ \
|
||||
static gsize type_id = 0; \
|
||||
if (g_once_init_enter (&type_id)) { \
|
||||
GType id = g_boxed_type_register_static (g_intern_static_string ("hb_" #name "_t"), \
|
||||
(GBoxedCopyFunc) copy_func, \
|
||||
(GBoxedFreeFunc) free_func); \
|
||||
g_once_init_leave (&type_id, id); \
|
||||
} \
|
||||
return type_id; \
|
||||
}
|
||||
|
||||
#define HB_DEFINE_OBJECT_TYPE(name) \
|
||||
HB_DEFINE_BOXED_TYPE (name, hb_##name##_reference, hb_##name##_destroy)
|
||||
|
||||
#define HB_DEFINE_VALUE_TYPE(name) \
|
||||
static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
|
||||
{ \
|
||||
hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
|
||||
if (unlikely (!c)) return nullptr; \
|
||||
*c = *l; \
|
||||
return c; \
|
||||
} \
|
||||
static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
|
||||
HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy)
|
||||
|
||||
HB_DEFINE_OBJECT_TYPE (buffer)
|
||||
HB_DEFINE_OBJECT_TYPE (blob)
|
||||
HB_DEFINE_OBJECT_TYPE (face)
|
||||
HB_DEFINE_OBJECT_TYPE (font)
|
||||
HB_DEFINE_OBJECT_TYPE (font_funcs)
|
||||
HB_DEFINE_OBJECT_TYPE (set)
|
||||
HB_DEFINE_OBJECT_TYPE (map)
|
||||
HB_DEFINE_OBJECT_TYPE (shape_plan)
|
||||
HB_DEFINE_OBJECT_TYPE (unicode_funcs)
|
||||
HB_DEFINE_VALUE_TYPE (feature)
|
||||
HB_DEFINE_VALUE_TYPE (glyph_info)
|
||||
HB_DEFINE_VALUE_TYPE (glyph_position)
|
||||
HB_DEFINE_VALUE_TYPE (segment_properties)
|
||||
HB_DEFINE_VALUE_TYPE (user_data_key)
|
||||
|
||||
HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant)
|
||||
HB_DEFINE_VALUE_TYPE (ot_math_glyph_part)
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_GOBJECT_H_IN
|
||||
#error "Include <hb-gobject.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_GOBJECT_STRUCTS_H
|
||||
#define HB_GOBJECT_STRUCTS_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
/* Object types */
|
||||
|
||||
/**
|
||||
* hb_gobject_blob_get_type:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN GType
|
||||
hb_gobject_blob_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_BLOB (hb_gobject_blob_get_type ())
|
||||
|
||||
/**
|
||||
* hb_gobject_buffer_get_type:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN GType
|
||||
hb_gobject_buffer_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ())
|
||||
|
||||
/**
|
||||
* hb_gobject_face_get_type:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN GType
|
||||
hb_gobject_face_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ())
|
||||
|
||||
/**
|
||||
* hb_gobject_font_get_type:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN GType
|
||||
hb_gobject_font_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_FONT (hb_gobject_font_get_type ())
|
||||
|
||||
/**
|
||||
* hb_gobject_font_funcs_get_type:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN GType
|
||||
hb_gobject_font_funcs_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_FONT_FUNCS (hb_gobject_font_funcs_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_set_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_map_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_MAP (hb_gobject_map_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_shape_plan_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
|
||||
|
||||
/**
|
||||
* hb_gobject_unicode_funcs_get_type:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN GType
|
||||
hb_gobject_unicode_funcs_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_UNICODE_FUNCS (hb_gobject_unicode_funcs_get_type ())
|
||||
|
||||
/* Value types */
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_feature_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_FEATURE (hb_gobject_feature_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_glyph_info_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_GLYPH_INFO (hb_gobject_glyph_info_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_glyph_position_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_GLYPH_POSITION (hb_gobject_glyph_position_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_segment_properties_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_SEGMENT_PROPERTIES (hb_gobject_segment_properties_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_user_data_key_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_USER_DATA_KEY (hb_gobject_user_data_key_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_ot_math_glyph_variant_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_OT_MATH_GLYPH_VARIANT (hb_gobject_ot_math_glyph_variant_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_ot_math_glyph_part_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_OT_MATH_GLYPH_PART (hb_gobject_ot_math_glyph_part_get_type ())
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_GOBJECT_H */
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright © 2012 Google, Inc.
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
|
|
@ -24,16 +24,17 @@
|
|||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-mutex-private.hh"
|
||||
#ifndef HB_GOBJECT_H
|
||||
#define HB_GOBJECT_H
|
||||
#define HB_GOBJECT_H_IN
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#if defined(HB_ATOMIC_INT_NIL)
|
||||
#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe"
|
||||
#error "Check hb-atomic-private.hh for possible resolutions."
|
||||
#endif
|
||||
#include "hb-gobject-enums.h"
|
||||
#include "hb-gobject-structs.h"
|
||||
|
||||
#if defined(HB_MUTEX_IMPL_NIL)
|
||||
#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe"
|
||||
#error "Check hb-mutex-private.hh for possible resolutions."
|
||||
#endif
|
||||
HB_BEGIN_DECLS
|
||||
HB_END_DECLS
|
||||
|
||||
#undef HB_GOBJECT_H_IN
|
||||
#endif /* HB_GOBJECT_H */
|
||||
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
* Copyright © 2011 Martin Hosken
|
||||
* Copyright © 2011 SIL International
|
||||
* Copyright © 2011,2012 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_GRAPHITE2
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include "hb-graphite2.h"
|
||||
|
||||
#include <graphite2/Segment.h>
|
||||
|
||||
#include "hb-ot-layout.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-graphite2
|
||||
* @title: hb-graphite2
|
||||
* @short_description: Graphite2 integration
|
||||
* @include: hb-graphite2.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the Graphite2 fonts.
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
typedef struct hb_graphite2_tablelist_t
|
||||
{
|
||||
struct hb_graphite2_tablelist_t *next;
|
||||
hb_blob_t *blob;
|
||||
unsigned int tag;
|
||||
} hb_graphite2_tablelist_t;
|
||||
|
||||
struct hb_graphite2_face_data_t
|
||||
{
|
||||
hb_face_t *face;
|
||||
gr_face *grface;
|
||||
hb_atomic_ptr_t<hb_graphite2_tablelist_t> tlist;
|
||||
};
|
||||
|
||||
static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
|
||||
{
|
||||
hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
|
||||
hb_graphite2_tablelist_t *tlist = face_data->tlist;
|
||||
|
||||
hb_blob_t *blob = nullptr;
|
||||
|
||||
for (hb_graphite2_tablelist_t *p = tlist; p; p = p->next)
|
||||
if (p->tag == tag) {
|
||||
blob = p->blob;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely (!blob))
|
||||
{
|
||||
blob = face_data->face->reference_table (tag);
|
||||
|
||||
hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
|
||||
if (unlikely (!p)) {
|
||||
hb_blob_destroy (blob);
|
||||
return nullptr;
|
||||
}
|
||||
p->blob = blob;
|
||||
p->tag = tag;
|
||||
|
||||
retry:
|
||||
hb_graphite2_tablelist_t *tlist = face_data->tlist;
|
||||
p->next = tlist;
|
||||
|
||||
if (unlikely (!face_data->tlist.cmpexch (tlist, p)))
|
||||
goto retry;
|
||||
}
|
||||
|
||||
unsigned int tlen;
|
||||
const char *d = hb_blob_get_data (blob, &tlen);
|
||||
*len = tlen;
|
||||
return d;
|
||||
}
|
||||
|
||||
hb_graphite2_face_data_t *
|
||||
_hb_graphite2_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
|
||||
/* Umm, we just reference the table to check whether it exists.
|
||||
* Maybe add better API for this? */
|
||||
if (!hb_blob_get_length (silf_blob))
|
||||
{
|
||||
hb_blob_destroy (silf_blob);
|
||||
return nullptr;
|
||||
}
|
||||
hb_blob_destroy (silf_blob);
|
||||
|
||||
hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
data->face = face;
|
||||
data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
|
||||
|
||||
if (unlikely (!data->grface)) {
|
||||
free (data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
|
||||
{
|
||||
hb_graphite2_tablelist_t *tlist = data->tlist;
|
||||
|
||||
while (tlist)
|
||||
{
|
||||
hb_graphite2_tablelist_t *old = tlist;
|
||||
hb_blob_destroy (tlist->blob);
|
||||
tlist = tlist->next;
|
||||
free (old);
|
||||
}
|
||||
|
||||
gr_face_destroy (data->grface);
|
||||
|
||||
free (data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
gr_face *
|
||||
hb_graphite2_face_get_gr_face (hb_face_t *face)
|
||||
{
|
||||
const hb_graphite2_face_data_t *data = face->data.graphite2;
|
||||
return data ? data->grface : nullptr;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_graphite2_font_data_t {};
|
||||
|
||||
hb_graphite2_font_data_t *
|
||||
_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_graphite2_font_get_gr_font:
|
||||
*
|
||||
* Since: 0.9.10
|
||||
* Deprecated: 1.4.2
|
||||
*/
|
||||
gr_font *
|
||||
hb_graphite2_font_get_gr_font (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
||||
struct hb_graphite2_cluster_t {
|
||||
unsigned int base_char;
|
||||
unsigned int num_chars;
|
||||
unsigned int base_glyph;
|
||||
unsigned int num_glyphs;
|
||||
unsigned int cluster;
|
||||
unsigned int advance;
|
||||
};
|
||||
|
||||
hb_bool_t
|
||||
_hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
const hb_feature_t *features,
|
||||
unsigned int num_features)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
gr_face *grface = face->data.graphite2->grface;
|
||||
|
||||
const char *lang = hb_language_to_string (hb_buffer_get_language (buffer));
|
||||
const char *lang_end = lang ? strchr (lang, '-') : nullptr;
|
||||
int lang_len = lang_end ? lang_end - lang : -1;
|
||||
gr_feature_val *feats = gr_face_featureval_for_lang (grface, lang ? hb_tag_from_string (lang, lang_len) : 0);
|
||||
|
||||
for (unsigned int i = 0; i < num_features; i++)
|
||||
{
|
||||
const gr_feature_ref *fref = gr_face_find_fref (grface, features[i].tag);
|
||||
if (fref)
|
||||
gr_fref_set_feature_value (fref, features[i].value, feats);
|
||||
}
|
||||
|
||||
gr_segment *seg = nullptr;
|
||||
const gr_slot *is;
|
||||
unsigned int ci = 0, ic = 0;
|
||||
unsigned int curradvx = 0, curradvy = 0;
|
||||
|
||||
unsigned int scratch_size;
|
||||
hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
|
||||
uint32_t *chars = (uint32_t *) scratch;
|
||||
|
||||
for (unsigned int i = 0; i < buffer->len; ++i)
|
||||
chars[i] = buffer->info[i].codepoint;
|
||||
|
||||
/* TODO ensure_native_direction. */
|
||||
|
||||
hb_tag_t script_tag[HB_OT_MAX_TAGS_PER_SCRIPT];
|
||||
unsigned int count = HB_OT_MAX_TAGS_PER_SCRIPT;
|
||||
hb_ot_tags_from_script_and_language (hb_buffer_get_script (buffer),
|
||||
HB_LANGUAGE_INVALID,
|
||||
&count,
|
||||
script_tag,
|
||||
nullptr, nullptr);
|
||||
|
||||
seg = gr_make_seg (nullptr, grface,
|
||||
count ? script_tag[count - 1] : HB_OT_TAG_DEFAULT_SCRIPT,
|
||||
feats,
|
||||
gr_utf32, chars, buffer->len,
|
||||
2 | (hb_buffer_get_direction (buffer) == HB_DIRECTION_RTL ? 1 : 0));
|
||||
|
||||
if (unlikely (!seg)) {
|
||||
if (feats) gr_featureval_destroy (feats);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int glyph_count = gr_seg_n_slots (seg);
|
||||
if (unlikely (!glyph_count)) {
|
||||
if (feats) gr_featureval_destroy (feats);
|
||||
gr_seg_destroy (seg);
|
||||
buffer->len = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
buffer->ensure (glyph_count);
|
||||
scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
while ((DIV_CEIL (sizeof (hb_graphite2_cluster_t) * buffer->len, sizeof (*scratch)) +
|
||||
DIV_CEIL (sizeof (hb_codepoint_t) * glyph_count, sizeof (*scratch))) > scratch_size)
|
||||
{
|
||||
if (unlikely (!buffer->ensure (buffer->allocated * 2)))
|
||||
{
|
||||
if (feats) gr_featureval_destroy (feats);
|
||||
gr_seg_destroy (seg);
|
||||
return false;
|
||||
}
|
||||
scratch = buffer->get_scratch_buffer (&scratch_size);
|
||||
}
|
||||
|
||||
#define ALLOCATE_ARRAY(Type, name, len) \
|
||||
Type *name = (Type *) scratch; \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
assert (_consumed <= scratch_size); \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
} while (0)
|
||||
|
||||
ALLOCATE_ARRAY (hb_graphite2_cluster_t, clusters, buffer->len);
|
||||
ALLOCATE_ARRAY (hb_codepoint_t, gids, glyph_count);
|
||||
|
||||
#undef ALLOCATE_ARRAY
|
||||
|
||||
memset (clusters, 0, sizeof (clusters[0]) * buffer->len);
|
||||
|
||||
hb_codepoint_t *pg = gids;
|
||||
clusters[0].cluster = buffer->info[0].cluster;
|
||||
unsigned int upem = hb_face_get_upem (face);
|
||||
float xscale = (float) font->x_scale / upem;
|
||||
float yscale = (float) font->y_scale / upem;
|
||||
yscale *= yscale / xscale;
|
||||
unsigned int curradv = 0;
|
||||
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
{
|
||||
curradv = gr_slot_origin_X(gr_seg_first_slot(seg)) * xscale;
|
||||
clusters[0].advance = gr_seg_advance_X(seg) * xscale - curradv;
|
||||
}
|
||||
else
|
||||
clusters[0].advance = 0;
|
||||
for (is = gr_seg_first_slot (seg), ic = 0; is; is = gr_slot_next_in_segment (is), ic++)
|
||||
{
|
||||
unsigned int before = gr_slot_before (is);
|
||||
unsigned int after = gr_slot_after (is);
|
||||
*pg = gr_slot_gid (is);
|
||||
pg++;
|
||||
while (clusters[ci].base_char > before && ci)
|
||||
{
|
||||
clusters[ci-1].num_chars += clusters[ci].num_chars;
|
||||
clusters[ci-1].num_glyphs += clusters[ci].num_glyphs;
|
||||
clusters[ci-1].advance += clusters[ci].advance;
|
||||
ci--;
|
||||
}
|
||||
|
||||
if (gr_slot_can_insert_before (is) && clusters[ci].num_chars && before >= clusters[ci].base_char + clusters[ci].num_chars)
|
||||
{
|
||||
hb_graphite2_cluster_t *c = clusters + ci + 1;
|
||||
c->base_char = clusters[ci].base_char + clusters[ci].num_chars;
|
||||
c->cluster = buffer->info[c->base_char].cluster;
|
||||
c->num_chars = before - c->base_char;
|
||||
c->base_glyph = ic;
|
||||
c->num_glyphs = 0;
|
||||
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
{
|
||||
c->advance = curradv - gr_slot_origin_X(is) * xscale;
|
||||
curradv -= c->advance;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->advance = 0;
|
||||
clusters[ci].advance += gr_slot_origin_X(is) * xscale - curradv;
|
||||
curradv += clusters[ci].advance;
|
||||
}
|
||||
ci++;
|
||||
}
|
||||
clusters[ci].num_glyphs++;
|
||||
|
||||
if (clusters[ci].base_char + clusters[ci].num_chars < after + 1)
|
||||
clusters[ci].num_chars = after + 1 - clusters[ci].base_char;
|
||||
}
|
||||
|
||||
if (HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
clusters[ci].advance += curradv;
|
||||
else
|
||||
clusters[ci].advance += gr_seg_advance_X(seg) * xscale - curradv;
|
||||
ci++;
|
||||
|
||||
for (unsigned int i = 0; i < ci; ++i)
|
||||
{
|
||||
for (unsigned int j = 0; j < clusters[i].num_glyphs; ++j)
|
||||
{
|
||||
hb_glyph_info_t *info = &buffer->info[clusters[i].base_glyph + j];
|
||||
info->codepoint = gids[clusters[i].base_glyph + j];
|
||||
info->cluster = clusters[i].cluster;
|
||||
info->var1.i32 = clusters[i].advance; // all glyphs in the cluster get the same advance
|
||||
}
|
||||
}
|
||||
buffer->len = glyph_count;
|
||||
|
||||
/* Positioning. */
|
||||
unsigned int currclus = (unsigned int) -1;
|
||||
const hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pPos = hb_buffer_get_glyph_positions (buffer, nullptr);
|
||||
if (!HB_DIRECTION_IS_BACKWARD(buffer->props.direction))
|
||||
{
|
||||
curradvx = 0;
|
||||
for (is = gr_seg_first_slot (seg); is; pPos++, ++info, is = gr_slot_next_in_segment (is))
|
||||
{
|
||||
pPos->x_offset = gr_slot_origin_X (is) * xscale - curradvx;
|
||||
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
|
||||
if (info->cluster != currclus) {
|
||||
pPos->x_advance = info->var1.i32;
|
||||
curradvx += pPos->x_advance;
|
||||
currclus = info->cluster;
|
||||
} else
|
||||
pPos->x_advance = 0.;
|
||||
|
||||
pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
|
||||
curradvy += pPos->y_advance;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
curradvx = gr_seg_advance_X(seg) * xscale;
|
||||
for (is = gr_seg_first_slot (seg); is; pPos++, info++, is = gr_slot_next_in_segment (is))
|
||||
{
|
||||
if (info->cluster != currclus)
|
||||
{
|
||||
pPos->x_advance = info->var1.i32;
|
||||
curradvx -= pPos->x_advance;
|
||||
currclus = info->cluster;
|
||||
} else
|
||||
pPos->x_advance = 0.;
|
||||
|
||||
pPos->y_advance = gr_slot_advance_Y (is, grface, nullptr) * yscale;
|
||||
curradvy -= pPos->y_advance;
|
||||
pPos->x_offset = gr_slot_origin_X (is) * xscale - info->var1.i32 - curradvx + pPos->x_advance;
|
||||
pPos->y_offset = gr_slot_origin_Y (is) * yscale - curradvy;
|
||||
}
|
||||
hb_buffer_reverse_clusters (buffer);
|
||||
}
|
||||
|
||||
if (feats) gr_featureval_destroy (feats);
|
||||
gr_seg_destroy (seg);
|
||||
|
||||
buffer->unsafe_to_break_all ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright © 2011 Martin Hosken
|
||||
* Copyright © 2011 SIL International
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_GRAPHITE2_H
|
||||
#define HB_GRAPHITE2_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <graphite2/Font.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
#define HB_GRAPHITE2_TAG_SILF HB_TAG('S','i','l','f')
|
||||
|
||||
|
||||
HB_EXTERN gr_face *
|
||||
hb_graphite2_face_get_gr_face (hb_face_t *face);
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
|
||||
HB_EXTERN HB_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) gr_font *
|
||||
hb_graphite2_font_get_gr_font (hb_font_t *font);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_GRAPHITE2_H */
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2009 Keith Stribley
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_ICU
|
||||
|
||||
#include "hb-icu.h"
|
||||
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
#include <unicode/uchar.h>
|
||||
#include <unicode/unorm2.h>
|
||||
#include <unicode/ustring.h>
|
||||
#include <unicode/utf16.h>
|
||||
#include <unicode/uversion.h>
|
||||
|
||||
/* ICU extra semicolon, fixed since 65, https://github.com/unicode-org/icu/commit/480bec3 */
|
||||
#if U_ICU_VERSION_MAJOR_NUM < 65 && (defined(__GNUC__) || defined(__clang__))
|
||||
#define HB_ICU_EXTRA_SEMI_IGNORED
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wextra-semi-stmt"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION:hb-icu
|
||||
* @title: hb-icu
|
||||
* @short_description: ICU integration
|
||||
* @include: hb-icu.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the ICU library to provide Unicode data.
|
||||
**/
|
||||
|
||||
hb_script_t
|
||||
hb_icu_script_to_script (UScriptCode script)
|
||||
{
|
||||
if (unlikely (script == USCRIPT_INVALID_CODE))
|
||||
return HB_SCRIPT_INVALID;
|
||||
|
||||
return hb_script_from_string (uscript_getShortName (script), -1);
|
||||
}
|
||||
|
||||
UScriptCode
|
||||
hb_icu_script_from_script (hb_script_t script)
|
||||
{
|
||||
if (unlikely (script == HB_SCRIPT_INVALID))
|
||||
return USCRIPT_INVALID_CODE;
|
||||
|
||||
unsigned int numScriptCode = 1 + u_getIntPropertyMaxValue (UCHAR_SCRIPT);
|
||||
for (unsigned int i = 0; i < numScriptCode; i++)
|
||||
if (unlikely (hb_icu_script_to_script ((UScriptCode) i) == script))
|
||||
return (UScriptCode) i;
|
||||
|
||||
return USCRIPT_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
static hb_unicode_combining_class_t
|
||||
hb_icu_unicode_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
|
||||
{
|
||||
return (hb_unicode_combining_class_t) u_getCombiningClass (unicode);
|
||||
}
|
||||
|
||||
static hb_unicode_general_category_t
|
||||
hb_icu_unicode_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
switch (u_getIntPropertyValue(unicode, UCHAR_GENERAL_CATEGORY))
|
||||
{
|
||||
case U_UNASSIGNED: return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
|
||||
|
||||
case U_UPPERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_UPPERCASE_LETTER;
|
||||
case U_LOWERCASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_LOWERCASE_LETTER;
|
||||
case U_TITLECASE_LETTER: return HB_UNICODE_GENERAL_CATEGORY_TITLECASE_LETTER;
|
||||
case U_MODIFIER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_LETTER;
|
||||
case U_OTHER_LETTER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER;
|
||||
|
||||
case U_NON_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK;
|
||||
case U_ENCLOSING_MARK: return HB_UNICODE_GENERAL_CATEGORY_ENCLOSING_MARK;
|
||||
case U_COMBINING_SPACING_MARK: return HB_UNICODE_GENERAL_CATEGORY_SPACING_MARK;
|
||||
|
||||
case U_DECIMAL_DIGIT_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_DECIMAL_NUMBER;
|
||||
case U_LETTER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_LETTER_NUMBER;
|
||||
case U_OTHER_NUMBER: return HB_UNICODE_GENERAL_CATEGORY_OTHER_NUMBER;
|
||||
|
||||
case U_SPACE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_SPACE_SEPARATOR;
|
||||
case U_LINE_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_LINE_SEPARATOR;
|
||||
case U_PARAGRAPH_SEPARATOR: return HB_UNICODE_GENERAL_CATEGORY_PARAGRAPH_SEPARATOR;
|
||||
|
||||
case U_CONTROL_CHAR: return HB_UNICODE_GENERAL_CATEGORY_CONTROL;
|
||||
case U_FORMAT_CHAR: return HB_UNICODE_GENERAL_CATEGORY_FORMAT;
|
||||
case U_PRIVATE_USE_CHAR: return HB_UNICODE_GENERAL_CATEGORY_PRIVATE_USE;
|
||||
case U_SURROGATE: return HB_UNICODE_GENERAL_CATEGORY_SURROGATE;
|
||||
|
||||
|
||||
case U_DASH_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_DASH_PUNCTUATION;
|
||||
case U_START_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION;
|
||||
case U_END_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CLOSE_PUNCTUATION;
|
||||
case U_CONNECTOR_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_CONNECT_PUNCTUATION;
|
||||
case U_OTHER_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_OTHER_PUNCTUATION;
|
||||
|
||||
case U_MATH_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MATH_SYMBOL;
|
||||
case U_CURRENCY_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_CURRENCY_SYMBOL;
|
||||
case U_MODIFIER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_MODIFIER_SYMBOL;
|
||||
case U_OTHER_SYMBOL: return HB_UNICODE_GENERAL_CATEGORY_OTHER_SYMBOL;
|
||||
|
||||
case U_INITIAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_INITIAL_PUNCTUATION;
|
||||
case U_FINAL_PUNCTUATION: return HB_UNICODE_GENERAL_CATEGORY_FINAL_PUNCTUATION;
|
||||
}
|
||||
|
||||
return HB_UNICODE_GENERAL_CATEGORY_UNASSIGNED;
|
||||
}
|
||||
|
||||
static hb_codepoint_t
|
||||
hb_icu_unicode_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return u_charMirror(unicode);
|
||||
}
|
||||
|
||||
static hb_script_t
|
||||
hb_icu_unicode_script (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UScriptCode scriptCode = uscript_getScript(unicode, &status);
|
||||
|
||||
if (unlikely (U_FAILURE (status)))
|
||||
return HB_SCRIPT_UNKNOWN;
|
||||
|
||||
return hb_icu_script_to_script (scriptCode);
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_icu_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t a,
|
||||
hb_codepoint_t b,
|
||||
hb_codepoint_t *ab,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
{
|
||||
const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
|
||||
UChar32 ret = unorm2_composePair (normalizer, a, b);
|
||||
if (ret < 0) return false;
|
||||
*ab = ret;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We don't ifdef-out the fallback code such that compiler always
|
||||
* sees it and makes sure it's compilable. */
|
||||
|
||||
UChar utf16[4], normalized[5];
|
||||
unsigned int len;
|
||||
hb_bool_t ret, err;
|
||||
UErrorCode icu_err;
|
||||
|
||||
len = 0;
|
||||
err = false;
|
||||
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), a, err);
|
||||
if (err) return false;
|
||||
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), b, err);
|
||||
if (err) return false;
|
||||
|
||||
icu_err = U_ZERO_ERROR;
|
||||
len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
|
||||
if (U_FAILURE (icu_err))
|
||||
return false;
|
||||
if (u_countChar32 (normalized, len) == 1) {
|
||||
U16_GET_UNSAFE (normalized, 0, *ab);
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
|
||||
hb_codepoint_t ab,
|
||||
hb_codepoint_t *a,
|
||||
hb_codepoint_t *b,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
{
|
||||
const UNormalizer2 *normalizer = (const UNormalizer2 *) user_data;
|
||||
UChar decomposed[4];
|
||||
int len;
|
||||
UErrorCode icu_err = U_ZERO_ERROR;
|
||||
len = unorm2_getRawDecomposition (normalizer, ab, decomposed,
|
||||
ARRAY_LENGTH (decomposed), &icu_err);
|
||||
if (U_FAILURE (icu_err) || len < 0) return false;
|
||||
|
||||
len = u_countChar32 (decomposed, len);
|
||||
if (len == 1) {
|
||||
U16_GET_UNSAFE (decomposed, 0, *a);
|
||||
*b = 0;
|
||||
return *a != ab;
|
||||
} else if (len == 2) {
|
||||
len = 0;
|
||||
U16_NEXT_UNSAFE (decomposed, len, *a);
|
||||
U16_NEXT_UNSAFE (decomposed, len, *b);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We don't ifdef-out the fallback code such that compiler always
|
||||
* sees it and makes sure it's compilable. */
|
||||
|
||||
UChar utf16[2], normalized[2 * 19/*HB_UNICODE_MAX_DECOMPOSITION_LEN*/ + 1];
|
||||
unsigned int len;
|
||||
hb_bool_t ret, err;
|
||||
UErrorCode icu_err;
|
||||
|
||||
/* This function is a monster! Maybe it wasn't a good idea adding a
|
||||
* pairwise decompose API... */
|
||||
/* Watchout for the dragons. Err, watchout for macros changing len. */
|
||||
|
||||
len = 0;
|
||||
err = false;
|
||||
U16_APPEND (utf16, len, ARRAY_LENGTH (utf16), ab, err);
|
||||
if (err) return false;
|
||||
|
||||
icu_err = U_ZERO_ERROR;
|
||||
len = unorm2_normalize (unorm2_getNFDInstance (&icu_err), utf16, len, normalized, ARRAY_LENGTH (normalized), &icu_err);
|
||||
if (U_FAILURE (icu_err))
|
||||
return false;
|
||||
|
||||
len = u_countChar32 (normalized, len);
|
||||
|
||||
if (len == 1) {
|
||||
U16_GET_UNSAFE (normalized, 0, *a);
|
||||
*b = 0;
|
||||
ret = *a != ab;
|
||||
} else if (len == 2) {
|
||||
len = 0;
|
||||
U16_NEXT_UNSAFE (normalized, len, *a);
|
||||
U16_NEXT_UNSAFE (normalized, len, *b);
|
||||
|
||||
/* Here's the ugly part: if ab decomposes to a single character and
|
||||
* that character decomposes again, we have to detect that and undo
|
||||
* the second part :-(. */
|
||||
UChar recomposed[20];
|
||||
icu_err = U_ZERO_ERROR;
|
||||
unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
|
||||
if (U_FAILURE (icu_err))
|
||||
return false;
|
||||
hb_codepoint_t c;
|
||||
U16_GET_UNSAFE (recomposed, 0, c);
|
||||
if (c != *a && c != ab) {
|
||||
*a = c;
|
||||
*b = 0;
|
||||
}
|
||||
ret = true;
|
||||
} else {
|
||||
/* If decomposed to more than two characters, take the last one,
|
||||
* and recompose the rest to get the first component. */
|
||||
U16_PREV_UNSAFE (normalized, len, *b); /* Changes len in-place. */
|
||||
UChar recomposed[18 * 2];
|
||||
icu_err = U_ZERO_ERROR;
|
||||
len = unorm2_normalize (unorm2_getNFCInstance (&icu_err), normalized, len, recomposed, ARRAY_LENGTH (recomposed), &icu_err);
|
||||
if (U_FAILURE (icu_err))
|
||||
return false;
|
||||
/* We expect that recomposed has exactly one character now. */
|
||||
if (unlikely (u_countChar32 (recomposed, len) != 1))
|
||||
return false;
|
||||
U16_GET_UNSAFE (recomposed, 0, *a);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static void free_static_icu_funcs ();
|
||||
#endif
|
||||
|
||||
static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
|
||||
{
|
||||
static hb_unicode_funcs_t *create ()
|
||||
{
|
||||
void *user_data = nullptr;
|
||||
#if U_ICU_VERSION_MAJOR_NUM >= 49
|
||||
UErrorCode icu_err = U_ZERO_ERROR;
|
||||
user_data = (void *) unorm2_getNFCInstance (&icu_err);
|
||||
assert (user_data);
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr);
|
||||
|
||||
hb_unicode_funcs_set_combining_class_func (funcs, hb_icu_unicode_combining_class, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_general_category_func (funcs, hb_icu_unicode_general_category, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_mirroring_func (funcs, hb_icu_unicode_mirroring, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_script_func (funcs, hb_icu_unicode_script, nullptr, nullptr);
|
||||
hb_unicode_funcs_set_compose_func (funcs, hb_icu_unicode_compose, user_data, nullptr);
|
||||
hb_unicode_funcs_set_decompose_func (funcs, hb_icu_unicode_decompose, user_data, nullptr);
|
||||
|
||||
hb_unicode_funcs_make_immutable (funcs);
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
atexit (free_static_icu_funcs);
|
||||
#endif
|
||||
|
||||
return funcs;
|
||||
}
|
||||
} static_icu_funcs;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_icu_funcs ()
|
||||
{
|
||||
static_icu_funcs.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_unicode_funcs_t *
|
||||
hb_icu_get_unicode_funcs ()
|
||||
{
|
||||
return static_icu_funcs.get_unconst ();
|
||||
}
|
||||
|
||||
#ifdef HB_ICU_EXTRA_SEMI_IGNORED
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright © 2009 Red Hat, Inc.
|
||||
* Copyright © 2011 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_ICU_H
|
||||
#define HB_ICU_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
#include <unicode/uscript.h>
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
HB_EXTERN hb_script_t
|
||||
hb_icu_script_to_script (UScriptCode script);
|
||||
|
||||
HB_EXTERN UScriptCode
|
||||
hb_icu_script_from_script (hb_script_t script);
|
||||
|
||||
|
||||
HB_EXTERN hb_unicode_funcs_t *
|
||||
hb_icu_get_unicode_funcs (void);
|
||||
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_ICU_H */
|
||||
|
|
@ -0,0 +1,939 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
* Copyright © 2019 Facebook, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_ITER_HH
|
||||
#define HB_ITER_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-algs.hh"
|
||||
#include "hb-meta.hh"
|
||||
|
||||
|
||||
/* Unified iterator object.
|
||||
*
|
||||
* The goal of this template is to make the same iterator interface
|
||||
* available to all types, and make it very easy and compact to use.
|
||||
* hb_iter_tator objects are small, light-weight, objects that can be
|
||||
* copied by value. If the collection / object being iterated on
|
||||
* is writable, then the iterator returns lvalues, otherwise it
|
||||
* returns rvalues.
|
||||
*
|
||||
* TODO Document more.
|
||||
*
|
||||
* If iterator implementation implements operator!=, then can be
|
||||
* used in range-based for loop. That comes free if the iterator
|
||||
* is random-access. Otherwise, the range-based for loop incurs
|
||||
* one traversal to find end(), which can be avoided if written
|
||||
* as a while-style for loop, or if iterator implements a faster
|
||||
* __end__() method.
|
||||
* TODO When opting in for C++17, address this by changing return
|
||||
* type of .end()?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Base classes for iterators.
|
||||
*/
|
||||
|
||||
/* Base class for all iterators. */
|
||||
template <typename iter_t, typename Item = typename iter_t::__item_t__>
|
||||
struct hb_iter_t
|
||||
{
|
||||
typedef Item item_t;
|
||||
constexpr unsigned get_item_size () const { return hb_static_size (Item); }
|
||||
static constexpr bool is_iterator = true;
|
||||
static constexpr bool is_random_access_iterator = false;
|
||||
static constexpr bool is_sorted_iterator = false;
|
||||
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
|
||||
iter_t* thiz () { return static_cast< iter_t *> (this); }
|
||||
public:
|
||||
|
||||
/* TODO:
|
||||
* Port operators below to use hb_enable_if to sniff which method implements
|
||||
* an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
|
||||
|
||||
/* Operators. */
|
||||
iter_t iter () const { return *thiz(); }
|
||||
iter_t operator + () const { return *thiz(); }
|
||||
iter_t begin () const { return *thiz(); }
|
||||
iter_t end () const { return thiz()->__end__ (); }
|
||||
explicit operator bool () const { return thiz()->__more__ (); }
|
||||
unsigned len () const { return thiz()->__len__ (); }
|
||||
/* The following can only be enabled if item_t is reference type. Otherwise
|
||||
* it will be returning pointer to temporary rvalue.
|
||||
* TODO Use a wrapper return type to fix for non-reference type. */
|
||||
template <typename T = item_t,
|
||||
hb_enable_if (hb_is_reference (T))>
|
||||
hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
|
||||
item_t operator * () const { return thiz()->__item__ (); }
|
||||
item_t operator * () { return thiz()->__item__ (); }
|
||||
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
|
||||
item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
|
||||
iter_t& operator += (unsigned count) & { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () & { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t operator ++ () && { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) & { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t& operator -- () & { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator -- () && { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
|
||||
friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
|
||||
iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
|
||||
iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
|
||||
iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) & { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t& operator << (const T v) & { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
|
||||
protected:
|
||||
hb_iter_t () = default;
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
#define HB_ITER_USING(Name) \
|
||||
using item_t = typename Name::item_t; \
|
||||
using Name::begin; \
|
||||
using Name::end; \
|
||||
using Name::get_item_size; \
|
||||
using Name::is_iterator; \
|
||||
using Name::iter; \
|
||||
using Name::operator bool; \
|
||||
using Name::len; \
|
||||
using Name::operator ->; \
|
||||
using Name::operator *; \
|
||||
using Name::operator []; \
|
||||
using Name::operator +=; \
|
||||
using Name::operator ++; \
|
||||
using Name::operator -=; \
|
||||
using Name::operator --; \
|
||||
using Name::operator +; \
|
||||
using Name::operator -; \
|
||||
using Name::operator >>; \
|
||||
using Name::operator <<; \
|
||||
static_assert (true, "")
|
||||
|
||||
/* Returns iterator / item type of a type. */
|
||||
template <typename Iterable>
|
||||
using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
|
||||
template <typename Iterable>
|
||||
using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
|
||||
|
||||
|
||||
template <typename> struct hb_array_t;
|
||||
template <typename> struct hb_sorted_array_t;
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T> hb_iter_type<T>
|
||||
operator () (T&& c) const
|
||||
{ return hb_deref (hb_forward<T> (c)).iter (); }
|
||||
|
||||
/* Specialization for C arrays. */
|
||||
|
||||
template <typename Type> inline hb_array_t<Type>
|
||||
operator () (Type *array, unsigned int length) const
|
||||
{ return hb_array_t<Type> (array, length); }
|
||||
|
||||
template <typename Type, unsigned int length> hb_array_t<Type>
|
||||
operator () (Type (&array)[length]) const
|
||||
{ return hb_array_t<Type> (array, length); }
|
||||
|
||||
}
|
||||
HB_FUNCOBJ (hb_iter);
|
||||
struct
|
||||
{
|
||||
template <typename T> unsigned
|
||||
operator () (T&& c) const
|
||||
{ return c.len (); }
|
||||
|
||||
}
|
||||
HB_FUNCOBJ (hb_len);
|
||||
|
||||
/* Mixin to fill in what the subclass doesn't provide. */
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
struct hb_iter_fallback_mixin_t
|
||||
{
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
const iter_t* thiz () const { return static_cast<const iter_t *> (this); }
|
||||
iter_t* thiz () { return static_cast< iter_t *> (this); }
|
||||
public:
|
||||
|
||||
/* Access: Implement __item__(), or __item_at__() if random-access. */
|
||||
item_t __item__ () const { return (*thiz())[0]; }
|
||||
item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
|
||||
|
||||
/* Termination: Implement __more__(), or __len__() if random-access. */
|
||||
bool __more__ () const { return bool (thiz()->len ()); }
|
||||
unsigned __len__ () const
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
|
||||
|
||||
/* Advancing: Implement __next__(), or __forward__() if random-access. */
|
||||
void __next__ () { *thiz() += 1; }
|
||||
void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
|
||||
|
||||
/* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
|
||||
void __prev__ () { *thiz() -= 1; }
|
||||
void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
|
||||
|
||||
/* Range-based for: Implement __end__() if can be done faster,
|
||||
* and operator!=. */
|
||||
iter_t __end__ () const
|
||||
{
|
||||
if (thiz()->is_random_access_iterator)
|
||||
return *thiz() + thiz()->len ();
|
||||
/* Above expression loops twice. Following loops once. */
|
||||
auto it = *thiz();
|
||||
while (it) ++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
protected:
|
||||
hb_iter_fallback_mixin_t () = default;
|
||||
hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
struct hb_iter_with_fallback_t :
|
||||
hb_iter_t<iter_t, item_t>,
|
||||
hb_iter_fallback_mixin_t<iter_t, item_t>
|
||||
{
|
||||
protected:
|
||||
hb_iter_with_fallback_t () = default;
|
||||
hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Meta-programming predicates.
|
||||
*/
|
||||
|
||||
/* hb_is_iterator() / hb_is_iterator_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_iterator_of
|
||||
{
|
||||
template <typename Item2 = Item>
|
||||
static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
|
||||
static hb_false_type impl (hb_priority<0>, const void *);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
|
||||
};
|
||||
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
|
||||
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
|
||||
|
||||
/* hb_is_iterable() */
|
||||
|
||||
template <typename T>
|
||||
struct hb_is_iterable
|
||||
{
|
||||
private:
|
||||
|
||||
template <typename U>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
|
||||
|
||||
template <typename>
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
|
||||
|
||||
/* hb_is_source_of() / hb_is_sink_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_source_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_sink_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
|
||||
|
||||
/* This is commonly used, so define: */
|
||||
#define hb_is_sorted_source_of(Iter, Item) \
|
||||
(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
|
||||
|
||||
|
||||
/* Range-based 'for' for iterables. */
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
/* begin()/end() are NOT looked up non-ADL. So each namespace must declare them.
|
||||
* Do it for namespace OT. */
|
||||
namespace OT {
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Adaptors, combiners, etc.
|
||||
*/
|
||||
|
||||
template <typename Lhs, typename Rhs,
|
||||
hb_requires (hb_is_iterator (Lhs))>
|
||||
static inline auto
|
||||
operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
|
||||
|
||||
/* hb_map(), hb_filter(), hb_reduce() */
|
||||
|
||||
enum class hb_function_sortedness_t {
|
||||
NOT_SORTED,
|
||||
RETAINS_SORTING,
|
||||
SORTED,
|
||||
};
|
||||
|
||||
template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_map_iter_t :
|
||||
hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
|
||||
decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
|
||||
{
|
||||
hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
|
||||
|
||||
typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
|
||||
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
|
||||
static constexpr bool is_sorted_iterator =
|
||||
Sorted == hb_function_sortedness_t::SORTED ? true :
|
||||
Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
|
||||
false;
|
||||
__item_t__ __item__ () const { return hb_get (f.get (), *it); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
|
||||
bool __more__ () const { return bool (it); }
|
||||
unsigned __len__ () const { return it.len (); }
|
||||
void __next__ () { ++it; }
|
||||
void __forward__ (unsigned n) { it += n; }
|
||||
void __prev__ () { --it; }
|
||||
void __rewind__ (unsigned n) { it -= n; }
|
||||
hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
|
||||
bool operator != (const hb_map_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
|
||||
template <typename Proj, hb_function_sortedness_t Sorted>
|
||||
struct hb_map_iter_factory_t
|
||||
{
|
||||
hb_map_iter_factory_t (Proj f) : f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_map_iter_t<Iter, Proj, Sorted>
|
||||
operator () (Iter it)
|
||||
{ return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
|
||||
|
||||
private:
|
||||
Proj f;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_retains_sorting);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_sorted);
|
||||
|
||||
template <typename Iter, typename Pred, typename Proj,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_filter_iter_t :
|
||||
hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
|
||||
typename Iter::item_t>
|
||||
{
|
||||
hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
|
||||
{ while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
|
||||
|
||||
typedef typename Iter::item_t __item_t__;
|
||||
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
|
||||
__item_t__ __item__ () const { return *it; }
|
||||
bool __more__ () const { return bool (it); }
|
||||
void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
|
||||
bool operator != (const hb_filter_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
hb_reference_wrapper<Pred> p;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
template <typename Pred, typename Proj>
|
||||
struct hb_filter_iter_factory_t
|
||||
{
|
||||
hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_filter_iter_t<Iter, Pred, Proj>
|
||||
operator () (Iter it)
|
||||
{ return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
|
||||
|
||||
private:
|
||||
Pred p;
|
||||
Proj f;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity))>
|
||||
hb_filter_iter_factory_t<Pred, Proj>
|
||||
operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
|
||||
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_filter);
|
||||
|
||||
template <typename Redu, typename InitT>
|
||||
struct hb_reduce_t
|
||||
{
|
||||
hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter)),
|
||||
typename AccuT = hb_decay<decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>>
|
||||
AccuT
|
||||
operator () (Iter it)
|
||||
{
|
||||
AccuT value = init_value;
|
||||
for (; it; ++it)
|
||||
value = r (value, *it);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Redu r;
|
||||
InitT init_value;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Redu, typename InitT>
|
||||
hb_reduce_t<Redu, InitT>
|
||||
operator () (Redu&& r, InitT init_value) const
|
||||
{ return hb_reduce_t<Redu, InitT> (r, init_value); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_reduce);
|
||||
|
||||
|
||||
/* hb_zip() */
|
||||
|
||||
template <typename A, typename B>
|
||||
struct hb_zip_iter_t :
|
||||
hb_iter_t<hb_zip_iter_t<A, B>,
|
||||
hb_pair_t<typename A::item_t, typename B::item_t>>
|
||||
{
|
||||
hb_zip_iter_t () {}
|
||||
hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
|
||||
|
||||
typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
|
||||
static constexpr bool is_random_access_iterator =
|
||||
A::is_random_access_iterator &&
|
||||
B::is_random_access_iterator;
|
||||
/* Note. The following categorization is only valid if A is strictly sorted,
|
||||
* ie. does NOT have duplicates. Previously I tried to categorize sortedness
|
||||
* more granularly, see commits:
|
||||
*
|
||||
* 513762849a683914fc266a17ddf38f133cccf072
|
||||
* 4d3cf2adb669c345cc43832d11689271995e160a
|
||||
*
|
||||
* However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
|
||||
* SortedArrayOf, etc all needed to be updated to add more variants. At that
|
||||
* point I saw it not worth the effort, and instead we now deem all sorted
|
||||
* collections as essentially strictly-sorted for the purposes of zip.
|
||||
*
|
||||
* The above assumption is not as bad as it sounds. Our "sorted" comes with
|
||||
* no guarantees. It's just a contract, put in place to help you remember,
|
||||
* and think about, whether an iterator you receive is expected to be
|
||||
* sorted or not. As such, it's not perfect by definition, and should not
|
||||
* be treated so. The inaccuracy here just errs in the direction of being
|
||||
* more permissive, so your code compiles instead of erring on the side of
|
||||
* marking your zipped iterator unsorted in which case your code won't
|
||||
* compile.
|
||||
*
|
||||
* This semantical limitation does NOT affect logic in any other place I
|
||||
* know of as of this writing.
|
||||
*/
|
||||
static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
|
||||
|
||||
__item_t__ __item__ () const { return __item_t__ (*a, *b); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
|
||||
bool __more__ () const { return bool (a) && bool (b); }
|
||||
unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
|
||||
void __next__ () { ++a; ++b; }
|
||||
void __forward__ (unsigned n) { a += n; b += n; }
|
||||
void __prev__ () { --a; --b; }
|
||||
void __rewind__ (unsigned n) { a -= n; b -= n; }
|
||||
hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
|
||||
/* Note, we should stop if ANY of the iters reaches end. As such two compare
|
||||
* unequal if both items are unequal, NOT if either is unequal. */
|
||||
bool operator != (const hb_zip_iter_t& o) const
|
||||
{ return a != o.a && b != o.b; }
|
||||
|
||||
private:
|
||||
A a;
|
||||
B b;
|
||||
};
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename A, typename B,
|
||||
hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
|
||||
hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
|
||||
operator () (A&& a, B&& b) const
|
||||
{ return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_zip);
|
||||
|
||||
/* hb_apply() */
|
||||
|
||||
template <typename Appl>
|
||||
struct hb_apply_t
|
||||
{
|
||||
hb_apply_t (Appl a) : a (a) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) hb_invoke (a, *it);
|
||||
}
|
||||
|
||||
private:
|
||||
Appl a;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Appl> hb_apply_t<Appl>
|
||||
operator () (Appl&& a) const
|
||||
{ return hb_apply_t<Appl> (a); }
|
||||
|
||||
template <typename Appl> hb_apply_t<Appl&>
|
||||
operator () (Appl *a) const
|
||||
{ return hb_apply_t<Appl&> (*a); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_apply);
|
||||
|
||||
/* hb_range()/hb_iota()/hb_repeat() */
|
||||
|
||||
template <typename T, typename S>
|
||||
struct hb_range_iter_t :
|
||||
hb_iter_t<hb_range_iter_t<T, S>, T>
|
||||
{
|
||||
hb_range_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return hb_ridentity (v); }
|
||||
__item_t__ __item_at__ (unsigned j) const { return v + j * step; }
|
||||
bool __more__ () const { return v != end_; }
|
||||
unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
|
||||
void __next__ () { v += step; }
|
||||
void __forward__ (unsigned n) { v += n * step; }
|
||||
void __prev__ () { v -= step; }
|
||||
void __rewind__ (unsigned n) { v -= n * step; }
|
||||
hb_range_iter_t __end__ () const { return hb_range_iter_t (end_, end_, step); }
|
||||
bool operator != (const hb_range_iter_t& o) const
|
||||
{ return v != o.v; }
|
||||
|
||||
private:
|
||||
static inline T end_for (T start, T end_, S step)
|
||||
{
|
||||
if (!step)
|
||||
return end_;
|
||||
auto res = (end_ - start) % step;
|
||||
if (!res)
|
||||
return end_;
|
||||
end_ += step - res;
|
||||
return end_;
|
||||
}
|
||||
|
||||
private:
|
||||
T v;
|
||||
T end_;
|
||||
S step;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned> hb_range_iter_t<T, unsigned>
|
||||
operator () (T end = (unsigned) -1) const
|
||||
{ return hb_range_iter_t<T, unsigned> (0, end, 1u); }
|
||||
|
||||
template <typename T, typename S = unsigned> hb_range_iter_t<T, S>
|
||||
operator () (T start, T end, S step = 1u) const
|
||||
{ return hb_range_iter_t<T, S> (start, end, step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_range);
|
||||
|
||||
template <typename T, typename S>
|
||||
struct hb_iota_iter_t :
|
||||
hb_iter_with_fallback_t<hb_iota_iter_t<T, S>, T>
|
||||
{
|
||||
hb_iota_iter_t (T start, S step) : v (start), step (step) {}
|
||||
|
||||
private:
|
||||
|
||||
template <typename S2 = S>
|
||||
auto
|
||||
inc (hb_type_identity<S2> s, hb_priority<1>)
|
||||
-> hb_void_t<decltype (hb_invoke (hb_forward<S2> (s), hb_declval<T&> ()))>
|
||||
{ v = hb_invoke (hb_forward<S2> (s), v); }
|
||||
|
||||
void
|
||||
inc (S s, hb_priority<0>)
|
||||
{ v += s; }
|
||||
|
||||
public:
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return hb_ridentity (v); }
|
||||
bool __more__ () const { return true; }
|
||||
unsigned __len__ () const { return UINT_MAX; }
|
||||
void __next__ () { inc (step, hb_prioritize); }
|
||||
void __prev__ () { v -= step; }
|
||||
hb_iota_iter_t __end__ () const { return *this; }
|
||||
bool operator != (const hb_iota_iter_t& o) const { return true; }
|
||||
|
||||
private:
|
||||
T v;
|
||||
S step;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned, typename S = unsigned> hb_iota_iter_t<T, S>
|
||||
operator () (T start = 0u, S step = 1u) const
|
||||
{ return hb_iota_iter_t<T, S> (start, step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_iota);
|
||||
|
||||
template <typename T>
|
||||
struct hb_repeat_iter_t :
|
||||
hb_iter_t<hb_repeat_iter_t<T>, T>
|
||||
{
|
||||
hb_repeat_iter_t (T value) : v (value) {}
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return v; }
|
||||
__item_t__ __item_at__ (unsigned j) const { return v; }
|
||||
bool __more__ () const { return true; }
|
||||
unsigned __len__ () const { return UINT_MAX; }
|
||||
void __next__ () {}
|
||||
void __forward__ (unsigned) {}
|
||||
void __prev__ () {}
|
||||
void __rewind__ (unsigned) {}
|
||||
hb_repeat_iter_t __end__ () const { return *this; }
|
||||
bool operator != (const hb_repeat_iter_t& o) const { return true; }
|
||||
|
||||
private:
|
||||
T v;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T> hb_repeat_iter_t<T>
|
||||
operator () (T value) const
|
||||
{ return hb_repeat_iter_t<T> (value); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_repeat);
|
||||
|
||||
/* hb_enumerate()/hb_take() */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Index = unsigned,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
|
||||
( hb_zip (hb_iota (start), it) )
|
||||
}
|
||||
HB_FUNCOBJ (hb_enumerate);
|
||||
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
|
||||
( hb_zip (hb_range (count), it) | hb_map (hb_second) )
|
||||
|
||||
/* Specialization arrays. */
|
||||
|
||||
template <typename Type> inline hb_array_t<Type>
|
||||
operator () (hb_array_t<Type> array, unsigned count) const
|
||||
{ return array.sub_array (0, count); }
|
||||
|
||||
template <typename Type> inline hb_sorted_array_t<Type>
|
||||
operator () (hb_sorted_array_t<Type> array, unsigned count) const
|
||||
{ return array.sub_array (0, count); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_take);
|
||||
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
auto operator () (Iter it, unsigned count) const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_iota (it, hb_add (count))
|
||||
| hb_map (hb_take (count))
|
||||
| hb_take ((hb_len (it) + count - 1) / count)
|
||||
)
|
||||
}
|
||||
HB_FUNCOBJ (hb_chop);
|
||||
|
||||
/* hb_sink() */
|
||||
|
||||
template <typename Sink>
|
||||
struct hb_sink_t
|
||||
{
|
||||
hb_sink_t (Sink s) : s (s) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
s << *it;
|
||||
}
|
||||
|
||||
private:
|
||||
Sink s;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Sink> hb_sink_t<Sink>
|
||||
operator () (Sink&& s) const
|
||||
{ return hb_sink_t<Sink> (s); }
|
||||
|
||||
template <typename Sink> hb_sink_t<Sink&>
|
||||
operator () (Sink *s) const
|
||||
{ return hb_sink_t<Sink&> (*s); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_sink);
|
||||
|
||||
/* hb-drain: hb_sink to void / blackhole / /dev/null. */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it) const
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) *it;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_drain);
|
||||
|
||||
/* hb_unzip(): unzip and sink to two sinks. */
|
||||
|
||||
template <typename Sink1, typename Sink2>
|
||||
struct hb_unzip_t
|
||||
{
|
||||
hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
{
|
||||
const auto &v = *it;
|
||||
s1 << v.first;
|
||||
s2 << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Sink1 s1;
|
||||
Sink2 s2;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Sink1, typename Sink2> hb_unzip_t<Sink1, Sink2>
|
||||
operator () (Sink1&& s1, Sink2&& s2) const
|
||||
{ return hb_unzip_t<Sink1, Sink2> (s1, s2); }
|
||||
|
||||
template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
|
||||
operator () (Sink1 *s1, Sink2 *s2) const
|
||||
{ return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_unzip);
|
||||
|
||||
|
||||
/* hb-all, hb-any, hb-none. */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_all);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_any);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_none);
|
||||
|
||||
/*
|
||||
* Algorithms operating on iterators.
|
||||
*/
|
||||
|
||||
template <typename C, typename V,
|
||||
hb_requires (hb_is_iterable (C))>
|
||||
inline void
|
||||
hb_fill (C& c, const V &v)
|
||||
{
|
||||
for (auto i = hb_iter (c); i; i++)
|
||||
*i = v;
|
||||
}
|
||||
|
||||
template <typename S, typename D>
|
||||
inline void
|
||||
hb_copy (S&& is, D&& id)
|
||||
{
|
||||
hb_iter (is) | hb_sink (id);
|
||||
}
|
||||
|
||||
|
||||
#endif /* HB_ITER_HH */
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright © 2017 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_KERN_HH
|
||||
#define HB_KERN_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-ot-layout-gpos-table.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
||||
template <typename Driver>
|
||||
struct hb_kern_machine_t
|
||||
{
|
||||
hb_kern_machine_t (const Driver &driver_,
|
||||
bool crossStream_ = false) :
|
||||
driver (driver_),
|
||||
crossStream (crossStream_) {}
|
||||
|
||||
HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW
|
||||
void kern (hb_font_t *font,
|
||||
hb_buffer_t *buffer,
|
||||
hb_mask_t kern_mask,
|
||||
bool scale = true) const
|
||||
{
|
||||
OT::hb_ot_apply_context_t c (1, font, buffer);
|
||||
c.set_lookup_mask (kern_mask);
|
||||
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
|
||||
OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
|
||||
skippy_iter.init (&c);
|
||||
|
||||
bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
|
||||
unsigned int count = buffer->len;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
hb_glyph_position_t *pos = buffer->pos;
|
||||
for (unsigned int idx = 0; idx < count;)
|
||||
{
|
||||
if (!(info[idx].mask & kern_mask))
|
||||
{
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
skippy_iter.reset (idx, 1);
|
||||
if (!skippy_iter.next ())
|
||||
{
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int i = idx;
|
||||
unsigned int j = skippy_iter.idx;
|
||||
|
||||
hb_position_t kern = driver.get_kerning (info[i].codepoint,
|
||||
info[j].codepoint);
|
||||
|
||||
|
||||
if (likely (!kern))
|
||||
goto skip;
|
||||
|
||||
if (horizontal)
|
||||
{
|
||||
if (scale)
|
||||
kern = font->em_scale_x (kern);
|
||||
if (crossStream)
|
||||
{
|
||||
pos[j].y_offset = kern;
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_position_t kern1 = kern >> 1;
|
||||
hb_position_t kern2 = kern - kern1;
|
||||
pos[i].x_advance += kern1;
|
||||
pos[j].x_advance += kern2;
|
||||
pos[j].x_offset += kern2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (scale)
|
||||
kern = font->em_scale_y (kern);
|
||||
if (crossStream)
|
||||
{
|
||||
pos[j].x_offset = kern;
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_position_t kern1 = kern >> 1;
|
||||
hb_position_t kern2 = kern - kern1;
|
||||
pos[i].y_advance += kern1;
|
||||
pos[j].y_advance += kern2;
|
||||
pos[j].y_offset += kern2;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->unsafe_to_break (i, j + 1);
|
||||
|
||||
skip:
|
||||
idx = skippy_iter.idx;
|
||||
}
|
||||
}
|
||||
|
||||
const Driver &driver;
|
||||
bool crossStream;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
||||
#endif /* HB_KERN_HH */
|
||||
|
|
@ -0,0 +1,323 @@
|
|||
/*
|
||||
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
||||
* Copyright © 2012,2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_MACHINERY_HH
|
||||
#define HB_MACHINERY_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-blob.hh"
|
||||
|
||||
#include "hb-dispatch.hh"
|
||||
#include "hb-sanitize.hh"
|
||||
#include "hb-serialize.hh"
|
||||
|
||||
|
||||
/*
|
||||
* Casts
|
||||
*/
|
||||
|
||||
/* Cast to struct T, reference to reference */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type& CastR(const TObject &X)
|
||||
{ return reinterpret_cast<const Type&> (X); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type& CastR(TObject &X)
|
||||
{ return reinterpret_cast<Type&> (X); }
|
||||
|
||||
/* Cast to struct T, pointer to pointer */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type* CastP(const TObject *X)
|
||||
{ return reinterpret_cast<const Type*> (X); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type* CastP(TObject *X)
|
||||
{ return reinterpret_cast<Type*> (X); }
|
||||
|
||||
/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
|
||||
* location pointed to by P plus Ofs bytes. */
|
||||
template<typename Type>
|
||||
static inline const Type& StructAtOffset(const void *P, unsigned int offset)
|
||||
{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
|
||||
template<typename Type>
|
||||
static inline Type& StructAtOffset(void *P, unsigned int offset)
|
||||
{ return * reinterpret_cast<Type*> ((char *) P + offset); }
|
||||
template<typename Type>
|
||||
static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int offset)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
return * reinterpret_cast<Type*> ((char *) P + offset);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
template<typename Type>
|
||||
static inline Type& StructAtOffsetUnaligned(void *P, unsigned int offset)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
return * reinterpret_cast<Type*> ((char *) P + offset);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
/* StructAfter<T>(X) returns the struct T& that is placed after X.
|
||||
* Works with X of variable size also. X must implement get_size() */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type& StructAfter(const TObject &X)
|
||||
{ return StructAtOffset<Type>(&X, X.get_size()); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type& StructAfter(TObject &X)
|
||||
{ return StructAtOffset<Type>(&X, X.get_size()); }
|
||||
|
||||
|
||||
/*
|
||||
* Size checking
|
||||
*/
|
||||
|
||||
/* Check _assertion in a method environment */
|
||||
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
|
||||
void _instance_assertion_on_line_##_line () const \
|
||||
{ static_assert ((_assertion), ""); }
|
||||
# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
|
||||
# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
|
||||
|
||||
/* Check that _code compiles in a method environment */
|
||||
#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
|
||||
void _compiles_assertion_on_line_##_line () const \
|
||||
{ _code; }
|
||||
# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
|
||||
# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
|
||||
|
||||
|
||||
#define DEFINE_SIZE_STATIC(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)) \
|
||||
unsigned int get_size () const { return (size); } \
|
||||
static constexpr unsigned null_size = (size); \
|
||||
static constexpr unsigned min_size = (size); \
|
||||
static constexpr unsigned static_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_UNION(size, _member) \
|
||||
DEFINE_COMPILES_ASSERTION ((void) this->u._member.static_size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof(this->u._member) == (size)) \
|
||||
static constexpr unsigned null_size = (size); \
|
||||
static constexpr unsigned min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_MIN(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \
|
||||
static constexpr unsigned null_size = (size); \
|
||||
static constexpr unsigned min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_UNBOUNDED(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)) \
|
||||
static constexpr unsigned min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY(size, array) \
|
||||
DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + HB_VAR_ARRAY * sizeof ((array)[0])) \
|
||||
static constexpr unsigned null_size = (size); \
|
||||
static constexpr unsigned min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY_SIZED(size, array) \
|
||||
unsigned int get_size () const { return (size - (array).min_size + (array).get_size ()); } \
|
||||
DEFINE_SIZE_ARRAY(size, array)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Lazy loaders.
|
||||
*/
|
||||
|
||||
template <typename Data, unsigned int WheresData>
|
||||
struct hb_data_wrapper_t
|
||||
{
|
||||
static_assert (WheresData > 0, "");
|
||||
|
||||
Data * get_data () const
|
||||
{ return *(((Data **) (void *) this) - WheresData); }
|
||||
|
||||
bool is_inert () const { return !get_data (); }
|
||||
|
||||
template <typename Stored, typename Subclass>
|
||||
Stored * call_create () const { return Subclass::create (get_data ()); }
|
||||
};
|
||||
template <>
|
||||
struct hb_data_wrapper_t<void, 0>
|
||||
{
|
||||
bool is_inert () const { return false; }
|
||||
|
||||
template <typename Stored, typename Funcs>
|
||||
Stored * call_create () const { return Funcs::create (); }
|
||||
};
|
||||
|
||||
template <typename T1, typename T2> struct hb_non_void_t { typedef T1 value; };
|
||||
template <typename T2> struct hb_non_void_t<void, T2> { typedef T2 value; };
|
||||
|
||||
template <typename Returned,
|
||||
typename Subclass = void,
|
||||
typename Data = void,
|
||||
unsigned int WheresData = 0,
|
||||
typename Stored = Returned>
|
||||
struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
||||
{
|
||||
typedef typename hb_non_void_t<Subclass,
|
||||
hb_lazy_loader_t<Returned,Subclass,Data,WheresData,Stored>
|
||||
>::value Funcs;
|
||||
|
||||
void init0 () {} /* Init, when memory is already set to 0. No-op for us. */
|
||||
void init () { instance.set_relaxed (nullptr); }
|
||||
void fini () { do_destroy (instance.get ()); }
|
||||
|
||||
void free_instance ()
|
||||
{
|
||||
retry:
|
||||
Stored *p = instance.get ();
|
||||
if (unlikely (p && !cmpexch (p, nullptr)))
|
||||
goto retry;
|
||||
do_destroy (p);
|
||||
}
|
||||
|
||||
static void do_destroy (Stored *p)
|
||||
{
|
||||
if (p && p != const_cast<Stored *> (Funcs::get_null ()))
|
||||
Funcs::destroy (p);
|
||||
}
|
||||
|
||||
const Returned * operator -> () const { return get (); }
|
||||
const Returned & operator * () const { return *get (); }
|
||||
explicit operator bool () const
|
||||
{ return get_stored () != Funcs::get_null (); }
|
||||
template <typename C> operator const C * () const { return get (); }
|
||||
|
||||
Stored * get_stored () const
|
||||
{
|
||||
retry:
|
||||
Stored *p = this->instance.get ();
|
||||
if (unlikely (!p))
|
||||
{
|
||||
if (unlikely (this->is_inert ()))
|
||||
return const_cast<Stored *> (Funcs::get_null ());
|
||||
|
||||
p = this->template call_create<Stored, Funcs> ();
|
||||
if (unlikely (!p))
|
||||
p = const_cast<Stored *> (Funcs::get_null ());
|
||||
|
||||
if (unlikely (!cmpexch (nullptr, p)))
|
||||
{
|
||||
do_destroy (p);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
Stored * get_stored_relaxed () const
|
||||
{
|
||||
return this->instance.get_relaxed ();
|
||||
}
|
||||
|
||||
bool cmpexch (Stored *current, Stored *value) const
|
||||
{
|
||||
/* This *must* be called when there are no other threads accessing. */
|
||||
return this->instance.cmpexch (current, value);
|
||||
}
|
||||
|
||||
const Returned * get () const { return Funcs::convert (get_stored ()); }
|
||||
const Returned * get_relaxed () const { return Funcs::convert (get_stored_relaxed ()); }
|
||||
Returned * get_unconst () const { return const_cast<Returned *> (Funcs::convert (get_stored ())); }
|
||||
|
||||
/* To be possibly overloaded by subclasses. */
|
||||
static Returned* convert (Stored *p) { return p; }
|
||||
|
||||
/* By default null/init/fini the object. */
|
||||
static const Stored* get_null () { return &Null(Stored); }
|
||||
static Stored *create (Data *data)
|
||||
{
|
||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
||||
if (likely (p))
|
||||
p->init (data);
|
||||
return p;
|
||||
}
|
||||
static Stored *create ()
|
||||
{
|
||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
||||
if (likely (p))
|
||||
p->init ();
|
||||
return p;
|
||||
}
|
||||
static void destroy (Stored *p)
|
||||
{
|
||||
p->fini ();
|
||||
free (p);
|
||||
}
|
||||
|
||||
// private:
|
||||
/* Must only have one pointer. */
|
||||
hb_atomic_ptr_t<Stored *> instance;
|
||||
};
|
||||
|
||||
/* Specializations. */
|
||||
|
||||
template <typename T, unsigned int WheresFace>
|
||||
struct hb_face_lazy_loader_t : hb_lazy_loader_t<T,
|
||||
hb_face_lazy_loader_t<T, WheresFace>,
|
||||
hb_face_t, WheresFace> {};
|
||||
|
||||
template <typename T, unsigned int WheresFace>
|
||||
struct hb_table_lazy_loader_t : hb_lazy_loader_t<T,
|
||||
hb_table_lazy_loader_t<T, WheresFace>,
|
||||
hb_face_t, WheresFace,
|
||||
hb_blob_t>
|
||||
{
|
||||
static hb_blob_t *create (hb_face_t *face)
|
||||
{ return hb_sanitize_context_t ().reference_table<T> (face); }
|
||||
static void destroy (hb_blob_t *p) { hb_blob_destroy (p); }
|
||||
|
||||
static const hb_blob_t *get_null ()
|
||||
{ return hb_blob_get_empty (); }
|
||||
|
||||
static const T* convert (const hb_blob_t *blob)
|
||||
{ return blob->as<T> (); }
|
||||
|
||||
hb_blob_t* get_blob () const { return this->get_stored (); }
|
||||
};
|
||||
|
||||
template <typename Subclass>
|
||||
struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t<hb_font_funcs_t, Subclass>
|
||||
{
|
||||
static void destroy (hb_font_funcs_t *p)
|
||||
{ hb_font_funcs_destroy (p); }
|
||||
static const hb_font_funcs_t *get_null ()
|
||||
{ return hb_font_funcs_get_empty (); }
|
||||
};
|
||||
template <typename Subclass>
|
||||
struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t<hb_unicode_funcs_t, Subclass>
|
||||
{
|
||||
static void destroy (hb_unicode_funcs_t *p)
|
||||
{ hb_unicode_funcs_destroy (p); }
|
||||
static const hb_unicode_funcs_t *get_null ()
|
||||
{ return hb_unicode_funcs_get_empty (); }
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_MACHINERY_HH */
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-map.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-map
|
||||
* @title: hb-map
|
||||
* @short_description: Object representing integer to integer mapping
|
||||
* @include: hb.h
|
||||
*
|
||||
* Map objects are integer-to-integer hash-maps. Currently they are
|
||||
* not used in the HarfBuzz public API, but are provided for client's
|
||||
* use if desired.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
* hb_map_create: (Xconstructor)
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_map_t *
|
||||
hb_map_create ()
|
||||
{
|
||||
hb_map_t *map;
|
||||
|
||||
if (!(map = hb_object_create<hb_map_t> ()))
|
||||
return hb_map_get_empty ();
|
||||
|
||||
map->init_shallow ();
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_get_empty:
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_map_t *
|
||||
hb_map_get_empty ()
|
||||
{
|
||||
return const_cast<hb_map_t *> (&Null(hb_map_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_reference: (skip)
|
||||
* @map: a map.
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_map_t *
|
||||
hb_map_reference (hb_map_t *map)
|
||||
{
|
||||
return hb_object_reference (map);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_destroy: (skip)
|
||||
* @map: a map.
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
void
|
||||
hb_map_destroy (hb_map_t *map)
|
||||
{
|
||||
if (!hb_object_destroy (map)) return;
|
||||
|
||||
map->fini_shallow ();
|
||||
|
||||
free (map);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_set_user_data: (skip)
|
||||
* @map: a map.
|
||||
* @key:
|
||||
* @data:
|
||||
* @destroy:
|
||||
* @replace:
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_map_set_user_data (hb_map_t *map,
|
||||
hb_user_data_key_t *key,
|
||||
void * data,
|
||||
hb_destroy_func_t destroy,
|
||||
hb_bool_t replace)
|
||||
{
|
||||
return hb_object_set_user_data (map, key, data, destroy, replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_get_user_data: (skip)
|
||||
* @map: a map.
|
||||
* @key:
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
void *
|
||||
hb_map_get_user_data (hb_map_t *map,
|
||||
hb_user_data_key_t *key)
|
||||
{
|
||||
return hb_object_get_user_data (map, key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_map_allocation_successful:
|
||||
* @map: a map.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_map_allocation_successful (const hb_map_t *map)
|
||||
{
|
||||
return map->successful;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_map_set:
|
||||
* @map: a map.
|
||||
* @key:
|
||||
* @value:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
void
|
||||
hb_map_set (hb_map_t *map,
|
||||
hb_codepoint_t key,
|
||||
hb_codepoint_t value)
|
||||
{
|
||||
map->set (key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_get:
|
||||
* @map: a map.
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_codepoint_t
|
||||
hb_map_get (const hb_map_t *map,
|
||||
hb_codepoint_t key)
|
||||
{
|
||||
return map->get (key);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_del:
|
||||
* @map: a map.
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
void
|
||||
hb_map_del (hb_map_t *map,
|
||||
hb_codepoint_t key)
|
||||
{
|
||||
map->del (key);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_has:
|
||||
* @map: a map.
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_map_has (const hb_map_t *map,
|
||||
hb_codepoint_t key)
|
||||
{
|
||||
return map->has (key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_map_clear:
|
||||
* @map: a map.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
void
|
||||
hb_map_clear (hb_map_t *map)
|
||||
{
|
||||
return map->clear ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_is_empty:
|
||||
* @map: a map.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_map_is_empty (const hb_map_t *map)
|
||||
{
|
||||
return map->is_empty ();
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_map_get_population:
|
||||
* @map: a map.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
unsigned int
|
||||
hb_map_get_population (const hb_map_t *map)
|
||||
{
|
||||
return map->get_population ();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue