From 06b914390d92349958b858de662f18652891341e Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Tue, 14 Jul 2015 16:28:52 +0200 Subject: [PATCH 1/3] Extend CMake build system for usage of ICU --- CMakeLists.txt | 10 ++ Makefile.am | 1 + cmake/modules/FindICU.cmake | 314 ++++++++++++++++++++++++++++++++++++++++++++ config.h.cmake | 3 + 4 files changed, 328 insertions(+) create mode 100644 cmake/modules/FindICU.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index bfd374c..c2cee28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(ENABLE_LIBOPENJPEG "auto" CACHE STRING "Use libopenjpeg for JPX streams. Pos set(ENABLE_CMS "auto" CACHE STRING "Use color management system. Possible values: auto, lcms1, lcms2. 'auto' prefers lcms2 over lcms1 if both are available. Unset to disable color management system.") option(ENABLE_LIBCURL "Build libcurl based HTTP support." OFF) option(ENABLE_ZLIB "Build with zlib (not totally safe)." OFF) +option(ENABLE_ICU "Build with icu" ON) option(SPLASH_CMYK "Include support for CMYK rasterization." OFF) option(USE_FIXEDPOINT "Use fixed point arithmetic in the Splash backend" OFF) option(USE_FLOAT "Use single precision arithmetic in the Splash backend" OFF) @@ -157,6 +158,11 @@ if(ENABLE_ZLIB) endif(ZLIB_FOUND) set(ENABLE_ZLIB ${ZLIB_FOUND}) endif(ENABLE_ZLIB) +if(ENABLE_ICU) + macro_optional_find_package(ICU) + set(ENABLE_ICU ${ICU_FOUND}) + set(HAVE_ICU ${ICU_FOUND}) +endif(ENABLE_ICU) set(USE_OPENJPEG1 FALSE) set(USE_OPENJPEG2 FALSE) set(WITH_OPENJPEG FALSE) @@ -423,6 +429,9 @@ if(ENABLE_ZLIB) ) set(poppler_LIBS ${poppler_LIBS} ${ZLIB_LIBRARIES}) endif(ENABLE_ZLIB) +if(ENABLE_ICU) + set(poppler_LIBS ${poppler_LIBS} ${ICU_LIBRARIES}) +endif(ENABLE_ICU) if(ENABLE_LIBCURL) set(poppler_SRCS ${poppler_SRCS} poppler/CurlCachedFile.cc @@ -718,6 +727,7 @@ show_end_message_yesno("use libjpeg" ENABLE_LIBJPEG) show_end_message_yesno("use libpng" ENABLE_LIBPNG) show_end_message_yesno("use libtiff" ENABLE_LIBTIFF) show_end_message_yesno("use zlib" ENABLE_ZLIB) +show_end_message_yesno("use icu" ENABLE_ICU) show_end_message_yesno("use curl" ENABLE_LIBCURL) show_end_message_yesno("use libopenjpeg" WITH_OPENJPEG) if(USE_OPENJPEG1) diff --git a/Makefile.am b/Makefile.am index 691512f..7c8bd10 100644 --- a/Makefile.am +++ b/Makefile.am @@ -97,6 +97,7 @@ EXTRA_DIST += \ cmake/modules/PopplerDefaults.cmake \ cmake/modules/PopplerMacros.cmake \ cmake/modules/FindLIBOPENJPEG.cmake \ + cmake/modules/FindICU.cmake \ config.h.cmake \ poppler-cairo.pc.cmake \ poppler/poppler-config.h.cmake \ diff --git a/cmake/modules/FindICU.cmake b/cmake/modules/FindICU.cmake new file mode 100644 index 0000000..cd6bf92 --- /dev/null +++ b/cmake/modules/FindICU.cmake @@ -0,0 +1,314 @@ +# This module can find the International Components for Unicode (ICU) Library +# +# Requirements: +# - CMake >= 2.8.3 (for new version of find_package_handle_standard_args) +# +# The following variables will be defined for your use: +# - ICU_FOUND : were all of your specified components found (include dependencies)? +# - ICU_INCLUDE_DIRS : ICU include directory +# - ICU_LIBRARIES : ICU libraries +# - ICU_VERSION : complete version of ICU (x.y.z) +# - ICU_MAJOR_VERSION : major version of ICU +# - ICU_MINOR_VERSION : minor version of ICU +# - ICU_PATCH_VERSION : patch version of ICU +# - ICU__FOUND : were found? (FALSE for non specified component if it is not a dependency) +# +# For windows or non standard installation, define ICU_ROOT variable to point to the root installation of ICU. Two ways: +# - run cmake with -DICU_ROOT= +# - define an environment variable with the same name before running cmake +# With cmake-gui, before pressing "Configure": +# 1) Press "Add Entry" button +# 2) Add a new entry defined as: +# - Name: ICU_ROOT +# - Type: choose PATH in the selection list +# - Press "..." button and select the root installation of ICU +# +# Example Usage: +# +# 1. Copy this file in the root of your project source directory +# 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt: +# set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}) +# 3. Finally call find_package() once, here are some examples to pick from +# +# Require ICU 4.4 or later +# find_package(ICU 4.4 REQUIRED) +# +# if(ICU_FOUND) +# include_directories(${ICU_INCLUDE_DIRS}) +# add_executable(myapp myapp.c) +# target_link_libraries(myapp ${ICU_LIBRARIES}) +# endif(ICU_FOUND) + +#============================================================================= +# Copyright (c) 2011-2013, julp +# +# Distributed under the OSI-approved BSD License +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +#============================================================================= + +find_package(PkgConfig QUIET) + +########## Private ########## +if(NOT DEFINED ICU_PUBLIC_VAR_NS) + set(ICU_PUBLIC_VAR_NS "ICU") # Prefix for all ICU relative public variables +endif(NOT DEFINED ICU_PUBLIC_VAR_NS) +if(NOT DEFINED ICU_PRIVATE_VAR_NS) + set(ICU_PRIVATE_VAR_NS "_${ICU_PUBLIC_VAR_NS}") # Prefix for all ICU relative internal variables +endif(NOT DEFINED ICU_PRIVATE_VAR_NS) +if(NOT DEFINED PC_ICU_PRIVATE_VAR_NS) + set(PC_ICU_PRIVATE_VAR_NS "_PC${ICU_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables +endif(NOT DEFINED PC_ICU_PRIVATE_VAR_NS) + +function(icudebug _VARNAME) + if(${ICU_PUBLIC_VAR_NS}_DEBUG) + if(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME}) + message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ${${ICU_PUBLIC_VAR_NS}_${_VARNAME}}") + else(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME}) + message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ") + endif(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME}) + endif(${ICU_PUBLIC_VAR_NS}_DEBUG) +endfunction(icudebug) + +set(${ICU_PRIVATE_VAR_NS}_ROOT "") +if(DEFINED ENV{ICU_ROOT}) + set(${ICU_PRIVATE_VAR_NS}_ROOT "$ENV{ICU_ROOT}") +endif(DEFINED ENV{ICU_ROOT}) +if (DEFINED ICU_ROOT) + set(${ICU_PRIVATE_VAR_NS}_ROOT "${ICU_ROOT}") +endif(DEFINED ICU_ROOT) + +set(${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES ) +set(${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES ) +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin64") + list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib64") +endif(CMAKE_SIZEOF_VOID_P EQUAL 8) +list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin") +list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib") + +set(${ICU_PRIVATE_VAR_NS}_COMPONENTS ) +# ... +macro(icu_declare_component _NAME) + list(APPEND ${ICU_PRIVATE_VAR_NS}_COMPONENTS ${_NAME}) + set("${ICU_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN}) +endmacro(icu_declare_component) + +icu_declare_component(data icudata) +icu_declare_component(uc icuuc) # Common and Data libraries +icu_declare_component(i18n icui18n icuin) # Internationalization library +icu_declare_component(io icuio ustdio) # Stream and I/O Library +icu_declare_component(le icule) # Layout library +icu_declare_component(lx iculx) # Paragraph Layout library + +########## Public ########## +set(${ICU_PUBLIC_VAR_NS}_FOUND TRUE) +set(${ICU_PUBLIC_VAR_NS}_LIBRARIES ) +set(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS ) +set(${ICU_PUBLIC_VAR_NS}_C_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CXX_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CPP_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS "") +set(${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS "") +foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS}) + string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT) + set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the icu_declare_component macro +endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) + +# Check components +if(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) # uc required at least + set(${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc) +else(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc) + list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS}) + if(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) + message(FATAL_ERROR "Unknown ICU component: ${${ICU_PRIVATE_VAR_NS}_COMPONENT}") + endif(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) + endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) +endif(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + +# Includes +find_path( + ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS + NAMES unicode/utypes.h utypes.h + HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} + PATH_SUFFIXES "include" + DOC "Include directories for ICU" +) + +if(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + ########## ########## + if(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h") # ICU >= 4 + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h") # ICU [2;4[ + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h") # ICU [1.4;2[ + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h") # ICU 1.3 + file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS) + else() + message(FATAL_ERROR "ICU version header not found") + endif() + + if(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *ICU_VERSION *\"([0-9]+)\".*") # ICU 1.3 + # [1.3;1.4[ as #define ICU_VERSION "3" (no patch version, ie all 1.3.X versions will be detected as 1.3.0) + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "1") + set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_1}") + set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0") + elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION_MAJOR_NUM *([0-9]+).*") + # + # Since version 4.9.1, ICU release version numbering was totaly changed, see: + # - http://site.icu-project.org/download/49 + # - http://userguide.icu-project.org/design#TOC-Version-Numbers-in-ICU + # + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") + string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}") + string(REGEX REPLACE ".*# *define *U_ICU_VERSION_PATCHLEVEL_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}") + elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION *\"(([0-9]+)(\\.[0-9]+)*)\".*") # ICU [1.4;1.8[ + # [1.4;1.8[ as #define U_ICU_VERSION "1.4.1.2" but it seems that some 1.4.1(?:\.\d)? have releasing error and appears as 1.4.0 + set(${ICU_PRIVATE_VAR_NS}_FULL_VERSION "${CMAKE_MATCH_1}") # copy CMAKE_MATCH_1, no longer valid on the following if + if(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)$") + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") + set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}") + set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0") + elseif(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)") + set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}") + set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}") + set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${CMAKE_MATCH_3}") + endif() + else() + message(FATAL_ERROR "failed to detect ICU version") + endif() + set(${ICU_PUBLIC_VAR_NS}_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_MINOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_PATCH_VERSION}") + ########## ########## + + # Check dependencies (implies pkg-config) + if(PKG_CONFIG_FOUND) + set(${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS}) + foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP}) + pkg_check_modules(PC_ICU_PRIVATE_VAR_NS "icu-${${ICU_PRIVATE_VAR_NS}_COMPONENT}" QUIET) + + if(${PC_ICU_PRIVATE_VAR_NS}_FOUND) + foreach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY ${PC_ICU_LIBRARIES}) + string(REGEX REPLACE "^icu" "" ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY ${${PC_ICU_PRIVATE_VAR_NS}_LIBRARY}) + list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY}) + endforeach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY) + endif(${PC_ICU_PRIVATE_VAR_NS}_FOUND) + endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) + list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) + endif(PKG_CONFIG_FOUND) + + # Check libraries + foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS}) + set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES ) + set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES ) + foreach(${ICU_PRIVATE_VAR_NS}_BASE_NAME ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}) + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}") + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}d") + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}") + list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}d") + endforeach(${ICU_PRIVATE_VAR_NS}_BASE_NAME) + + find_library( + ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} + NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES} + HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} + PATH_SUFFIXES ${_ICU_LIB_SUFFIXES} + DOC "Release libraries for ICU" + ) + find_library( + ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT} + NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES} + HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} + PATH_SUFFIXES ${_ICU_LIB_SUFFIXES} + DOC "Debug libraries for ICU" + ) + + string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT) + if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # both not found + set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) + set("${ICU_PUBLIC_VAR_NS}_FOUND" FALSE) + else(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # one or both found + set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE) + if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # release not found => we are in debug + set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}") + elseif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # debug not found => we are in release + set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}") + else() # both found + set( + ${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} + optimized ${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}} + debug ${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}} + ) + endif() + list(APPEND ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}) + endif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) + endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT) + + # Try to find out compiler flags + find_program(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE icu-config HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}) + if(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + endif(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE) + + # Check find_package arguments + include(FindPackageHandleStandardArgs) + if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) + find_package_handle_standard_args( + ${ICU_PUBLIC_VAR_NS} + REQUIRED_VARS ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS + VERSION_VAR ${ICU_PUBLIC_VAR_NS}_VERSION + ) + else(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) + find_package_handle_standard_args(${ICU_PUBLIC_VAR_NS} "ICU not found" ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) +else(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + set("${ICU_PUBLIC_VAR_NS}_FOUND" FALSE) + if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) + message(FATAL_ERROR "Could not find ICU include directory") + endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY) +endif(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS) + +mark_as_advanced( + ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS + ${ICU_PUBLIC_VAR_NS}_LIBRARIES +) + +# IN (args) +icudebug("FIND_COMPONENTS") +icudebug("FIND_REQUIRED") +icudebug("FIND_QUIETLY") +icudebug("FIND_VERSION") +# OUT +# Found +icudebug("FOUND") +icudebug("UC_FOUND") +icudebug("I18N_FOUND") +icudebug("IO_FOUND") +icudebug("LE_FOUND") +icudebug("LX_FOUND") +icudebug("DATA_FOUND") +# Flags +icudebug("C_FLAGS") +icudebug("CPP_FLAGS") +icudebug("CXX_FLAGS") +icudebug("C_SHARED_FLAGS") +icudebug("CPP_SHARED_FLAGS") +icudebug("CXX_SHARED_FLAGS") +# Linking +icudebug("INCLUDE_DIRS") +icudebug("LIBRARIES") +# Version +icudebug("MAJOR_VERSION") +icudebug("MINOR_VERSION") +icudebug("PATCH_VERSION") +icudebug("VERSION") diff --git a/config.h.cmake b/config.h.cmake index 400b16b..799f195 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -21,6 +21,9 @@ /* Use zlib instead of builtin zlib decoder. */ #cmakedefine ENABLE_ZLIB 1 +/* Use ICU for text reodering. */ +#cmakedefine ENABLE_ICU 1 + /* Use cairo for rendering. */ #cmakedefine HAVE_CAIRO 1 -- 2.4.5 From 0bb06e485491aaf1e0df76f628f8c13e9e14371f Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Tue, 14 Jul 2015 16:29:28 +0200 Subject: [PATCH 2/3] Extend autotools build system for usage of ICU --- configure.ac | 26 ++++++++++++++++++++++++++ poppler/Makefile.am | 11 +++++++++++ 2 files changed, 37 insertions(+) diff --git a/configure.ac b/configure.ac index 308715a..1337294 100644 --- a/configure.ac +++ b/configure.ac @@ -321,6 +321,31 @@ AM_CONDITIONAL(BUILD_ZLIB, test x$enable_zlib = xyes) AH_TEMPLATE([ENABLE_ZLIB], [Use zlib instead of builtin zlib decoder.]) +dnl Test for icu +AC_ARG_ENABLE([icu], + [AS_HELP_STRING([--enable-icu],[Build with icu])], + [enable_icu=$enableval],[enable_icu="yes"]) +if test x$enable_icu = xyes; then + PKG_CHECK_MODULES(ICU, icu-uc, + [icu_pkgconfig=yes], [icu_pkgconfig=no]) + if test x$icu_pkgconfig = xyes; then + AC_DEFINE(ENABLE_ICU, 1, [Use ICU library]) + else + ICU_LIBS= + ICU_CFLAGS= + AC_PATH_PROG(ICU_CONFIG, icu-config, no) + if test "x$ICU_CONFIG" != "xno" ; then + ICU_CFLAGS=`$ICU_CONFIG --cflags` + ICU_LIBS=`$ICU_CONFIG --ldflags` + AC_DEFINE(ENABLE_ICU, 1, [Use ICU library]) + fi + fi +fi + +AM_CONDITIONAL(BUILD_ICU, test x$enable_icu = xyes) +AH_TEMPLATE([ENABLE_ICU], + [Use ICU to handle RTL text.]) + dnl Test for libcurl AC_ARG_ENABLE(libcurl, AC_HELP_STRING([--enable-libcurl], @@ -956,6 +981,7 @@ echo " use libjpeg: $enable_libjpeg" echo " use libpng: $enable_libpng" echo " use libtiff: $enable_libtiff" echo " use zlib: $enable_zlib" +echo " use icu: $enable_icu" echo " use libcurl: $enable_libcurl" echo " use libopenjpeg: $enable_libopenjpeg" if test x$enable_libopenjpeg = xyes;then diff --git a/poppler/Makefile.am b/poppler/Makefile.am index 0442929..a311ddb 100644 --- a/poppler/Makefile.am +++ b/poppler/Makefile.am @@ -90,6 +90,15 @@ zlib_libs = \ endif +if BUILD_ICU + +icu_libs = \ + $(ICU_LIBS) +icu_includes = \ + $(ICU_CFLAGS) + +endif + if BUILD_LIBCURL libcurl_libs = \ @@ -274,6 +283,7 @@ libpoppler_la_CPPFLAGS = \ $(libtiff_includes) \ $(libjpeg2000_includes) \ $(libpng_includes) \ + $(icu_includes) \ $(libcurl_includes) \ $(FREETYPE_CFLAGS) \ $(FONTCONFIG_CFLAGS) \ @@ -288,6 +298,7 @@ libpoppler_la_LIBADD = \ $(libjpeg_libs) \ $(libpng_libs) \ $(zlib_libs) \ + $(icu_libs) \ $(libcurl_libs) \ $(libjpeg2000_libs) \ $(FREETYPE_LIBS) \ -- 2.4.5 From 4c918d927ec0f5c582113a0c1c874c4e258ceddd Mon Sep 17 00:00:00 2001 From: Adam Reichold Date: Tue, 14 Jul 2015 16:30:40 +0200 Subject: [PATCH 3/3] Use ICU to reorder bidirectional text This extends the TextOutputDev to use ICU in the TextPage::findText and TextPage::dumpFragement methods to reorder bidirectional text. --- poppler/TextOutputDev.cc | 368 +++++++++++++++++++++++++++++++++++------------ poppler/TextOutputDev.h | 17 ++- 2 files changed, 293 insertions(+), 92 deletions(-) diff --git a/poppler/TextOutputDev.cc b/poppler/TextOutputDev.cc index 16f099f..e930735 100644 --- a/poppler/TextOutputDev.cc +++ b/poppler/TextOutputDev.cc @@ -57,6 +57,11 @@ #include // for O_BINARY #include // for setmode #endif +#if ENABLE_ICU +#include +#include +#include +#endif #include "goo/gmem.h" #include "goo/GooString.h" #include "goo/GooList.h" @@ -178,6 +183,259 @@ #define combMaxMidDelta 0.3 #define combMaxBaseDelta 0.4 +#if ENABLE_ICU + +#define icuConverterName "UTF32_PlatformEndian" + +static inline UBiDiReorderingMode getReorderingMode(TextReordering reordering, bool inverse) { + switch (reordering) { + default: + case textReorderingDefault: +#ifdef _WIN32 + return getReorderingMode(textReorderingNumbersSpecial, inverse); +#else + return getReorderingMode(textReorderingLikeDirect, inverse); +#endif + case textReorderingNumbersSpecial: + return inverse ? UBIDI_REORDER_INVERSE_FOR_NUMBERS_SPECIAL : UBIDI_REORDER_NUMBERS_SPECIAL; + case textReorderingLikeDirect: + return inverse ? UBIDI_REORDER_INVERSE_LIKE_DIRECT : UBIDI_REORDER_DEFAULT; + } +} + +static GBool reorderText(Unicode *s, int len, GBool primaryLR, TextReordering reordering) { + UErrorCode err = U_ZERO_ERROR; + UBiDi *bidi = NULL; + UConverter *converter = NULL; + int32_t ulen = 0; + UChar *output = NULL, *input = NULL; + + const UBiDiReorderingMode reorderingMode = getReorderingMode(reordering, false); + const UBiDiLevel level = primaryLR ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL; + + converter = ucnv_open(icuConverterName, &err); + + if (!converter) + goto out; + + err = U_ZERO_ERROR; + ulen = ucnv_toUChars(converter, NULL, 0, (const char *)s, len * sizeof(Unicode), &err); + + if (ulen <= 0) + goto out; + + err = U_ERROR_LIMIT; + input = new UChar[ulen]; + output = new UChar[ulen]; + + if (!input || !output) + goto out; + + err = U_ZERO_ERROR; + ucnv_toUChars(converter, input, ulen, (const char *)s, len * sizeof(Unicode), &err); + + if (U_FAILURE(err)) + goto out; + + err = U_ERROR_LIMIT; + bidi = ubidi_open(); + + if (!bidi) + goto out; + + ubidi_setReorderingMode(bidi, reorderingMode); + ubidi_setReorderingOptions(bidi, UBIDI_OPTION_REMOVE_CONTROLS); + + err = U_ZERO_ERROR; + ubidi_setPara(bidi, input, ulen, level, NULL, &err); + + if (U_FAILURE(err)) + goto out; + + err = U_ZERO_ERROR; + ubidi_writeReordered(bidi, output, ulen, UBIDI_DO_MIRRORING, &err); + + if (U_FAILURE(err)) + goto out; + + err = U_ZERO_ERROR; + ucnv_fromUChars(converter, (char *)s, len * sizeof(Unicode), output, ulen, &err); + +out: + ubidi_close(bidi); + delete[] input; + delete[] output; + ucnv_close(converter); + + return U_SUCCESS(err) ? gTrue : gFalse; +} + +static int dumpReorderedText(Unicode *text, int len, UnicodeMap *uMap, GBool primaryLR, TextReordering reordering, GooString *s) { + int nCols = 0; + + UErrorCode err = U_ZERO_ERROR; + UConverter *converter = NULL; + int32_t ulen = 0; + UChar *output = NULL, *input = NULL; + UBiDi *bidi = NULL; + + const UBiDiReorderingMode reorderingMode = getReorderingMode(reordering, true); + const UBiDiLevel level = primaryLR ? UBIDI_DEFAULT_LTR : UBIDI_DEFAULT_RTL; + + converter = ucnv_open(icuConverterName, &err); + + if(!converter) + goto out; + + err = U_ZERO_ERROR; + ulen = ucnv_toUChars(converter, NULL, 0, (const char *)text, len * sizeof(Unicode), &err); + + if (ulen <= 0) + goto out; + + input = new UChar[ulen]; + output = new UChar[ulen]; + + if (!input || !output) + goto out; + + err = U_ZERO_ERROR; + ucnv_toUChars(converter, input, ulen, (const char *)text, len * sizeof(Unicode), &err); + + if (U_FAILURE(err)) + goto out; + + bidi = ubidi_open(); + + if (!bidi) + goto out; + + ubidi_setReorderingMode(bidi, reorderingMode); + ubidi_setReorderingOptions(bidi, UBIDI_OPTION_REMOVE_CONTROLS); + + err = U_ZERO_ERROR; + ubidi_setPara(bidi, input, ulen, level, NULL, &err); + + if (U_FAILURE(err)) + goto out; + + err = U_ZERO_ERROR; + ubidi_writeReordered(bidi, output, ulen, UBIDI_DO_MIRRORING, &err); + + if (U_FAILURE(err)) + goto out; + + err = U_ZERO_ERROR; + ucnv_fromUChars(converter, (char *)text, len * sizeof(Unicode), output, ulen, &err); + + if (U_FAILURE(err)) + goto out; + + { + char buf[8]; + int buflen = 0; + + for (int idx = 0; idx < len; ++idx) { + buflen = uMap->mapUnicode(text[idx], buf, sizeof(buf)); + s->append(buf, buflen); + + ++nCols; + } + } + +out: + ubidi_close(bidi); + delete[] input; + delete[] output; + ucnv_close(converter); + + return nCols; +} + +#else + +static inline GBool reorderText(Unicode * /* s */, int /* len */, GBool /* primaryLR */, TextReordering /* reordering */) { return gTrue; } + +static int dumpReorderedText(Unicode *text, int len, UnicodeMap *uMap, GBool primaryLR, TextReordering /* reordering */, GooString *s) { + char lre[8], rle[8], popdf[8], buf[8]; + int lreLen, rleLen, popdfLen, n; + int nCols, i, j, k; + + nCols = 0; + + lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre)); + rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle)); + popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf)); + + if (primaryLR) { + + i = 0; + while (i < len) { + // output a left-to-right section + for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ; + for (k = i; k < j; ++k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + i = j; + // output a right-to-left section + for (j = i; + j < len && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j])); + ++j) ; + if (j > i) { + s->append(rle, rleLen); + for (k = j - 1; k >= i; --k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + s->append(popdf, popdfLen); + i = j; + } + } + + } else { + + // Note: This code treats numeric characters (European and + // Arabic/Indic) as left-to-right, which isn't strictly correct + // (incurs extra LRE/POPDF pairs), but does produce correct + // visual formatting. + s->append(rle, rleLen); + i = len - 1; + while (i >= 0) { + // output a right-to-left section + for (j = i; + j >= 0 && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j])); + --j) ; + for (k = i; k > j; --k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + i = j; + // output a left-to-right section + for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ; + if (j < i) { + s->append(lre, lreLen); + for (k = j + 1; k <= i; ++k) { + n = uMap->mapUnicode(text[k], buf, sizeof(buf)); + s->append(buf, n); + ++nCols; + } + s->append(popdf, popdfLen); + i = j; + } + } + s->append(popdf, popdfLen); + + } + + return nCols; +} + +#endif + //------------------------------------------------------------------------ // TextUnderline //------------------------------------------------------------------------ @@ -2221,11 +2479,12 @@ TextWord *TextWordList::get(int idx) { // TextPage //------------------------------------------------------------------------ -TextPage::TextPage(GBool rawOrderA) { +TextPage::TextPage(GBool rawOrderA, TextReordering reorderingA) { int rot; refCnt = 1; rawOrder = rawOrderA; + reordering = reorderingA; curWord = NULL; charPos = 0; curFont = NULL; @@ -3728,7 +3987,9 @@ GBool TextPage::findText(Unicode *s, int len, double xMin1, yMin1, xMax1, yMax1; GBool found; - //~ needs to handle right-to-left text + if (!reorderText(s, len, primaryLR, reordering)) { + return gFalse; + } if (rawOrder) { return gFalse; @@ -5330,91 +5591,24 @@ void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) { int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GooString *s) { - char lre[8], rle[8], popdf[8], buf[8]; - int lreLen, rleLen, popdfLen, n; - int nCols, i, j, k; - - nCols = 0; - if (uMap->isUnicode()) { - lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre)); - rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle)); - popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf)); - - if (primaryLR) { + return dumpReorderedText(text, len, uMap, primaryLR, reordering, s); - i = 0; - while (i < len) { - // output a left-to-right section - for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ; - for (k = i; k < j; ++k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - i = j; - // output a right-to-left section - for (j = i; - j < len && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j])); - ++j) ; - if (j > i) { - s->append(rle, rleLen); - for (k = j - 1; k >= i; --k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - s->append(popdf, popdfLen); - i = j; - } - } - - } else { + } else { + int nCols = 0; - // Note: This code treats numeric characters (European and - // Arabic/Indic) as left-to-right, which isn't strictly correct - // (incurs extra LRE/POPDF pairs), but does produce correct - // visual formatting. - s->append(rle, rleLen); - i = len - 1; - while (i >= 0) { - // output a right-to-left section - for (j = i; - j >= 0 && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j])); - --j) ; - for (k = i; k > j; --k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - i = j; - // output a left-to-right section - for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ; - if (j < i) { - s->append(lre, lreLen); - for (k = j + 1; k <= i; ++k) { - n = uMap->mapUnicode(text[k], buf, sizeof(buf)); - s->append(buf, n); - ++nCols; - } - s->append(popdf, popdfLen); - i = j; - } - } - s->append(popdf, popdfLen); + char buf[8]; + int buflen = 0; + for (int i = 0; i < len; ++i) { + buflen = uMap->mapUnicode(text[i], buf, sizeof(buf)); + s->append(buf, buflen); + nCols += buflen; } - } else { - for (i = 0; i < len; ++i) { - n = uMap->mapUnicode(text[i], buf, sizeof(buf)); - s->append(buf, n); - nCols += n; - } + return nCols; } - - return nCols; } #if TEXTOUT_WORD_LIST @@ -5496,12 +5690,11 @@ static void TextOutputDev_outputToFile(void *stream, const char *text, int len) } TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA, - double fixedPitchA, GBool rawOrderA, - GBool append) { + double fixedPitchA, GBool rawOrderA, + GBool append, TextReordering reorderingA) { text = NULL; physLayout = physLayoutA; fixedPitch = physLayout ? fixedPitchA : 0; - rawOrder = rawOrderA; doHTML = gFalse; ok = gTrue; @@ -5528,21 +5721,20 @@ TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA, } // set up text object - text = new TextPage(rawOrderA); + text = new TextPage(rawOrderA, reorderingA); actualText = new ActualText(text); } TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, - GBool physLayoutA, double fixedPitchA, - GBool rawOrderA) { + GBool physLayoutA, double fixedPitchA, + GBool rawOrderA, TextReordering reorderingA) { outputFunc = func; outputStream = stream; needClose = gFalse; physLayout = physLayoutA; fixedPitch = physLayout ? fixedPitchA : 0; - rawOrder = rawOrderA; doHTML = gFalse; - text = new TextPage(rawOrderA); + text = new TextPage(rawOrderA, reorderingA); actualText = new ActualText(text); ok = gTrue; } @@ -5813,6 +6005,6 @@ TextPage *TextOutputDev::takeText() { TextPage *ret; ret = text; - text = new TextPage(rawOrder); + text = new TextPage(ret->getRawOrder(), ret->getReordering()); return ret; } diff --git a/poppler/TextOutputDev.h b/poppler/TextOutputDev.h index a0aa6f8..ddeb52e 100644 --- a/poppler/TextOutputDev.h +++ b/poppler/TextOutputDev.h @@ -69,6 +69,12 @@ enum SelectionStyle { selectionStyleLine }; +enum TextReordering { + textReorderingDefault, + textReorderingNumbersSpecial, + textReorderingLikeDirect +}; + //------------------------------------------------------------------------ // TextFontInfo //------------------------------------------------------------------------ @@ -525,7 +531,7 @@ class TextPage { public: // Constructor. - TextPage(GBool rawOrderA); + TextPage(GBool rawOrderA, TextReordering reorderingA = textReorderingDefault); void incRefCnt(); void decRefCnt(); @@ -632,6 +638,9 @@ public: TextWordList *makeWordList(GBool physLayout); #endif + GBool getRawOrder() const { return rawOrder; } + TextReordering getReordering() const { return reordering; } + private: // Destructor. @@ -642,6 +651,7 @@ private: int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GooString *s); GBool rawOrder; // keep text in content stream order + TextReordering reordering; // determines how RTL text is reordered GBool mergeCombining; // merge when combining and base characters // are drawn on top of each other @@ -730,7 +740,7 @@ public: // content stream order. TextOutputDev(char *fileName, GBool physLayoutA, double fixedPitchA, GBool rawOrderA, - GBool append); + GBool append, TextReordering reorderingA = textReorderingDefault); // Create a TextOutputDev which will write to a generic stream. If // is true, the original physical layout of the text @@ -738,7 +748,7 @@ public: // content stream order. TextOutputDev(TextOutputFunc func, void *stream, GBool physLayoutA, double fixedPitchA, - GBool rawOrderA); + GBool rawOrderA, TextReordering reorderingA = textReorderingDefault); // Destructor. virtual ~TextOutputDev(); @@ -870,7 +880,6 @@ private: double fixedPitch; // if physLayout is true and this is non-zero, // assume fixed-pitch characters with this // width - GBool rawOrder; // keep text in content stream order GBool doHTML; // extra processing for HTML conversion GBool ok; // set up ok? -- 2.4.5