diff --git a/starboard/android/shared/BUILD.gn b/starboard/android/shared/BUILD.gn index 72ce1e37320f..8c219b391aec 100644 --- a/starboard/android/shared/BUILD.gn +++ b/starboard/android/shared/BUILD.gn @@ -279,6 +279,8 @@ static_library("starboard_platform") { "android_media_session_client.cc", "application_android.cc", "application_android.h", + "asset_manager.cc", + "asset_manager.h", "atomic_public.h", "audio_decoder.cc", "audio_decoder.h", @@ -379,6 +381,7 @@ static_library("starboard_platform") { "player_set_max_video_input_size.h", "player_set_playback_rate.cc", "posix_emu/errno.cc", + "posix_emu/file.cc", "posix_emu/pthread.cc", "posix_emu/stat.cc", "sanitizer_options.cc", diff --git a/starboard/android/shared/asset_manager.cc b/starboard/android/shared/asset_manager.cc new file mode 100644 index 000000000000..a386544390db --- /dev/null +++ b/starboard/android/shared/asset_manager.cc @@ -0,0 +1,138 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "starboard/android/shared/asset_manager.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "starboard/android/shared/file_internal.h" +#include "starboard/common/log.h" +#include "starboard/common/mutex.h" +#include "starboard/common/once.h" +#include "starboard/common/string.h" +#include "starboard/system.h" + +namespace starboard { +namespace android { +namespace shared { + +// static +SB_ONCE_INITIALIZE_FUNCTION(AssetManager, AssetManager::GetInstance); + +AssetManager::AssetManager() { + const int kPathSize = PATH_MAX / 2; + char path[kPathSize] = {0}; + SB_CHECK(SbSystemGetPath(kSbSystemPathTempDirectory, path, kPathSize)) + << "Unable to get system temp path for AssetManager."; + SB_CHECK(starboard::strlcat(path, "/asset_tmp", kPathSize) < kPathSize) + << "Unable to construct temp path for AssetManager."; + tmp_root_ = path; + ClearTempDir(); +} + +uint64_t AssetManager::AcquireInternalFd() { + ScopedLock scoped_lock(mutex_); + do { + ++internal_fd_; + } while (in_use_internal_fd_set_.count(internal_fd_) == 1); + in_use_internal_fd_set_.insert(internal_fd_); + return internal_fd_; +} + +std::string AssetManager::TempFilepath(uint64_t internal_fd) const { + return tmp_root_ + "/" + std::to_string(internal_fd); +} + +int AssetManager::Open(const char* path) { + if (!path) { + return -1; + } + + AAsset* asset = OpenAndroidAsset(path); + if (!asset) { + SB_LOG(WARNING) << "Asset path not found within package: " << path; + return -1; + } + + // Create temporary POSIX file for the asset + uint64_t internal_fd = AcquireInternalFd(); + std::string filepath = TempFilepath(internal_fd); + int fd = open(filepath.c_str(), O_RDWR | O_TRUNC | O_CREAT); + if (fd < 0) { + mutex_.Acquire(); + in_use_internal_fd_set_.erase(internal_fd); + mutex_.Release(); + return -1; + } + + // Copy contents of asset into temporary file and then seek to start of file. + const off_t size = AAsset_getLength(asset); + const void* const data = AAsset_getBuffer(asset); + if (write(fd, data, size) != size || lseek(fd, 0, SEEK_SET) != 0) { + SB_LOG(WARNING) << "Failed to write temporary file for asset: " << path; + mutex_.Acquire(); + in_use_internal_fd_set_.erase(internal_fd); + mutex_.Release(); // Can't hold lock when calling close(); + close(fd); + return -1; + } + AAsset_close(asset); + + // Keep track of the internal fd so we can delete its file on close(); + mutex_.Acquire(); + fd_to_internal_fd_map_[fd] = internal_fd; + mutex_.Release(); + return fd; +} + +bool AssetManager::IsAssetFd(int fd) const { + ScopedLock scoped_lock(mutex_); + return fd_to_internal_fd_map_.count(fd) == 1; +} + +int AssetManager::Close(int fd) { + mutex_.Acquire(); + if (auto search = fd_to_internal_fd_map_.find(fd); + search != fd_to_internal_fd_map_.end()) { + uint64_t internal_fd = search->second; + fd_to_internal_fd_map_.erase(search); + in_use_internal_fd_set_.erase(internal_fd); + mutex_.Release(); // Can't hold lock when calling close(); + int retval = close(fd); + std::string filepath = TempFilepath(internal_fd); + if (unlink(filepath.c_str()) != 0) { + SB_LOG(WARNING) << "Failed to delete temporary file: " << filepath; + } + return retval; + } + mutex_.Release(); + return -1; +} + +void AssetManager::ClearTempDir() { + auto callback = [](const char* child, const struct stat*, int file_type, + struct FTW*) -> int { return remove(child); }; + nftw(tmp_root_.c_str(), callback, 32, FTW_DEPTH | FTW_PHYS); + mkdir(tmp_root_.c_str(), 0700); +} + +} // namespace shared +} // namespace android +} // namespace starboard diff --git a/starboard/android/shared/asset_manager.h b/starboard/android/shared/asset_manager.h new file mode 100644 index 000000000000..10f1a8b5d526 --- /dev/null +++ b/starboard/android/shared/asset_manager.h @@ -0,0 +1,54 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef STARBOARD_ANDROID_SHARED_ASSET_MANAGER_H_ +#define STARBOARD_ANDROID_SHARED_ASSET_MANAGER_H_ + +#include +#include +#include + +#include "starboard/common/mutex.h" + +namespace starboard { +namespace android { +namespace shared { + +// This class handles opening/closing Android asset files as POSIX filehandles. +class AssetManager { + public: + static AssetManager* GetInstance(); + int Open(const char* path); + int Close(int fd); + bool IsAssetFd(int fd) const; + + private: + AssetManager(); + ~AssetManager() { ClearTempDir(); } + uint64_t AcquireInternalFd(); + std::string TempFilepath(uint64_t internal_fd) const; + void ClearTempDir(); + + std::string tmp_root_; + mutable Mutex mutex_; + uint64_t internal_fd_ = 0; // Guarded by |mutex_|. + std::set in_use_internal_fd_set_; // Guarded by |mutex_|. + std::map fd_to_internal_fd_map_; // Guarded by |mutex_|. +}; + +} // namespace shared +} // namespace android +} // namespace starboard + +#endif // STARBOARD_ANDROID_SHARED_ASSET_MANAGER_H_ diff --git a/starboard/android/shared/platform_configuration/BUILD.gn b/starboard/android/shared/platform_configuration/BUILD.gn index 0de86397e4f2..9c7bc708fb56 100644 --- a/starboard/android/shared/platform_configuration/BUILD.gn +++ b/starboard/android/shared/platform_configuration/BUILD.gn @@ -169,7 +169,11 @@ config("platform_configuration") { "-Wl,--wrap=eglSwapBuffers", ] if (!is_native_target_build) { - ldflags += [ "-Wl,--wrap=stat" ] + ldflags += [ + "-Wl,--wrap=close", + "-Wl,--wrap=open", + "-Wl,--wrap=stat", + ] } } diff --git a/starboard/android/shared/posix_emu/file.cc b/starboard/android/shared/posix_emu/file.cc new file mode 100644 index 000000000000..d18ebefb3997 --- /dev/null +++ b/starboard/android/shared/posix_emu/file.cc @@ -0,0 +1,61 @@ +// Copyright 2024 The Cobalt Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +#include "starboard/android/shared/asset_manager.h" +#include "starboard/android/shared/file_internal.h" +#include "starboard/common/log.h" +#include "starboard/configuration_constants.h" +#include "starboard/directory.h" +#include "starboard/log.h" + +using starboard::android::shared::AssetManager; +using starboard::android::shared::IsAndroidAssetPath; +using starboard::android::shared::OpenAndroidAsset; + +// /////////////////////////////////////////////////////////////////////////////// +// // Implementations below exposed externally in pure C for emulation. +// /////////////////////////////////////////////////////////////////////////////// + +extern "C" { +int __real_close(int fildes); +int __real_open(const char* path, int oflag, ...); + +int __wrap_close(int fildes) { + AssetManager* asset_manager = AssetManager::GetInstance(); + if (asset_manager->IsAssetFd(fildes)) { + return asset_manager->Close(fildes); + } + return __real_close(fildes); +} + +int __wrap_open(const char* path, int oflag, ...) { + if (!IsAndroidAssetPath(path)) { + va_list args; + va_start(args, oflag); + int fd; + if (oflag & O_CREAT) { + mode_t mode = va_arg(args, int); + return __real_open(path, oflag, mode); + } else { + return __real_open(path, oflag); + } + } + return AssetManager::GetInstance()->Open(path); +} + +} // extern "C" diff --git a/starboard/android/shared/test_filters.py b/starboard/android/shared/test_filters.py index 3d30f3deac2e..7c90f5484614 100644 --- a/starboard/android/shared/test_filters.py +++ b/starboard/android/shared/test_filters.py @@ -65,12 +65,6 @@ 'PosixDirectoryOpenTest.SunnyDayStaticContent', 'PosixFileGetPathInfoTest.WorksOnStaticContentDirectories', - # These POSIX tests should be disabled until asset manager starboard - # extension is implemented. - 'PosixFileGetInfoTest.WorksOnStaticContentFiles', - 'PosixFileReadTest/*.ReadStaticContent', - 'PosixFileSeekTest.FromEndInStaticContentWorks', - # These tests are disabled due to not receiving the kEndOfStream # player state update within the specified timeout. 'SbPlayerGetAudioConfigurationTests/SbPlayerGetAudioConfigurationTest.NoInput/*', diff --git a/starboard/decode_target.h b/starboard/decode_target.h index 6034a5a1f5e5..c120646a7434 100644 --- a/starboard/decode_target.h +++ b/starboard/decode_target.h @@ -24,7 +24,7 @@ // copies, and also avoiding pushing data between CPU and GPU memory // unnecessarily. // -// # SbDecodeTargetFormat +// * SbDecodeTargetFormat // // SbDecodeTargets support several different formats that can be used to decode // into and render from. Some formats may be easier to decode into, and others @@ -33,7 +33,7 @@ // an error. Each decoder provides a way to check if a given // SbDecodeTargetFormat is supported by that decoder. // -// # SbDecodeTargetGraphicsContextProvider +// * SbDecodeTargetGraphicsContextProvider // // Some components may need to acquire SbDecodeTargets compatible with a certain // rendering context, which may need to be created on a particular thread. The @@ -42,7 +42,7 @@ // rendering context that will be used to render the SbDecodeTarget objects. // For GLES renderers, it also provides functionality to enable the Starboard // implementation to run arbitrary code on the application's renderer thread -// with the renderer's EGLContext held current. This may be useful if your +// with the renderer's EGLContext held current. This may be useful if your // SbDecodeTarget creation code needs to execute GLES commands like, for // example, glGenTextures(). // @@ -104,10 +104,10 @@ typedef enum SbDecodeTargetFormat { #endif // SB_API_VERSION >= 14 // A decoder target format consisting of a single plane with pixels laid out - // in the format UYVY. Since there are two Y values per sample, but only one + // in the format UYVY. Since there are two Y values per sample, but only one // U value and only one V value, horizontally the Y resolution is twice the - // size of both the U and V resolutions. Vertically, they Y, U and V all - // have the same resolution. This is a YUV 422 format. When using this + // size of both the U and V resolutions. Vertically, the Y, U, and V planes + // all have the same resolution. This is a YUV 422 format. When using this // format with GL platforms, it is expected that the underlying texture will // be set to the GL_RGBA format, and the width of the texture will be equal to // the number of UYVY tuples per row (e.g. the u/v width resolution). @@ -157,19 +157,19 @@ typedef void (*SbDecodeTargetGlesContextRunner)( // In general, the SbDecodeTargetGraphicsContextProvider structure provides // information about the graphics context that will be used to render -// SbDecodeTargets. Some Starboard implementations may need to have references +// SbDecodeTargets. Some Starboard implementations may need to have references // to some graphics objects when creating/destroying resources used by -// SbDecodeTarget. References to SbDecodeTargetGraphicsContextProvider objects +// SbDecodeTarget. References to SbDecodeTargetGraphicsContextProvider objects // should be provided to all Starboard functions that might create // SbDecodeTargets. typedef struct SbDecodeTargetGraphicsContextProvider { // A reference to the EGLDisplay object that hosts the EGLContext that will - // be used to render any produced SbDecodeTargets. Note that it has the - // type |void*| in order to avoid #including the EGL header files here. + // be used to render any produced SbDecodeTargets. Note that it has the + // type |void*| in order to avoid including the EGL header files here. void* egl_display; // The EGLContext object that will be used to render any produced - // SbDecodeTargets. Note that it has the - // type |void*| in order to avoid #including the EGL header files here. + // SbDecodeTargets. Note that it has the type |void*| in order to avoid + // including the EGL header files here. void* egl_context; // The |gles_context_runner| function pointer is passed in from the @@ -220,9 +220,9 @@ typedef struct SbDecodeTargetInfoPlane { int height; // The following properties specify a rectangle indicating a region within - // the texture/surface that contains valid image data. The top-left corner - // is (0, 0) and increases to the right and to the bottom. The units - // specified by these parameters are number of pixels. The range for + // the texture/surface that contains valid image data. The top-left corner + // is (0, 0) and increases to the right and to the bottom. The units + // specified by these parameters are number of pixels. The range for // left/right is [0, width], and for top/bottom it is [0, height]. SbDecodeTargetInfoContentRegion content_region; } SbDecodeTargetInfoPlane; @@ -234,16 +234,16 @@ typedef struct SbDecodeTargetInfo { // expected in |planes|. SbDecodeTargetFormat format; - // Specifies whether the decode target is opaque. The underlying - // source of this value is expected to be properly maintained by the Starboard - // implementation. So, for example, if an opaque only image type were decoded + // Specifies whether the decode target is opaque. The underlying source of + // this value is expected to be properly maintained by the Starboard + // implementation. So, for example, if an opaque only image type were decoded // into an SbDecodeTarget, then the implementation would configure things in - // such a way that this value is set to true. By opaque, it is meant - // that all alpha values are guaranteed to be 255, if the decode target is of - // a format that has alpha values. If the decode target is of a format that - // does not have alpha values, then this value should be set to true. - // Applications may rely on this value in order to implement certain - // optimizations such as occlusion culling. + // such a way that this value is set to true. By opaque, it is meant that all + // alpha values are guaranteed to be 255, if the decode target is of a format + // that has alpha values. If the decode target is of a format that does not + // have alpha values, then this value should be set to true. Applications may + // rely on this value in order to implement certain optimizations such as + // occlusion culling. bool is_opaque; // The width of the image represented by this decode target. @@ -252,7 +252,7 @@ typedef struct SbDecodeTargetInfo { int height; // The image planes (e.g. kSbDecodeTargetPlaneRGBA, or {kSbDecodeTargetPlaneY, - // kSbDecodeTargetPlaneU, kSbDecodeTargetPlaneV} associated with this + // kSbDecodeTargetPlaneU, kSbDecodeTargetPlaneV}) associated with this // decode target. SbDecodeTargetInfoPlane planes[3]; } SbDecodeTargetInfo; @@ -299,20 +299,20 @@ static inline int SbDecodeTargetNumberOfPlanesForFormat( // Returns ownership of |decode_target| to the Starboard implementation. // This function will likely result in the destruction of the SbDecodeTarget and // all its associated surfaces, though in some cases, platforms may simply -// adjust a reference count. This function must be called on a thread with -// the context +// adjust a reference count. This function must be called on a thread with +// the context. SB_EXPORT void SbDecodeTargetRelease(SbDecodeTarget decode_target); -// Writes all information about |decode_target| into |out_info|. -// The |decode_target| must not be kSbDecodeTargetInvalid. -// The |out_info| pointer must not be NULL. -// Returns false if the provided |out_info| structure is not zero initialized. +// Writes all information about |decode_target| into |out_info|. The +// |decode_target| must not be kSbDecodeTargetInvalid. The |out_info| pointer +// must not be NULL. Returns false if the provided |out_info| structure is +// not zero initialized. SB_EXPORT bool SbDecodeTargetGetInfo(SbDecodeTarget decode_target, SbDecodeTargetInfo* out_info); // Inline convenience function to run an arbitrary // SbDecodeTargetGlesContextRunnerTarget function through a -// SbDecodeTargetGraphicsContextProvider. This is intended to be called by +// SbDecodeTargetGraphicsContextProvider. This is intended to be called by // Starboard implementations, if it is necessary. static inline void SbDecodeTargetRunInGlesContext( SbDecodeTargetGraphicsContextProvider* provider, diff --git a/starboard/drm.h b/starboard/drm.h index 1fcebb06f0c9..c1ded7835d51 100644 --- a/starboard/drm.h +++ b/starboard/drm.h @@ -48,13 +48,14 @@ typedef enum SbDrmStatus { kSbDrmStatusNotSupportedError, kSbDrmStatusInvalidStateError, kSbDrmStatusQuotaExceededError, - // The following error can be used when the error status cannot be mapped to - // one of the above errors. + // The kSbDrmStatusUnknownError can be used when the error status cannot be + // mapped to one of the rest errors. New error codes (if needed) should be + // added before kSbDrmStatusUnknownError. kSbDrmStatusUnknownError, } SbDrmStatus; // Status of a particular media key. -// https://w3c.github.io/encrypted-media/#idl-def-MediaKeyStatus +// https://www.w3.org/TR/encrypted-media/#idl-def-mediakeystatus typedef enum SbDrmKeyStatus { kSbDrmKeyStatusUsable, kSbDrmKeyStatusExpired, @@ -134,15 +135,16 @@ typedef struct SbDrmSystemPrivate* SbDrmSystem; // |type| is the status of the session request. // // |error_message| may contain an optional error message when |status| isn't -// |kSbDrmStatusSuccess| to provide more details about the error. It may be +// |kSbDrmStatusSuccess| to provide more details about the error. It may be // NULL if |status| is |kSbDrmStatusSuccess| or if no error message can be // provided. +// // |ticket| will be the same ticket that was passed to // SbDrmGenerateSessionUpdateRequest() or |kSbDrmTicketInvalid| if the update // request was generated by the DRM system. // // |session_id| cannot be NULL when |ticket| is |kSbDrmTicketInvalid|, even when -// there was an error generating the request. This allows Cobalt to find and +// there was an error generating the request. This allows Cobalt to find and // reject the correct Promise corresponding to the associated // SbDrmGenerateSessionUpdateRequest(). typedef void (*SbDrmSessionUpdateRequestFunc)(SbDrmSystem drm_system, @@ -167,7 +169,7 @@ typedef void (*SbDrmSessionUpdateRequestFunc)(SbDrmSystem drm_system, // |status| is the status of the session request. // // |error_message| may contain an optional error message when |status| isn't -// |kSbDrmStatusSuccess| to provide more details about the error. It may be +// |kSbDrmStatusSuccess| to provide more details about the error. It may be // NULL if |status| is |kSbDrmStatusSuccess| or if no error message can be // provided. // |succeeded| is whether the session was successfully updated or not. @@ -180,8 +182,15 @@ typedef void (*SbDrmSessionUpdatedFunc)(SbDrmSystem drm_system, int session_id_size); // A callback for notifications that the status of one or more keys in a session -// has been changed. All keys of the session and their new status will be -// passed along. Any keys not in the list is considered as deleted. +// has been changed. A pointer to an array of all keys |key_ids| of the session +// and their new status will be passed along. Any keys not in the list are +// considered as deleted. +// +// |number_of_keys| is the number of keys. +// +// |key_ids| is a pointer to an array of keys. +// +// |key_statuses| is a pointer of a vector contains the status of each key. typedef void (*SbDrmSessionKeyStatusesChangedFunc)( SbDrmSystem drm_system, void* context, @@ -191,7 +200,7 @@ typedef void (*SbDrmSessionKeyStatusesChangedFunc)( const SbDrmKeyId* key_ids, const SbDrmKeyStatus* key_statuses); -// A callback for signalling that a session has been closed by the SbDrmSystem +// A callback for signalling that a session has been closed by the SbDrmSystem. typedef void (*SbDrmSessionClosedFunc)(SbDrmSystem drm_system, void* context, const void* session_id, @@ -234,29 +243,34 @@ static SB_C_FORCE_INLINE bool SbDrmTicketIsValid(int ticket) { // SbDrmUpdateSession() for more details. // // |key_system|: The DRM key system to be created. The value should be in the -// form of "com.example.somesystem" as suggested by -// https://w3c.github.io/encrypted-media/#key-system. All letters in the value +// form of "com.example.somesystem". All letters in the value // should be lowercase and will be matched exactly with known DRM key systems of -// the platform. +// the platform. Note the key system will be matched case sensitive. For more +// details, refer to https://w3c.github.io/encrypted-media/#dfn-key-system-s +// // |context|: A value passed when any of this function's callback parameters are // called. +// // |update_request_callback|: A function that is called every time after // SbDrmGenerateSessionUpdateRequest() is called. +// // |session_updated_callback|: A function that is called every time after // SbDrmUpdateSession() is called. +// // |key_statuses_changed_callback|: A function that can be called to indicate // that key statuses have changed. +// // |server_certificate_updated_callback|: A function that is called to report -// whether the server certificate has been successfully updated. It is called -// once and only once. It is possible that the callback is called before the +// whether the server certificate has been successfully updated. It is called +// once and only once. It is possible that the callback is called before the // function returns. +// // |session_closed_callback|: A function that can be called to indicate that a // session has closed. // If |NULL| is passed for any of the callbacks (|update_request_callback|, // |session_updated_callback|, |key_statuses_changed_callback|, // |server_certificate_updated_callback|, or |session_closed_callback|), then // |kSbDrmSystemInvalid| must be returned. - SB_EXPORT SbDrmSystem SbDrmCreateSystem( const char* key_system, void* context, @@ -294,9 +308,11 @@ SB_EXPORT SbDrmSystem SbDrmCreateSystem( // used. // // |type|: The case-sensitive type of the session update request payload. Must -// not be NULL. +// not be NULL. +// // |initialization_data|: The data for which the session update -// request payload is created. Must not be NULL. +// request payload is created. Must not be NULL. +// // |initialization_data_size|: The size of the session update request payload. SB_EXPORT void SbDrmGenerateSessionUpdateRequest( SbDrmSystem drm_system, @@ -339,28 +355,31 @@ SB_EXPORT void SbDrmCloseSession(SbDrmSystem drm_system, int session_id_size); // Returns true if server certificate of |drm_system| can be updated via -// SbDrmUpdateServerCertificate(). The return value should remain the same +// SbDrmUpdateServerCertificate(). The return value should remain the same // during the life time of |drm_system|. // // |drm_system|: The DRM system to check if its server certificate is updatable. // Must not be |kSbDrmSystemInvalid|. SB_EXPORT bool SbDrmIsServerCertificateUpdatable(SbDrmSystem drm_system); -// Update the server certificate of |drm_system|. The function can be called -// multiple times. It is possible that a call to it happens before the callback +// Update the server certificate of |drm_system|. The function can be called +// multiple times. It is possible that a call to it happens before the callback // of a previous call is called. // Note that this function should only be called after // |SbDrmIsServerCertificateUpdatable| is called first and returned true. // // |drm_system|: The DRM system whose server certificate is being updated. Must -// not be |kSbDrmSystemInvalid|. +// not be |kSbDrmSystemInvalid|. +// // |ticket|: The opaque ID that allows to distinguish callbacks from multiple -// concurrent calls to SbDrmUpdateServerCertificate(), which will be passed to -// |server_certificate_updated_callback| as-is. It is the responsibility of -// the caller to establish ticket uniqueness, issuing multiple requests with -// the same ticket may result in undefined behavior. The value -// |kSbDrmTicketInvalid| must not be used. +// concurrent calls to SbDrmUpdateServerCertificate(), which will be passed to +// |server_certificate_updated_callback| as-is. It is the responsibility of +// the caller to establish ticket uniqueness, issuing multiple requests with +// the same ticket may result in undefined behavior. The value +// |kSbDrmTicketInvalid| must not be used. +// // |certificate|: Pointer to the server certificate data. Must not be NULL. +// // |certificate_size|: Size of the server certificate data. SB_EXPORT void SbDrmUpdateServerCertificate(SbDrmSystem drm_system, int ticket, @@ -377,7 +396,7 @@ SB_EXPORT void SbDrmUpdateServerCertificate(SbDrmSystem drm_system, // using url safe base64 without padding and line wrapping. On systems using // Widevine CE CDM with oemcrypto 16 or later, it should return the metrics // retrieved via Cdm::getMetrics(), encoded using url safe base64 without -// padding and line wrapping. The returned pointer should remain valid and its +// padding and line wrapping. The returned pointer should remain valid and its // content should remain unmodified until the next time this function is called // on the associated |drm_system| or the |drm_system| is destroyed. // @@ -396,12 +415,12 @@ SB_EXPORT const void* SbDrmGetMetrics(SbDrmSystem drm_system, int* size); // destroyed unless any associated SbPlayer or SbDecoder has first been // destroyed. // -// All callbacks are guaranteed to be finished when this function returns. As a +// All callbacks are guaranteed to be finished when this function returns. As a // result, if this function is called from a callback that is passed to // SbDrmCreateSystem(), a deadlock will occur. // // |drm_system|: The DRM system to be destroyed. Must not be -// |kSbDrmSystemInvalid|. +// |kSbDrmSystemInvalid|. SB_EXPORT void SbDrmDestroySystem(SbDrmSystem drm_system); #ifdef __cplusplus diff --git a/starboard/media.h b/starboard/media.h index fca1792933f6..09affda1e3a7 100644 --- a/starboard/media.h +++ b/starboard/media.h @@ -149,7 +149,7 @@ typedef enum SbMediaAudioFrameStorageType { // "L0 R0 L1 R1 L2 R2 ...". kSbMediaAudioFrameStorageTypeInterleaved, - // The samples of each channel are stored in their own continuous buffer. For + // The samples of each channel are stored in their own continuous buffer. For // example, for a stereo stream with channels L and R that contains samples // with timestamps 0, 1, 2, etc., the samples are stored in two buffers // "L0 L1 L2 ..." and "R0 R1 R2 ...". @@ -311,9 +311,7 @@ typedef enum SbMediaRangeId { // HDR (High Dynamic Range) Metadata common for HDR10 and WebM/VP9-based HDR // formats, together with the ColorSpace. HDR reproduces a greater dynamic range -// of luminosity than is possible with standard digital imaging. See the -// Consumer Electronics Association press release: -// https://www.cta.tech/News/Press-Releases/2015/August/CEA-Defines-%E2%80%98HDR-Compatible%E2%80%99-Displays.aspx +// of luminosity than is possible with standard digital imaging. typedef struct SbMediaColorMetadata { // Number of decoded bits per channel. A value of 0 indicates that the // BitsPerChannel is unspecified. @@ -405,7 +403,7 @@ typedef struct SbMediaVideoStreamInfo { // The video codec of this sample. SbMediaVideoCodec codec; - // The mime of the video stream when |codec| isn't kSbMediaVideoCodecNone. It + // The mime of the video stream when |codec| isn't kSbMediaVideoCodecNone. It // may point to an empty string if the mime is not available, and it can only // be set to NULL when |codec| is kSbMediaVideoCodecNone. const char* mime; @@ -418,7 +416,7 @@ typedef struct SbMediaVideoStreamInfo { // SbMediaCanPlayMimeAndKeySystem(), for example, when it is set to // "width=1920; height=1080; framerate=15;", the video will never adapt to // resolution higher than 1920x1080 or frame per second higher than 15 fps. - // When the maximums are unknown, this will be set to an empty string. It can + // When the maximums are unknown, this will be set to an empty string. It can // only be set to NULL when |codec| is kSbMediaVideoCodecNone. const char* max_video_capabilities; @@ -462,7 +460,7 @@ typedef struct SbMediaVideoSampleInfo { // The video codec of this sample. SbMediaVideoCodec codec; - // The mime of the video stream when |codec| isn't kSbMediaVideoCodecNone. It + // The mime of the video stream when |codec| isn't kSbMediaVideoCodecNone. It // may point to an empty string if the mime is not available, and it can only // be set to NULL when |codec| is kSbMediaVideoCodecNone. const char* mime; @@ -475,7 +473,7 @@ typedef struct SbMediaVideoSampleInfo { // SbMediaCanPlayMimeAndKeySystem(), for example, when it is set to // "width=1920; height=1080; framerate=15;", the video will never adapt to // resolution higher than 1920x1080 or frame per second higher than 15 fps. - // When the maximums are unknown, this will be set to an empty string. It can + // When the maximums are unknown, this will be set to an empty string. It can // only be set to NULL when |codec| is kSbMediaVideoCodecNone. const char* max_video_capabilities; @@ -544,7 +542,7 @@ typedef struct SbMediaAudioStreamInfo { // The audio codec of this sample. SbMediaAudioCodec codec; - // The mime of the audio stream when |codec| isn't kSbMediaAudioCodecNone. It + // The mime of the audio stream when |codec| isn't kSbMediaAudioCodecNone. It // may point to an empty string if the mime is not available, and it can only // be set to NULL when |codec| is kSbMediaAudioCodecNone. const char* mime; @@ -561,8 +559,7 @@ typedef struct SbMediaAudioStreamInfo { // The size, in bytes, of the audio_specific_config. uint16_t audio_specific_config_size; - // The AudioSpecificConfig, as specified in ISO/IEC-14496-3, section 1.6.2.1: - // http://read.pudn.com/downloads98/doc/comm/401153/14496/ISO_IEC_14496-3%20Part%203%20Audio/C036083E_SUB1.PDF + // The AudioSpecificConfig, as specified in ISO/IEC-14496-3, section 1.6.2.1. const void* audio_specific_config; } SbMediaAudioStreamInfo; @@ -577,18 +574,18 @@ typedef struct SbMediaAudioSampleInfo { #else // SB_API_VERSION >= 15 -// An audio sample info, which is a description of a given audio sample. This +// An audio sample info, which is a description of a given audio sample. This // acts as a set of instructions to the audio decoder. // // The audio sample info consists of information found in the |WAVEFORMATEX| // structure, as well as other information for the audio decoder, including the -// Audio-specific configuration field. The |WAVEFORMATEX| structure is -// specified at http://msdn.microsoft.com/en-us/library/dd390970(v=vs.85).aspx. +// Audio-specific configuration field. The |WAVEFORMATEX| structure is +// specified at http://msdn.microsoft.com/en-us/library/dd390970(v=vs.85).aspx . typedef struct SbMediaAudioSampleInfo { // The audio codec of this sample. SbMediaAudioCodec codec; - // The mime of the audio stream when |codec| isn't kSbMediaAudioCodecNone. It + // The mime of the audio stream when |codec| isn't kSbMediaAudioCodecNone. It // may point to an empty string if the mime is not available, and it can only // be set to NULL when |codec| is kSbMediaAudioCodecNone. const char* mime; @@ -614,8 +611,7 @@ typedef struct SbMediaAudioSampleInfo { // The size, in bytes, of the audio_specific_config. uint16_t audio_specific_config_size; - // The AudioSpecificConfig, as specified in ISO/IEC-14496-3, section 1.6.2.1: - // http://read.pudn.com/downloads98/doc/comm/401153/14496/ISO_IEC_14496-3%20Part%203%20Audio/C036083E_SUB1.PDF + // The AudioSpecificConfig, as specified in ISO/IEC-14496-3, section 1.6.2.1. const void* audio_specific_config; } SbMediaAudioSampleInfo, SbMediaAudioStreamInfo; @@ -630,47 +626,46 @@ typedef struct SbMediaAudioSampleInfo { // |kSbMediaSupportNotSupported| if either is NULL. // // |mime|: The mime information of the media in the form of |video/webm| or -// |video/mp4; codecs="avc1.42001E"|. It may include arbitrary parameters like -// "codecs", "channels", etc. Note that the "codecs" parameter may contain -// more than one codec, delimited by comma. -// |key_system|: A lowercase value in the form of "com.example.somesystem" as -// suggested by https://w3c.github.io/encrypted-media/#key-system that can be -// matched exactly with known DRM key systems of the platform. When -// |key_system| is an empty string, the return value is an indication for -// non-encrypted media. +// |video/mp4; codecs="avc1.42001E"|. It may include arbitrary parameters like +// "codecs", "channels", etc. Note that the "codecs" parameter may contain +// more than one codec, delimited by comma. // -// An implementation may choose to support |key_system| with extra attributes, -// separated by ';', like -// |com.example.somesystem; attribute_name1="value1"; attribute_name2=value1|. -// If |key_system| with attributes is not supported by an implementation, it -// should treat |key_system| as if it contains only the key system, and reject -// any input containing extra attributes, i.e. it can keep using its existing -// implementation. -// When an implementation supports |key_system| with attributes, it has to -// support all attributes defined by the Starboard version the implementation -// uses. -// An implementation should ignore any unknown attributes, and make a decision -// solely based on the key system and the known attributes. For example, if -// an implementation supports "com.widevine.alpha", it should also return -// `kSbMediaSupportTypeProbably` when |key_system| is -// |com.widevine.alpha; invalid_attribute="invalid_value"|. -// Currently the only attribute has to be supported is |encryptionscheme|. It -// reflects the value passed to `encryptionScheme` of -// MediaKeySystemMediaCapability, as defined in -// https://wicg.github.io/encrypted-media-encryption-scheme/, which can take -// value "cenc", "cbcs", or "cbcs-1-9". -// Empty string is not a valid value for |encryptionscheme| and the -// implementation should return `kSbMediaSupportTypeNotSupported` when -// |encryptionscheme| is set to "". -// The implementation should return `kSbMediaSupportTypeNotSupported` for -// unknown values of known attributes. For example, if an implementation -// supports "encryptionscheme" with value "cenc", "cbcs", or "cbcs-1-9", then -// it should return `kSbMediaSupportTypeProbably` when |key_system| is -// |com.widevine.alpha; encryptionscheme="cenc"|, and return -// `kSbMediaSupportTypeNotSupported` when |key_system| is -// |com.widevine.alpha; encryptionscheme="invalid"|. -// If an implementation supports key system with attributes on one key system, -// it has to support key system with attributes on all key systems supported. +// |key_system|: A lowercase value in the form of "com.example.somesystem", +// and can be matched exactly with known DRM key systems of the platform. +// When |key_system| is an empty string, the return value is an indication for +// non-encrypted media. For more detail, refer to +// https://w3c.github.io/encrypted-media/#key-system +// +// An implementation may choose to support |key_system| with extra attributes, +// separated by ';', like +// |com.example.somesystem; attribute_name1="value1"; attribute_name2=value1|. +// If |key_system| with attributes is not supported by an implementation, it +// should treat |key_system| as if it contains only the key system, and reject +// any input containing extra attributes, i.e. it can keep using its existing +// implementation. When an implementation supports |key_system| with +// attributes, it has to support all attributes defined by the Starboard version +// the implementation uses. An implementation should ignore any unknown +// attributes, and make a decision solely based on the key system and the known +// attributes. For example, if an implementation supports "com.widevine.alpha", +// it should also return |kSbMediaSupportTypeProbably| when |key_system| is +// |com.widevine.alpha; invalid_attribute="invalid_value"|. +// Currently the only attribute has to be supported is |encryptionscheme|. It +// reflects the value passed to |encryptionScheme| of +// MediaKeySystemMediaCapability. It can take value "cenc", "cbcs", or +// "cbcs-1-9". Empty string is not a valid value for |encryptionscheme| and the +// implementation should return |kSbMediaSupportTypeNotSupported| when +// |encryptionscheme| is set to "". The implementation should return +// |kSbMediaSupportTypeNotSupported| for unknown values of known attributes. +// For example, if an implementation supports "encryptionscheme" with value +// "cenc", "cbcs", or "cbcs-1-9", then it should return +// |kSbMediaSupportTypeProbably| when |key_system| is +// |com.widevine.alpha; encryptionscheme="cenc"|, and return +// |kSbMediaSupportTypeNotSupported| when |key_system| is +// |com.widevine.alpha; encryptionscheme="invalid"|. +// If an implementation supports key system with attributes on one key system, +// it has to support key system with attributes on all key systems supported. +// For more detail, refer to +// https://wicg.github.io/encrypted-media-encryption-scheme SB_EXPORT SbMediaSupportType SbMediaCanPlayMimeAndKeySystem(const char* mime, const char* key_system); @@ -688,7 +683,7 @@ SB_EXPORT int SbMediaGetAudioOutputCount(); // platform or if |output_index| does not exist on this device. // // |out_configuration|: The variable that holds the audio configuration -// information. +// information. SB_EXPORT bool SbMediaGetAudioConfiguration( int output_index, SbMediaAudioConfiguration* out_configuration); @@ -703,7 +698,7 @@ typedef enum SbMediaBufferStorageType { kSbMediaBufferStorageTypeFile, } SbMediaBufferStorageType; -// The media buffer will be allocated using the returned alignment. Set this to +// The media buffer will be allocated using the returned alignment. Set this to // a larger value may increase the memory consumption of media buffers. // #if SB_API_VERSION < 16 @@ -718,31 +713,31 @@ SB_EXPORT int SbMediaGetBufferAlignment(SbMediaType type); // When the media stack needs more memory to store media buffers, it will // allocate extra memory in units returned by SbMediaGetBufferAllocationUnit. // This can return 0, in which case the media stack will allocate extra memory -// on demand. When SbMediaGetInitialBufferCapacity and this function both +// on demand. When SbMediaGetInitialBufferCapacity and this function both // return 0, the media stack will allocate individual buffers directly using // malloc functions. SB_EXPORT int SbMediaGetBufferAllocationUnit(); // Specifies the maximum amount of memory used by audio buffers of media source -// before triggering a garbage collection. A large value will cause more memory +// before triggering a garbage collection. A large value will cause more memory // being used by audio buffers but will also make the app less likely to -// re-download audio data. Note that the app may experience significant +// re-download audio data. Note that the app may experience significant // difficulty if this value is too low. SB_EXPORT int SbMediaGetAudioBufferBudget(); // Specifies the duration threshold of media source garbage collection in -// microseconds. When the accumulated duration in a source buffer exceeds this +// microseconds. When the accumulated duration in a source buffer exceeds this // value, the media source implementation will try to eject existing buffers // from the cache. This is usually triggered when the video being played has a -// simple content and the encoded data is small. In such case this can limit +// simple content and the encoded data is small. In such case this can limit // how much is allocated for the book keeping data of the media buffers and // avoid OOM of system heap. This should return 170 seconds for most of the -// platforms. But it can be further reduced on systems with extremely low +// platforms. But it can be further reduced on systems with extremely low // memory. SB_EXPORT int64_t SbMediaGetBufferGarbageCollectionDurationThreshold(); // The amount of memory that will be used to store media buffers allocated -// during system startup. To allocate a large chunk at startup helps with +// during system startup. To allocate a large chunk at startup helps with // reducing fragmentation and can avoid failures to allocate incrementally. This // can return 0. SB_EXPORT int SbMediaGetInitialBufferCapacity(); @@ -751,22 +746,25 @@ SB_EXPORT int SbMediaGetInitialBufferCapacity(); // must be larger than sum of the video budget and audio budget. // This is a soft limit and the app will continue to allocate media buffers even // if the accumulated memory used by the media buffers exceeds the maximum -// buffer capacity. The allocation of media buffers may only fail when there is +// buffer capacity. The allocation of media buffers may only fail when there is // not enough memory in the system to fulfill the request, under which case the // app will be terminated as under other OOM situations. // // |codec|: the video codec associated with the buffer. +// // |resolution_width|: the width of the video resolution. +// // |resolution_height|: the height of the video resolution. -// |bits_per_pixel|: the bits per pixel. This value is larger for HDR than non- -// HDR video. +// +// |bits_per_pixel|: the bits per pixel. This value is larger for HDR +// than non-HDR video. SB_EXPORT int SbMediaGetMaxBufferCapacity(SbMediaVideoCodec codec, int resolution_width, int resolution_height, int bits_per_pixel); // Extra bytes allocated at the end of a media buffer to ensure that the buffer -// can be use optimally by specific instructions like SIMD. Set to 0 to remove +// can be use optimally by specific instructions like SIMD. Set to 0 to remove // any padding. // #if SB_API_VERSION >= 14 @@ -777,7 +775,7 @@ SB_EXPORT int SbMediaGetBufferPadding(SbMediaType type); #endif // SB_API_VERSION >= 14 // When either SbMediaGetInitialBufferCapacity or SbMediaGetBufferAllocationUnit -// isn't zero, media buffers will be allocated using a memory pool. Set the +// isn't zero, media buffers will be allocated using a memory pool. Set the // following variable to true to allocate the media buffer pool memory on demand // and return all memory to the system when there is no media buffer allocated. // Setting the following value to false results in that Cobalt will allocate @@ -786,16 +784,19 @@ SB_EXPORT int SbMediaGetBufferPadding(SbMediaType type); // media buffers allocated. SB_EXPORT bool SbMediaIsBufferPoolAllocateOnDemand(); -// The memory used when playing mp4 videos that is not in DASH format. The -// resolution of such videos shouldn't go beyond 1080p. Its value should be +// The memory used when playing mp4 videos that is not in DASH format. The +// resolution of such videos shouldn't go beyond 1080p. Its value should be // less than the sum of SbMediaGetAudioBufferBudget and // 'SbMediaGetVideoBufferBudget(..., 1920, 1080, ...) but not less than 8 MB. // // |codec|: the video codec associated with the buffer. +// // |resolution_width|: the width of the video resolution. +// // |resolution_height|: the height of the video resolution. -// |bits_per_pixel|: the bits per pixel. This value is larger for HDR than non- -// HDR video. +// +// |bits_per_pixel|: the bits per pixel. This value is larger for HDR +// than non-HDR video. SB_EXPORT int SbMediaGetProgressiveBufferBudget(SbMediaVideoCodec codec, int resolution_width, int resolution_height, @@ -803,7 +804,7 @@ SB_EXPORT int SbMediaGetProgressiveBufferBudget(SbMediaVideoCodec codec, // Returns SbMediaBufferStorageType of type |SbMediaStorageTypeMemory| or // |SbMediaStorageTypeFile|. For memory storage, the media buffers will be -// stored in main memory allocated by malloc functions. For file storage, the +// stored in main memory allocated by malloc functions. For file storage, the // media buffers will be stored in a temporary file in the system cache folder // acquired by calling SbSystemGetPath() with "kSbSystemPathCacheDirectory". // Note that when its value is "file" the media stack will still allocate memory @@ -816,16 +817,19 @@ SB_EXPORT SbMediaBufferStorageType SbMediaGetBufferStorageType(); SB_EXPORT bool SbMediaIsBufferUsingMemoryPool(); // Specifies the maximum amount of memory used by video buffers of media source -// before triggering a garbage collection. A large value will cause more memory +// before triggering a garbage collection. A large value will cause more memory // being used by video buffers but will also make app less likely to re-download -// video data. Note that the app may experience significant difficulty if this +// video data. Note that the app may experience significant difficulty if this // value is too low. // // |codec|: the video codec associated with the buffer. +// // |resolution_width|: the width of the video resolution. +// // |resolution_height|: the height of the video resolution. -// |bits_per_pixel|: the bits per pixel. This value is larger for HDR than non- -// HDR video. +// +// |bits_per_pixel|: the bits per pixel. This value is larger for HDR +// than non-HDR video. SB_EXPORT int SbMediaGetVideoBufferBudget(SbMediaVideoCodec codec, int resolution_width, int resolution_height, diff --git a/starboard/player.h b/starboard/player.h index d4582fa6d516..340a89bca86e 100644 --- a/starboard/player.h +++ b/starboard/player.h @@ -67,8 +67,8 @@ typedef enum SbPlayerState { typedef enum SbPlayerError { kSbPlayerErrorDecode, // The playback capability of the player has changed, likely because of a - // change of the system environment. For example, the system may support vp9 - // decoding with an external GPU. When the external GPU is detached, this + // change of the system environment. For example, the system may support vp9 + // decoding with an external GPU. When the external GPU is detached, this // error code can signal the app to retry the playback, possibly with h264. kSbPlayerErrorCapabilityChanged, // The max value of SbPlayer error type. It should always at the bottom @@ -80,7 +80,7 @@ typedef enum SbPlayerOutputMode { // Requests for SbPlayer to produce an OpenGL texture that the client must // draw every frame with its graphics rendering. It may be that we get a // texture handle, but cannot perform operations like glReadPixels on it if it - // is DRM-protected, or it may not support DRM-protected content at all. When + // is DRM-protected, or it may not support DRM-protected content at all. When // this output mode is provided to SbPlayerCreate(), the application will be // able to pull frames via calls to SbPlayerGetCurrentFrame(). kSbPlayerOutputModeDecodeToTexture, @@ -88,7 +88,7 @@ typedef enum SbPlayerOutputMode { // Requests for SbPlayer to use a "punch-out" output mode, where video is // rendered to the far background, and the graphics plane is automatically // composited on top of the video by the platform. The client must punch an - // alpha hole out of the graphics plane for video to show through. In this + // alpha hole out of the graphics plane for video to show through. In this // case, changing the video bounds must be tightly synchronized between the // player and the graphics plane. kSbPlayerOutputModePunchOut, @@ -101,31 +101,31 @@ typedef enum SbPlayerOutputMode { // SbPlayerGetPreferredOutputMode(). typedef struct SbPlayerCreationParam { // Provides an appropriate DRM system if the media stream has encrypted - // portions. It will be |kSbDrmSystemInvalid| if the stream does not have + // portions. It will be |kSbDrmSystemInvalid| if the stream does not have // encrypted portions. SbDrmSystem drm_system; #if SB_API_VERSION >= 15 // Contains a populated SbMediaAudioStreamInfo if |audio_stream_info.codec| - // isn't |kSbMediaAudioCodecNone|. When |audio_stream_info.codec| is + // isn't |kSbMediaAudioCodecNone|. When |audio_stream_info.codec| is // |kSbMediaAudioCodecNone|, the video doesn't have an audio track. SbMediaAudioStreamInfo audio_stream_info; // Contains a populated SbMediaVideoStreamInfo if |video_stream_info.codec| - // isn't |kSbMediaVideoCodecNone|. When |video_stream_info.codec| is + // isn't |kSbMediaVideoCodecNone|. When |video_stream_info.codec| is // |kSbMediaVideoCodecNone|, the video is audio only. SbMediaVideoStreamInfo video_stream_info; #else // SB_API_VERSION >= 15 // Contains a populated SbMediaAudioSampleInfo if |audio_sample_info.codec| - // isn't |kSbMediaAudioCodecNone|. When |audio_sample_info.codec| is + // isn't |kSbMediaAudioCodecNone|. When |audio_sample_info.codec| is // |kSbMediaAudioCodecNone|, the video doesn't have an audio track. SbMediaAudioSampleInfo audio_sample_info; // Contains a populated SbMediaVideoSampleInfo if |video_sample_info.codec| - // isn't |kSbMediaVideoCodecNone|. When |video_sample_info.codec| is + // isn't |kSbMediaVideoCodecNone|. When |video_sample_info.codec| is // |kSbMediaVideoCodecNone|, the video is audio only. SbMediaVideoSampleInfo video_sample_info; #endif // SB_API_VERSION >= 15 - // Selects how the decoded video frames will be output. For example, + // Selects how the decoded video frames will be output. For example, // |kSbPlayerOutputModePunchOut| indicates that the decoded video frames will // be output to a background video layer by the platform, and // |kSbPlayerOutputDecodeToTexture| indicates that the decoded video frames @@ -138,11 +138,11 @@ typedef struct SbPlayerCreationParam { // data may come from multiple sources. typedef enum SbPlayerSampleSideDataType { // The side data comes from the BlockAdditional data in the Matroska/Webm - // container, as specified in - // https://tools.ietf.org/id/draft-lhomme-cellar-matroska-03.html#rfc.section.7.3.39 - // and https://www.webmproject.org/docs/container/#BlockAdditional. + // container. // The first 8 bytes of the data contains the value of BlockAddID in big - // endian format, followed by the content of BlockAdditional. + // endian format, followed by the content of BlockAdditional. See: + // * https://datatracker.ietf.org/doc/draft-lhomme-cellar-matroska/03 + // * https://www.webmproject.org/docs/container/#BlockAdditional kMatroskaBlockAdditional, } SbPlayerSampleSideDataType; @@ -169,7 +169,7 @@ typedef struct SbPlayerSampleInfo { // Points to an array of side data for the input, when available. SbPlayerSampleSideData* side_data; - // The number of side data pointed by |side_data|. It should be set to 0 if + // The number of side data pointed by |side_data|. It should be set to 0 if // there is no side data for the input. int side_data_count; @@ -230,11 +230,11 @@ typedef struct SbPlayerInfo2 { // the player. int corrupted_video_frames; - // The rate of playback. The video is played back in a speed that is - // proportional to this. By default it is 1.0 which indicates that the - // playback is at normal speed. When it is greater than one, the video is - // played in a faster than normal speed. When it is less than one, the video - // is played in a slower than normal speed. Negative speeds are not + // The rate of playback. The video is played back in a speed that is + // proportional to this. By default it is 1.0 which indicates that the + // playback is at normal speed. When it is greater than one, the video is + // played in a faster than normal speed. When it is less than one, the video + // is played in a slower than normal speed. Negative speeds are not // supported. double playback_rate; #if SB_API_VERSION >= 15 @@ -274,7 +274,9 @@ typedef void (*SbPlayerStatusFunc)(SbPlayer player, int ticket); // Callback for player errors, that may set a |message|. +// // |error|: indicates the error code. +// // |message|: provides specific informative diagnostic message about the error // condition encountered. It is ok for the message to be an empty // string or NULL if no information is available. @@ -283,7 +285,7 @@ typedef void (*SbPlayerErrorFunc)(SbPlayer player, SbPlayerError error, const char* message); -// Callback to free the given sample buffer data. When more than one buffer +// Callback to free the given sample buffer data. When more than one buffer // are sent in SbPlayerWriteSample(), the implementation only has to call this // callback with |sample_buffer| points to the first buffer. typedef void (*SbPlayerDeallocateSampleFunc)(SbPlayer player, @@ -340,79 +342,79 @@ static inline bool SbPlayerIsValid(SbPlayer player) { // must not cause a crash. // // |window|: The window that will display the player. |window| can be -// |kSbWindowInvalid| for platforms where video is only displayed on a -// particular window that the underlying implementation already has access to. +// |kSbWindowInvalid| for platforms where video is only displayed on a +// particular window that the underlying implementation already has access to. // // |video_codec|: The video codec used for the player. If |video_codec| is -// |kSbMediaVideoCodecNone|, the player is an audio-only player. If -// |video_codec| is any other value, the player is an audio/video decoder. -// This can be set to |kSbMediaVideoCodecNone| to play a video with only an -// audio track. +// |kSbMediaVideoCodecNone|, the player is an audio-only player. If +// |video_codec| is any other value, the player is an audio/video decoder. +// This can be set to |kSbMediaVideoCodecNone| to play a video with only an +// audio track. // // |audio_codec|: The audio codec used for the player. The caller must provide a -// populated |audio_sample_info| if audio codec is |kSbMediaAudioCodecAac|. -// Can be set to |kSbMediaAudioCodecNone| to play a video without any audio -// track. In such case |audio_sample_info| must be NULL. +// populated |audio_sample_info| if audio codec is |kSbMediaAudioCodecAac|. +// Can be set to |kSbMediaAudioCodecNone| to play a video without any audio +// track. In such case |audio_sample_info| must be NULL. // // |drm_system|: If the media stream has encrypted portions, then this -// parameter provides an appropriate DRM system, created with -// |SbDrmCreateSystem()|. If the stream does not have encrypted portions, -// then |drm_system| may be |kSbDrmSystemInvalid|. +// parameter provides an appropriate DRM system, created with +// |SbDrmCreateSystem()|. If the stream does not have encrypted portions, +// then |drm_system| may be |kSbDrmSystemInvalid|. // // |audio_sample_info|: Note that the caller must provide a populated -// |audio_sample_info| if the audio codec is |kSbMediaAudioCodecAac|. -// Otherwise, |audio_sample_info| can be NULL. See media.h for the format of -// the |SbMediaAudioSampleInfo| struct. +// |audio_sample_info| if the audio codec is |kSbMediaAudioCodecAac|. +// Otherwise, |audio_sample_info| can be NULL. See media.h for the format of +// the |SbMediaAudioSampleInfo| struct. // -// Note that |audio_specific_config| is a pointer and the content it points to -// is no longer valid after this function returns. The implementation has to -// make a copy of the content if it is needed after the function returns. +// Note that |audio_specific_config| is a pointer and the content it points to +// is no longer valid after this function returns. The implementation has to +// make a copy of the content if it is needed after the function returns. // // |max_video_capabilities|: This string communicates the max video capabilities -// required to the platform. The web app will not provide a video stream -// exceeding the maximums described by this parameter. Allows the platform to -// optimize playback pipeline for low quality video streams if it knows that -// it will never adapt to higher quality streams. The string uses the same -// format as the string passed in to SbMediaCanPlayMimeAndKeySystem(), for -// example, when it is set to "width=1920; height=1080; framerate=15;", the -// video will never adapt to resolution higher than 1920x1080 or frame per -// second higher than 15 fps. When the maximums are unknown, this will be set -// to NULL. +// required to the platform. The web app will not provide a video stream +// exceeding the maximums described by this parameter. Allows the platform to +// optimize playback pipeline for low quality video streams if it knows that +// it will never adapt to higher quality streams. The string uses the same +// format as the string passed in to SbMediaCanPlayMimeAndKeySystem(), for +// example, when it is set to "width=1920; height=1080; framerate=15;", the +// video will never adapt to resolution higher than 1920x1080 or frame per +// second higher than 15 fps. When the maximums are unknown, this will be set +// to NULL. // // |sample_deallocator_func|: If not |NULL|, the player calls this function -// on an internal thread to free the sample buffers passed into -// SbPlayerWriteSample(). +// on an internal thread to free the sample buffers passed into +// SbPlayerWriteSample(). // // |decoder_status_func|: If not |NULL|, the decoder calls this function on an -// internal thread to provide an update on the decoder's status. No work -// should be done on this thread. Rather, it should just signal the client -// thread interacting with the decoder. +// internal thread to provide an update on the decoder's status. No work +// should be done on this thread. Rather, it should just signal the client +// thread interacting with the decoder. // // |player_status_func|: If not |NULL|, the player calls this function on an -// internal thread to provide an update on the playback status. No work -// should be done on this thread. Rather, it should just signal the client -// thread interacting with the decoder. +// internal thread to provide an update on the playback status. No work +// should be done on this thread. Rather, it should just signal the client +// thread interacting with the decoder. // // |player_error_func|: If not |NULL|, the player calls this function on an -// internal thread to provide an update on the error status. This callback is -// responsible for setting the media error message. +// internal thread to provide an update on the error status. This callback is +// responsible for setting the media error message. // // |context|: This is passed to all callbacks and is generally used to point -// at a class or struct that contains state associated with the player. -// -// |output_mode|: Selects how the decoded video frames will be output. For -// example, kSbPlayerOutputModePunchOut indicates that the decoded video -// frames will be output to a background video layer by the platform, and -// kSbPlayerOutputDecodeToTexture indicates that the decoded video frames -// should be made available for the application to pull via calls to -// SbPlayerGetCurrentFrame(). -// -// |provider|: Only present in Starboard version 3 and up. If not |NULL|, -// then when output_mode == kSbPlayerOutputModeDecodeToTexture, the player MAY -// use the provider to create SbDecodeTargets on the renderer thread. A -// provider may not always be needed by the player, but if it is needed, and -// the provider is not given, the player will fail by returning -// |kSbPlayerInvalid|. +// at a class or struct that contains state associated with the player. +// +// |output_mode|: Selects how the decoded video frames will be output. For +// example, kSbPlayerOutputModePunchOut indicates that the decoded video +// frames will be output to a background video layer by the platform, and +// kSbPlayerOutputDecodeToTexture indicates that the decoded video frames +// should be made available for the application to pull via calls to +// SbPlayerGetCurrentFrame(). +// +// |provider|: Only present in Starboard version 3 and up. If not |NULL|, +// then when output_mode == kSbPlayerOutputModeDecodeToTexture, the player MAY +// use the provider to create SbDecodeTargets on the renderer thread. A +// provider may not always be needed by the player, but if it is needed, and +// the provider is not given, the player will fail by returning +// |kSbPlayerInvalid|. // // If |NULL| is passed to any of the callbacks (|sample_deallocator_func|, // |decoder_status_func|, |player_status_func|, or |player_error_func| if it @@ -428,13 +430,13 @@ SbPlayerCreate(SbWindow window, SbDecodeTargetGraphicsContextProvider* context_provider); // Returns the preferred output mode of the implementation when a video -// described by |creation_param| is played. It is assumed that it is okay to +// described by |creation_param| is played. It is assumed that it is okay to // call SbPlayerCreate() with the same video described by |creation_param|, // with its |output_mode| member replaced by the returned output mode. // When the caller has no preference on the output mode, it will set // |creation_param->output_mode| to |kSbPlayerOutputModeInvalid|, and the // implementation can return its preferred output mode based on the information -// contained in |creation_param|. The caller can also set +// contained in |creation_param|. The caller can also set // |creation_param->output_mode| to its preferred output mode, and the // implementation should return the same output mode if it is supported, // otherwise the implementation should return an output mode that it is @@ -451,10 +453,11 @@ SbPlayerGetPreferredOutputMode(const SbPlayerCreationParam* creation_param); // * Upon calling this method, there should be one call to the player status // callback (i.e. |player_status_func| used in the creation of the player) // which indicates the player is destroyed. Note, the callback has to be -// in-flight when SbPlayerDestroyed is called. +// inflight when SbPlayerDestroyed is called. // * No more other callbacks should be issued after this function returns. // * It is not allowed to pass |player| into any other |SbPlayer| function // once SbPlayerDestroy has been called on that player. +// // |player|: The player to be destroyed. Must not be |kSbPlayerInvalid|. SB_EXPORT void SbPlayerDestroy(SbPlayer player); @@ -463,29 +466,29 @@ SB_EXPORT void SbPlayerDestroy(SbPlayer player); // The player should restart playback once it can display the frame at // |seek_to_timestamp|, or the closest it can get. (Some players can only seek // to I-Frames, for example.) -// -// - Seek must be called before samples are sent when starting playback for -// the first time, or the client never receives the -// |kSbPlayerDecoderStateNeedsData| signal. -// - A call to seek may interrupt another seek. -// - After this function is called, the client should not send any more audio -// or video samples until |SbPlayerDecoderStatusFunc| is called back with -// |kSbPlayerDecoderStateNeedsData| for each required media type. -// |SbPlayerDecoderStatusFunc| is the |decoder_status_func| callback function -// that was specified when the player was created (SbPlayerCreate). +// * Seek must be called before samples are sent when starting playback for +// the first time, or the client never receives the +// |kSbPlayerDecoderStateNeedsData| signal. +// * A call to seek may interrupt another seek. +// * After this function is called, the client should not send any more audio +// or video samples until |SbPlayerDecoderStatusFunc| is called back with +// |kSbPlayerDecoderStateNeedsData| for each required media type. +// |SbPlayerDecoderStatusFunc| is the |decoder_status_func| callback function +// that was specified when the player was created (SbPlayerCreate). // // |player|: The SbPlayer in which the seek operation is being performed. -// Must not be |kSbPlayerInvalid|. - +// Must not be |kSbPlayerInvalid|. +// // |seek_to_timestamp|: The frame at which playback should begin. -// |ticket|: A user-supplied unique ID that is be passed to all subsequent -// |SbPlayerDecoderStatusFunc| calls. (That is the |decoder_status_func| -// callback function specified when calling SbPlayerCreate.) -// -// The |ticket| value is used to filter calls that may have been in flight -// when SbPlayerSeek was called. To be very specific, once SbPlayerSeek has -// been called with ticket X, a client should ignore all -// |SbPlayerDecoderStatusFunc| calls that do not pass in ticket X. +// +// |ticket|: A user-supplied unique ID to be passed to all subsequent +// |SbPlayerDecoderStatusFunc| calls. (That is the |decoder_status_func| +// callback function specified when calling SbPlayerCreate.) +// +// The |ticket| value is used to filter calls that may have been in flight +// when SbPlayerSeek was called. To be very specific, once SbPlayerSeek has +// been called with ticket X, a client should ignore all +// |SbPlayerDecoderStatusFunc| calls that do not pass in ticket X. #if SB_API_VERSION >= 15 SB_EXPORT void SbPlayerSeek(SbPlayer player, int64_t seek_to_timestamp, @@ -507,19 +510,21 @@ SB_EXPORT void SbPlayerSeek2(SbPlayer player, // SbPlayerWriteSamples() allows writing of multiple samples in one call. // // |player|: The player to which the sample is written. Must not be -// |kSbPlayerInvalid|. - +// |kSbPlayerInvalid|. +// // |sample_type|: The type of sample being written. See the |SbMediaType| -// enum in media.h. +// enum in media.h. +// // |sample_infos|: A pointer to an array of SbPlayerSampleInfo with -// |number_of_sample_infos| elements, each holds the data for an sample, i.e. -// a sequence of whole NAL Units for video, or a complete audio frame. -// |sample_infos| cannot be assumed to live past the call into -// SbPlayerWriteSamples(), so it must be copied if its content will be used -// after SbPlayerWriteSamples() returns. +// |number_of_sample_infos| elements, each holds the data for an sample, i.e. +// a sequence of whole NAL Units for video, or a complete audio frame. +// |sample_infos| cannot be assumed to live past the call into +// SbPlayerWriteSamples(), so it must be copied if its content will be used +// after SbPlayerWriteSamples() returns. +// // |number_of_sample_infos|: Specify the number of samples contained inside -// |sample_infos|. It has to be at least one, and at most the return value -// of SbPlayerGetMaximumNumberOfSamplesPerWrite(). +// |sample_infos|. It has to be at least one, and at most the return value +// of SbPlayerGetMaximumNumberOfSamplesPerWrite(). #if SB_API_VERSION >= 15 SB_EXPORT void SbPlayerWriteSamples(SbPlayer player, #else // SB_API_VERSION >= 15 @@ -538,8 +543,9 @@ SB_EXPORT void SbPlayerWriteSample2(SbPlayer player, // SbPlayerWriteSamples() will always be called with one sample. // // |player|: The player for which the number is retrieved. +// // |sample_type|: The type of sample for which the number is retrieved. See the -// |SbMediaType| enum in media.h. +// |SbMediaType| enum in media.h. SB_EXPORT int SbPlayerGetMaximumNumberOfSamplesPerWrite( SbPlayer player, SbMediaType sample_type); @@ -550,13 +556,14 @@ SB_EXPORT int SbPlayerGetMaximumNumberOfSamplesPerWrite( // contents, after a call to SbPlayerSeek. // // |player|: The player to which the marker is written. +// // |stream_type|: The type of stream for which the marker is written. SB_EXPORT void SbPlayerWriteEndOfStream(SbPlayer player, SbMediaType stream_type); // Sets the player bounds to the given graphics plane coordinates. The changes // do not take effect until the next graphics frame buffer swap. The default -// bounds for a player is the full screen. This function is only relevant when +// bounds for a player is the full screen. This function is only relevant when // the |player| is created with the kSbPlayerOutputModePunchOut output mode, and // if this is not the case then this function call can be ignored. // @@ -567,12 +574,17 @@ SB_EXPORT void SbPlayerWriteEndOfStream(SbPlayer player, // with such frequent calls. // // |player|: The player that is being resized. Must not be |kSbPlayerInvalid|. -// |z_index|: The z-index of the player. When the bounds of multiple players -// are overlapped, the one with larger z-index will be rendered on -// top of the ones with smaller z-index. +// +// |z_index|: The z-index of the player. When the bounds of multiple players +// are overlapped, the one with larger z-index will be rendered on +// top of the ones with smaller z-index. +// // |x|: The x-coordinate of the upper-left corner of the player. +// // |y|: The y-coordinate of the upper-left corner of the player. +// // |width|: The width of the player, in pixels. +// // |height|: The height of the player, in pixels. SB_EXPORT void SbPlayerSetBounds(SbPlayer player, int z_index, @@ -581,12 +593,12 @@ SB_EXPORT void SbPlayerSetBounds(SbPlayer player, int width, int height); -// Set the playback rate of the |player|. |rate| is default to 1.0 which -// indicates the playback is at its original speed. A |rate| greater than one -// will make the playback faster than its original speed. For example, when +// Set the playback rate of the |player|. |rate| is default to 1.0 which +// indicates the playback is at its original speed. A |rate| greater than one +// will make the playback faster than its original speed. For example, when // |rate| is 2, the video will be played at twice the speed as its original -// speed. A |rate| less than 1.0 will make the playback slower than its -// original speed. When |rate| is 0, the playback will be paused. +// speed. A |rate| less than 1.0 will make the playback slower than its +// original speed. When |rate| is 0, the playback will be paused. // The function returns true when the playback rate is set to |playback_rate| or // to a rate that is close to |playback_rate| which the implementation supports. // It returns false when the playback rate is unchanged, this can happen when @@ -598,10 +610,11 @@ SB_EXPORT bool SbPlayerSetPlaybackRate(SbPlayer player, double playback_rate); // Sets the player's volume. // // |player|: The player in which the volume is being adjusted. Must not be -// |kSbPlayerInvalid|. +// |kSbPlayerInvalid|. +// // |volume|: The new player volume. The value must be between |0.0| and |1.0|, -// inclusive. A value of |0.0| means that the audio should be muted, and a -// value of |1.0| means that it should be played at full volume. +// inclusive. A value of |0.0| means that the audio should be muted, and a +// value of |1.0| means that it should be played at full volume. SB_EXPORT void SbPlayerSetVolume(SbPlayer player, double volume); // Gets a snapshot of the current player state and writes it to @@ -609,9 +622,9 @@ SB_EXPORT void SbPlayerSetVolume(SbPlayer player, double volume); // expected to be inexpensive. // // |player|: The player about which information is being retrieved. Must not be -// |kSbPlayerInvalid|. +// |kSbPlayerInvalid|. +// // |out_player_info|: The information retrieved for the player. - #if SB_API_VERSION >= 15 SB_EXPORT void SbPlayerGetInfo(SbPlayer player, SbPlayerInfo* out_player_info); #else // SB_API_VERSION >= 15 @@ -621,9 +634,9 @@ SB_EXPORT void SbPlayerGetInfo2(SbPlayer player, // Given a player created with the kSbPlayerOutputModeDecodeToTexture // output mode, it will return a SbDecodeTarget representing the current frame -// to be rasterized. On GLES systems, this function must be called on a +// to be rasterized. On GLES systems, this function must be called on a // thread with an EGLContext current, and specifically the EGLContext that will -// be used to eventually render the frame. If this function is called with a +// be used to eventually render the frame. If this function is called with a // |player| object that was created with an output mode other than // kSbPlayerOutputModeDecodeToTexture, kSbDecodeTargetInvalid is returned. // @@ -633,58 +646,56 @@ SB_EXPORT SbDecodeTarget SbPlayerGetCurrentFrame(SbPlayer player); // Returns the audio configurations used by |player|. // // Returns true when |out_audio_configuration| is filled with the information of -// the configuration of the audio output devices used by |player|. Returns +// the configuration of the audio output devices used by |player|. Returns // false for |index| 0 to indicate that there is no audio output for this -// |player|. Returns false for |index| greater than 0 to indicate that there +// |player|. Returns false for |index| greater than 0 to indicate that there // are no more audio output configurations other than the ones already returned. // // The app will use the information returned to determine audio related // behaviors, like: -// -// Audio Write Duration: Audio write duration is how far past the current -// playback position the app will write audio samples. The app will write -// all samples between |current_playback_position| and -// |current_playback_position| + |audio_write_duration|, as soon as they -// are available. -// -// |audio_write_duration| will be to `kSbPlayerWriteDurationLocal` when -// all audio configurations linked to |player| is local, or if there isn't -// any audio output. It will be set to `kSbPlayerWriteDurationRemote` for -// remote or wireless audio outputs, i.e. one of -// `kSbMediaAudioConnectorBluetooth` or `kSbMediaAudioConnectorRemote*`. -// -// The app only guarantees to write |audio_write_duration| past -// |current_playback_position|, but the app is free to write more samples -// than that. So the platform shouldn't rely on this for flow control. -// The platform should achieve flow control by sending -// `kSbPlayerDecoderStateNeedsData` less frequently. -// -// The platform is responsible for guaranteeing that when only -// |audio_write_duration| audio samples are written at a time, no playback -// issues occur (such as transient or indefinite hanging). +// * Audio Write Duration: Audio write duration is how far past the current +// playback position the app will write audio samples. The app will write +// all samples between |current_playback_position| and +// |current_playback_position| + |audio_write_duration|, as soon as they +// are available. +// * |audio_write_duration| will be to |kSbPlayerWriteDurationLocal| when +// all audio configurations linked to |player| is local, or if there isn't +// any audio output. It will be set to |kSbPlayerWriteDurationRemote| for +// remote or wireless audio outputs, i.e. one of +// |kSbMediaAudioConnectorBluetooth| or |kSbMediaAudioConnectorRemote*|. +// * The app only guarantees to write |audio_write_duration| past +// |current_playback_position|, but the app is free to write more samples +// than that. So the platform shouldn't rely on this for flow control. +// The platform should achieve flow control by sending +// |kSbPlayerDecoderStateNeedsData| less frequently. +// * The platform is responsible for guaranteeing that when only +// |audio_write_duration| audio samples are written at a time, no playback +// issues occur (such as transient or indefinite hanging). // // The audio configurations should be available as soon as possible, and they -// have to be available when the |player| is at `kSbPlayerStatePresenting`, +// have to be available when the |player| is at |kSbPlayerStatePresenting|, // unless the audio codec is |kSbMediaAudioCodecNone| or there's no written // audio inputs. // -// The app will set |audio_write_duration| to `kSbPlayerWriteDurationLocal` +// The app will set |audio_write_duration| to |kSbPlayerWriteDurationLocal| // when the audio configuration isn't available (i.e. the function returns false -// when index is 0). The platform has to make the audio configuration +// when index is 0). The platform has to make the audio configuration // available immediately after the SbPlayer is created, if it expects the app to // treat the platform as using wireless audio outputs. // // Once at least one audio configurations are returned, the return values and -// their orders shouldn't change during the life time of |player|. The platform +// their orders shouldn't change during the life time of |player|. The platform // may inform the app of any changes by sending -// `kSbPlayerErrorCapabilityChanged` to request a playback restart. +// |kSbPlayerErrorCapabilityChanged| to request a playback restart. // // |player|: The player about which information is being retrieved. Must not be -// |kSbPlayerInvalid|. -// |index|: The index of the audio output configuration. Must be greater than -// or equal to 0. +// |kSbPlayerInvalid|. +// +// |index|: The index of the audio output configuration. Must be greater than +// or equal to 0. +// // |out_audio_configuration|: The information about the audio output, refer to -// |SbMediaAudioConfiguration| for more details. Must not be NULL. +// |SbMediaAudioConfiguration| for more details. Must not be NULL. #if SB_API_VERSION >= 15 SB_EXPORT bool SbPlayerGetAudioConfiguration( SbPlayer player, diff --git a/starboard/shared/modular/BUILD.gn b/starboard/shared/modular/BUILD.gn index 7d76132d5166..6149fbf4f45f 100644 --- a/starboard/shared/modular/BUILD.gn +++ b/starboard/shared/modular/BUILD.gn @@ -14,7 +14,9 @@ # TODO: b/315170518 - Revert to static library after fixing # symbol visibility issues for windows based modular platform builds. -if (sb_is_modular || sb_is_evergreen_compatible) { +if ((sb_is_modular || sb_is_evergreen_compatible) && + (current_toolchain == starboard_toolchain || + build_with_separate_cobalt_toolchain)) { source_set("starboard_layer_posix_abi_wrappers") { sources = [ "starboard_layer_posix_file_abi_wrappers.cc", diff --git a/third_party/dav1d/METADATA b/third_party/dav1d/METADATA index 9ffd4f204c8e..5bb0d602b2ee 100644 --- a/third_party/dav1d/METADATA +++ b/third_party/dav1d/METADATA @@ -1,12 +1,12 @@ third_party { identifier { type: "ChromiumVersion" - value: "113.0.5672.134" # from https://chromereleases.googleblog.com/2023/05/stable-channel-update-for-chromeos_19.html + value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html } identifier { type: "Git" value: "https://chromium.googlesource.com/chromium/src.git" - version: "1ff736ff5bff3c365b0b351f1d8abfbed2b28747" + version: "1759c6ae9316996b9f150c0ce9d0ca78a3d15c02" } identifier { type: "UpstreamSubdir" diff --git a/third_party/dav1d/libdav1d/METADATA b/third_party/dav1d/libdav1d/METADATA index c87d874af17d..8d987e1a4036 100644 --- a/third_party/dav1d/libdav1d/METADATA +++ b/third_party/dav1d/libdav1d/METADATA @@ -1,12 +1,12 @@ third_party { identifier { type: "ChromiumVersion" - value: "113.0.5672.134" # from https://chromereleases.googleblog.com/2023/05/stable-channel-update-for-chromeos_19.html + value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html } identifier { type: "Git" value: "https://chromium.googlesource.com/external/github.com/videolan/dav1d.git" version: "d426d1c91075b9c552b12dd052af1cd0368f05a2" - # from https://chromium.googlesource.com/chromium/src/+/113.0.5672.134/DEPS#1122 + # from https://chromium.googlesource.com/chromium/src/+/114.0.5735.358/DEPS#1106 } } diff --git a/third_party/freetype/BUILD.gn b/third_party/freetype/BUILD.gn index 92d43c6e742f..95e4c8a90a3c 100644 --- a/third_party/freetype/BUILD.gn +++ b/third_party/freetype/BUILD.gn @@ -140,6 +140,12 @@ source_set("freetype_source") { defines += [ "FT2_BUILD_LIBRARY" ] + if (use_system_harfbuzz) { + configs += [ "//third_party/harfbuzz-ng:harfbuzz_from_pkgconfig" ] + } else { + configs += [ "//third_party/harfbuzz-ng:harfbuzz_config" ] + } + configs -= [ "//build/config/compiler:chromium_code" ] configs += [ "//build/config/compiler:no_chromium_code" ] configs += [ "//build/config/sanitizers:cfi_icall_generalize_pointers" ] configs += [ ":freetype-warnings" ] diff --git a/third_party/freetype/METADATA b/third_party/freetype/METADATA index 66f02f02b837..1eeff65303ba 100644 --- a/third_party/freetype/METADATA +++ b/third_party/freetype/METADATA @@ -1,12 +1,12 @@ third_party { identifier { type: "ChromiumVersion" - value: "112.0.5615.134" # from https://chromereleases.googleblog.com/2023/04/stable-channel-update-for-chromeos_19.html + value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html } identifier { type: "Git" value: "https://chromium.googlesource.com/chromium/src.git" - version: "53b87ba394bbdcf2f9d63e985ca5385a5b420ca9" + version: "1759c6ae9316996b9f150c0ce9d0ca78a3d15c02" } identifier { type: "UpstreamSubdir" diff --git a/third_party/freetype/README.chromium b/third_party/freetype/README.chromium index 58630e40d5ab..703c7d3fecf1 100644 --- a/third_party/freetype/README.chromium +++ b/third_party/freetype/README.chromium @@ -1,8 +1,8 @@ Name: FreeType URL: http://www.freetype.org/ -Version: VER-2-13-0-69 -Revision: e78e2d29a95baf6053e30cc9422aa20319259803 -CPEPrefix: cpe:/a:freetype:freetype:2.13.0 +Version: VER-2-13-0-76-g0a3836c97 +Revision: 0a3836c97d5e84d6721ac0fd2839e8ae1b7be8d9 +CPEPrefix: cpe:/a:freetype:freetype:2.12.1 License: Custom license "inspired by the BSD, Artistic, and IJG (Independent JPEG Group) licenses" License File: src/docs/FTL.TXT diff --git a/third_party/freetype/src/METADATA b/third_party/freetype/src/METADATA index 585ae0c96a91..0ad64e096aac 100644 --- a/third_party/freetype/src/METADATA +++ b/third_party/freetype/src/METADATA @@ -5,13 +5,13 @@ description: third_party { identifier { type: "ChromiumVersion" - value: "112.0.5615.134" # from https://chromereleases.googleblog.com/2023/04/stable-channel-update-for-chromeos_19.html + value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html } identifier { type: "Git" value: "https://chromium.googlesource.com/chromium/src/third_party/freetype2.git" - version: "e78e2d29a95baf6053e30cc9422aa20319259803" - # from https://chromium.googlesource.com/chromium/src/+/112.0.5615.134/DEPS#353 + version: "0a3836c97d5e84d6721ac0fd2839e8ae1b7be8d9" + # from https://chromium.googlesource.com/chromium/src/+/114.0.5735.358/DEPS#347 } last_upgrade_date { year: 2023 diff --git a/third_party/freetype/src/include/freetype/freetype.h b/third_party/freetype/src/include/freetype/freetype.h index efff74fe399e..e855e6cb64f8 100644 --- a/third_party/freetype/src/include/freetype/freetype.h +++ b/third_party/freetype/src/include/freetype/freetype.h @@ -1002,7 +1002,7 @@ FT_BEGIN_HEADER * Note that the bounding box might be off by (at least) one pixel for * hinted fonts. See @FT_Size_Metrics for further discussion. * - * Note that the bounding box does not vary in OpenType variable fonts + * Note that the bounding box does not vary in OpenType variation fonts * and should only be used in relation to the default instance. * * units_per_EM :: @@ -1090,9 +1090,9 @@ FT_BEGIN_HEADER FT_Generic generic; - /*# The following member variables (down to `underline_thickness`) */ - /*# are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ - /*# for bitmap fonts. */ + /* The following member variables (down to `underline_thickness`) */ + /* are only relevant to scalable outlines; cf. @FT_Bitmap_Size */ + /* for bitmap fonts. */ FT_BBox bbox; FT_UShort units_per_EM; @@ -1110,7 +1110,7 @@ FT_BEGIN_HEADER FT_Size size; FT_CharMap charmap; - /*@private begin */ + /* private fields, internal to FreeType */ FT_Driver driver; FT_Memory memory; @@ -1123,8 +1123,6 @@ FT_BEGIN_HEADER FT_Face_Internal internal; - /*@private end */ - } FT_FaceRec; diff --git a/third_party/freetype/src/include/freetype/internal/services/svmetric.h b/third_party/freetype/src/include/freetype/internal/services/svmetric.h index d067dc977cc9..167617ebb3d0 100644 --- a/third_party/freetype/src/include/freetype/internal/services/svmetric.h +++ b/third_party/freetype/src/include/freetype/internal/services/svmetric.h @@ -77,7 +77,7 @@ FT_BEGIN_HEADER typedef void (*FT_Metrics_Adjust_Func)( FT_Face face ); - typedef void + typedef FT_Error (*FT_Size_Reset_Func)( FT_Size size ); diff --git a/third_party/freetype/src/src/cid/cidgload.c b/third_party/freetype/src/src/cid/cidgload.c index ba4b7565d547..66e298331609 100644 --- a/third_party/freetype/src/src/cid/cidgload.c +++ b/third_party/freetype/src/src/cid/cidgload.c @@ -117,11 +117,44 @@ off2 = cid_get_offset( &p, cid->gd_bytes ); FT_FRAME_EXIT(); - if ( fd_select >= cid->num_dicts || - off2 > stream->size || - off1 > off2 ) + + if ( fd_select >= cid->num_dicts ) { - FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" )); + /* + * fd_select == 0xFF is often used to indicate that the CID + * has no charstring to be rendered, similar to GID = 0xFFFF + * in TrueType fonts. + */ + if ( (cid->fd_bytes == 1 && fd_select == 0xFFU ) || + (cid->fd_bytes == 2 && fd_select == 0xFFFFU ) ) + { + FT_TRACE1(( "cid_load_glyph: fail for glyph_index=%d, " + "FD number %d is the max integer fitting into %d byte%s\n", + glyph_index, fd_select, cid->fd_bytes, + cid->fd_bytes == 1 ? "" : "s" )); + } + else + { + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " + "FD number %d > number of dicts %d\n", + glyph_index, fd_select, cid->num_dicts )); + } + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off2 > stream->size ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " + "end of the glyph data is beyond the data stream\n", + glyph_index )); + error = FT_THROW( Invalid_Offset ); + goto Exit; + } + else if ( off1 > off2 ) + { + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " + "the end position of glyph data is set before the start position\n", + glyph_index )); error = FT_THROW( Invalid_Offset ); goto Exit; } @@ -161,7 +194,9 @@ cs_offset = decoder->lenIV >= 0 ? (FT_UInt)decoder->lenIV : 0; if ( cs_offset > glyph_length ) { - FT_TRACE0(( "cid_load_glyph: invalid glyph stream offsets\n" )); + FT_TRACE0(( "cid_load_glyph: fail for glyph_index=%d, " + "offset to the charstring is beyond glyph length\n", + glyph_index )); error = FT_THROW( Invalid_Offset ); goto Exit; } diff --git a/third_party/freetype/src/src/sfnt/sfdriver.c b/third_party/freetype/src/src/sfnt/sfdriver.c index 762883db5420..70c63417b3ef 100644 --- a/third_party/freetype/src/src/sfnt/sfdriver.c +++ b/third_party/freetype/src/src/sfnt/sfdriver.c @@ -523,15 +523,14 @@ FT_TRACE0(( "get_win_string:" " Character 0x%X invalid in PS name string\n", ((unsigned)p[0])*256 + (unsigned)p[1] )); - break; + continue; } } - if ( !len ) - *r = '\0'; + *r = '\0'; FT_FRAME_EXIT(); - if ( !len ) + if ( r != result ) return result; get_win_string_error: @@ -580,15 +579,14 @@ FT_TRACE0(( "get_apple_string:" " Character `%c' (0x%X) invalid in PS name string\n", *p, *p )); - break; + continue; } } - if ( !len ) - *r = '\0'; + *r = '\0'; FT_FRAME_EXIT(); - if ( !len ) + if ( r != result ) return result; get_apple_string_error: @@ -819,9 +817,9 @@ if ( !found ) { - /* as a last resort we try the family name; note that this is */ - /* not in the Adobe TechNote, but GX fonts (which predate the */ - /* TechNote) benefit from this behaviour */ + /* according to the 'name' documentation in the OpenType */ + /* specification the font family name is to be used if the */ + /* typographic family name is missing, so let's do that */ found = sfnt_get_name_id( face, TT_NAME_ID_FONT_FAMILY, &win, @@ -853,6 +851,10 @@ { FT_TRACE0(( "sfnt_get_var_ps_name:" " No valid PS name prefix for font instances found\n" )); + /* XXX It probably makes sense to never let this fail */ + /* since an arbitrary prefix should work, too. */ + /* On the other hand, it is very unlikely that */ + /* we ever reach this code at all. */ return NULL; } diff --git a/third_party/freetype/src/src/truetype/ttgxvar.c b/third_party/freetype/src/src/truetype/ttgxvar.c index 3af028aac9d7..80553c93aebd 100644 --- a/third_party/freetype/src/src/truetype/ttgxvar.c +++ b/third_party/freetype/src/src/truetype/ttgxvar.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include diff --git a/third_party/freetype/src/src/truetype/ttinterp.c b/third_party/freetype/src/src/truetype/ttinterp.c index 8cf66ebaecc7..c6a6cde6b51c 100644 --- a/third_party/freetype/src/src/truetype/ttinterp.c +++ b/third_party/freetype/src/src/truetype/ttinterp.c @@ -7321,14 +7321,6 @@ * GETINFO[]: GET INFOrmation * Opcode range: 0x88 * Stack: uint32 --> uint32 - * - * XXX: UNDOCUMENTED: Selector bits higher than 9 are currently (May - * 2015) not documented in the OpenType specification. - * - * Selector bit 11 is incorrectly described as bit 8, while the - * real meaning of bit 8 (vertical LCD subpixels) stays - * undocumented. The same mistake can be found in Greg Hitchcock's - * whitepaper. */ static void Ins_GETINFO( TT_ExecContext exc, @@ -7387,8 +7379,6 @@ * VARIATION GLYPH * Selector Bit: 3 * Return Bit(s): 10 - * - * XXX: UNDOCUMENTED! */ if ( (args[0] & 8 ) != 0 && exc->face->blend ) K |= 1 << 10; diff --git a/third_party/freetype/src/src/truetype/ttobjs.c b/third_party/freetype/src/src/truetype/ttobjs.c index ee4f3de1bba9..c351e082b606 100644 --- a/third_party/freetype/src/src/truetype/ttobjs.c +++ b/third_party/freetype/src/src/truetype/ttobjs.c @@ -1346,12 +1346,16 @@ * Used for variation fonts as an iterator function. * * @Input: - * size :: - * A handle to the target size object. + * ft_size :: + * A handle to the target TT_Size object. This function will be called + * through a `FT_Size_Reset_Func` pointer which takes `FT_Size`. This + * function must take `FT_Size` as a result. The passed `FT_Size` is + * expected to point to a `TT_Size`. */ FT_LOCAL_DEF( FT_Error ) - tt_size_reset_height( TT_Size size ) + tt_size_reset_height( FT_Size ft_size ) { + TT_Size size = (TT_Size)ft_size; TT_Face face = (TT_Face)size->root.face; FT_Size_Metrics* size_metrics = &size->hinted_metrics; @@ -1408,7 +1412,7 @@ FT_Size_Metrics* size_metrics = &size->hinted_metrics; - error = tt_size_reset_height( size ); + error = tt_size_reset_height( (FT_Size)size ); if ( error ) return error; diff --git a/third_party/freetype/src/src/truetype/ttobjs.h b/third_party/freetype/src/src/truetype/ttobjs.h index d74264e57930..d1834c046f31 100644 --- a/third_party/freetype/src/src/truetype/ttobjs.h +++ b/third_party/freetype/src/src/truetype/ttobjs.h @@ -391,7 +391,7 @@ FT_BEGIN_HEADER #endif /* TT_USE_BYTECODE_INTERPRETER */ FT_LOCAL( FT_Error ) - tt_size_reset_height( TT_Size size ); + tt_size_reset_height( FT_Size size ); FT_LOCAL( FT_Error ) tt_size_reset( TT_Size size ); diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn index 61f564c76e41..216f825afe2a 100644 --- a/third_party/harfbuzz-ng/BUILD.gn +++ b/third_party/harfbuzz-ng/BUILD.gn @@ -64,6 +64,16 @@ if (use_system_harfbuzz) { ] sources = [ + "src/src/OT/Color/CBDT/CBDT.hh", + "src/src/OT/Color/COLR/COLR.hh", + "src/src/OT/Color/CPAL/CPAL.hh", + "src/src/OT/Color/sbix/sbix.hh", + "src/src/OT/Color/svg/svg.hh", + "src/src/OT/Layout/GDEF/GDEF.hh", + "src/src/OT/glyf/VarCompositeGlyph.hh", + "src/src/OT/glyf/composite-iter.hh", + "src/src/OT/glyf/coord-setter.hh", + "src/src/OT/name/name.hh", "src/src/graph/classdef-graph.hh", "src/src/graph/coverage-graph.hh", "src/src/graph/gsubgpos-context.cc", @@ -98,7 +108,8 @@ if (use_system_harfbuzz) { "src/src/hb-blob.cc", "src/src/hb-blob.hh", "src/src/hb-buffer-deserialize-json.hh", - "src/src/hb-buffer-deserialize-text.hh", + "src/src/hb-buffer-deserialize-text-glyphs.hh", + "src/src/hb-buffer-deserialize-text-unicode.hh", "src/src/hb-buffer-serialize.cc", "src/src/hb-buffer-verify.cc", "src/src/hb-buffer.cc", @@ -117,6 +128,7 @@ if (use_system_harfbuzz) { "src/src/hb-draw.cc", "src/src/hb-draw.h", "src/src/hb-draw.hh", + "src/src/hb-face-builder.cc", "src/src/hb-face.cc", "src/src/hb-face.hh", "src/src/hb-font.cc", @@ -125,11 +137,13 @@ if (use_system_harfbuzz) { "src/src/hb-icu.cc", "src/src/hb-iter.hh", "src/src/hb-kern.hh", + "src/src/hb-limits.hh", "src/src/hb-machinery.hh", "src/src/hb-map.cc", "src/src/hb-map.hh", "src/src/hb-meta.hh", "src/src/hb-ms-feature-ranges.hh", + "src/src/hb-multimap.hh", "src/src/hb-mutex.hh", "src/src/hb-null.hh", "src/src/hb-number-parser.hh", @@ -145,12 +159,6 @@ if (use_system_harfbuzz) { "src/src/hb-ot-cff2-table.cc", "src/src/hb-ot-cff2-table.hh", "src/src/hb-ot-cmap-table.hh", - "src/src/hb-ot-color-cbdt-table.hh", - "src/src/hb-ot-color-colr-table.hh", - "src/src/hb-ot-color-colrv1-closure.hh", - "src/src/hb-ot-color-cpal-table.hh", - "src/src/hb-ot-color-sbix-table.hh", - "src/src/hb-ot-color-svg-table.hh", "src/src/hb-ot-color.cc", "src/src/hb-ot-color.h", "src/src/hb-ot-deprecated.h", @@ -233,12 +241,15 @@ if (use_system_harfbuzz) { "src/src/hb-ot-tag.cc", "src/src/hb-ot-var-avar-table.hh", "src/src/hb-ot-var-common.hh", + "src/src/hb-ot-var-cvar-table.hh", "src/src/hb-ot-var-fvar-table.hh", "src/src/hb-ot-var-gvar-table.hh", "src/src/hb-ot-var-hvar-table.hh", "src/src/hb-ot-var-mvar-table.hh", "src/src/hb-ot-var.cc", "src/src/hb-ot-vorg-table.hh", + "src/src/hb-paint-extents.cc", + "src/src/hb-paint-extents.hh", "src/src/hb-pool.hh", "src/src/hb-priority-queue.hh", "src/src/hb-repacker.hh", @@ -309,6 +320,7 @@ if (use_system_harfbuzz) { "HAVE_ICU", "HAVE_ICU_BUILTIN", "HB_NO_MMAP", + "HB_NO_PAINT", "HB_NO_RESOURCE_FORK", # Size reductions by disabling parts that we do not currently require: diff --git a/third_party/harfbuzz-ng/METADATA b/third_party/harfbuzz-ng/METADATA index 220da2ca5a4c..7e41e63d40d4 100644 --- a/third_party/harfbuzz-ng/METADATA +++ b/third_party/harfbuzz-ng/METADATA @@ -1,12 +1,12 @@ third_party { identifier { type: "ChromiumVersion" - value: "112.0.5615.134" # from https://chromereleases.googleblog.com/2023/04/stable-channel-update-for-chromeos_19.html + value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html } identifier { type: "Git" value: "https://chromium.googlesource.com/chromium/src.git" - version: "53b87ba394bbdcf2f9d63e985ca5385a5b420ca9" + version: "1759c6ae9316996b9f150c0ce9d0ca78a3d15c02" } identifier { type: "UpstreamSubdir" diff --git a/third_party/harfbuzz-ng/src/.ci/build-win32.sh b/third_party/harfbuzz-ng/src/.ci/build-win32.sh index a1ca53d27ebc..f97db2a1ebb6 100755 --- a/third_party/harfbuzz-ng/src/.ci/build-win32.sh +++ b/third_party/harfbuzz-ng/src/.ci/build-win32.sh @@ -2,15 +2,17 @@ set -e meson --cross-file=.ci/win32-cross-file.txt \ - --wrap-mode=forcefallback \ + --wrap-mode=default \ -Dtests=disabled \ -Dcairo=enabled \ -Dcairo:fontconfig=disabled \ + -Dcairo:freetype=disabled \ + -Dcairo:dwrite=disabled \ + -Dcairo:tests=disabled \ -Dglib=enabled \ - -Dfreetype=enabled \ + -Dfreetype=disabled \ -Dgdi=enabled \ -Ddirectwrite=enabled \ - -Dcairo=enabled \ win32build \ $@ diff --git a/third_party/harfbuzz-ng/src/.ci/build-win64.sh b/third_party/harfbuzz-ng/src/.ci/build-win64.sh index 385d55974b09..b34ac0c19958 100644 --- a/third_party/harfbuzz-ng/src/.ci/build-win64.sh +++ b/third_party/harfbuzz-ng/src/.ci/build-win64.sh @@ -2,15 +2,17 @@ set -e meson --cross-file=.ci/win64-cross-file.txt \ - --wrap-mode=forcefallback \ + --wrap-mode=default \ -Dtests=disabled \ -Dcairo=enabled \ -Dcairo:fontconfig=disabled \ + -Dcairo:freetype=disabled \ + -Dcairo:dwrite=disabled \ + -Dcairo:tests=disabled \ -Dglib=enabled \ - -Dfreetype=enabled \ + -Dfreetype=disabled \ -Dgdi=enabled \ -Ddirectwrite=enabled \ - -Dcairo=enabled \ win64build \ $@ diff --git a/third_party/harfbuzz-ng/src/.circleci/config.yml b/third_party/harfbuzz-ng/src/.circleci/config.yml index 9525c4aec931..a149b36104fd 100644 --- a/third_party/harfbuzz-ng/src/.circleci/config.yml +++ b/third_party/harfbuzz-ng/src/.circleci/config.yml @@ -18,9 +18,9 @@ jobs: xcode: "12.5.1" steps: - checkout - - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection gtk-doc ninja + - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config ragel freetype glib cairo python3 icu4c graphite2 gobject-introspection ninja - run: pip3 install meson --upgrade - - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled + - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson setup build -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Ddocs=disabled - run: meson compile -Cbuild - run: meson test -Cbuild --print-errorlogs - store_artifacts: @@ -57,8 +57,8 @@ jobs: steps: - checkout - run: dnf install -y pkg-config ragel valgrind gcc gcc-c++ meson git glib2-devel freetype-devel cairo-devel libicu-devel gobject-introspection-devel graphite2-devel redhat-rpm-config python python-pip || true - - run: meson build --buildtype=debugoptimized - - run: ninja -Cbuild -j9 + - run: meson setup build --buildtype=debugoptimized + - run: meson compile -Cbuild -j9 # TOOD: increase timeouts and remove --no-suite=slow - run: RUN_VALGRIND=1 meson test -Cbuild --no-suite=slow --wrap='valgrind --leak-check=full --error-exitcode=1' --print-errorlogs --num-processes=$(($(nproc)/2 + 1)) @@ -69,24 +69,9 @@ jobs: - checkout - run: apk update && apk add ragel gcc g++ glib-dev freetype-dev cairo-dev git py3-pip ninja - run: pip3 install meson==0.56.0 - - run: meson build --buildtype=minsize - - run: ninja -Cbuild -j9 - - run: meson test -Cbuild --print-errorlogs - - archlinux: - docker: - - image: archlinux/base - steps: - - checkout - - run: pacman --noconfirm -Syu freetype2 meson git clang cairo icu gettext gobject-introspection gcc gcc-libs glib2 graphite pkg-config ragel python python-pip base-devel gtk-doc - - run: pip install flake8 fonttools - - run: flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics - - run: meson build -Dgraphite=enabled -Dauto_features=enabled -Dexperimental_api=true + - run: meson setup build --buildtype=minsize - run: meson compile -Cbuild -j9 - run: meson test -Cbuild --print-errorlogs - - run: meson dist -Cbuild - - run: clang -c src/harfbuzz.cc -DHB_NO_MT - - run: clang -c src/hb-*.cc -DHB_NO_MT -DHB_TINY -DHB_NO_OT_FONT asan-ubsan: docker: @@ -96,8 +81,9 @@ jobs: - run: apt update || true - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev - run: pip3 install meson==0.56.0 - - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true - - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=address,undefined --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true + - run: meson compile -Cbuild -j9 + - run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt tsan: docker: @@ -107,8 +93,9 @@ jobs: - run: apt update || true - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev - run: pip3 install meson==0.56.0 - - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true - - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=thread --buildtype=debugoptimized --wrap-mode=nodownload -Dexperimental_api=true + - run: meson compile -Cbuild -j9 + - run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt msan: docker: @@ -119,8 +106,9 @@ jobs: - run: DEBIAN_FRONTEND=noninteractive apt install -y python3 python3-pip ninja-build clang lld git binutils pkg-config ragel libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev - run: pip3 install meson==0.56.0 # msan, needs --force-fallback-for=glib,freetype2 also which doesn't work yet but runs fuzzer cases at least - - run: CC=clang CXX=clang++ meson build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true - - run: ninja -Cbuild -j8 && meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt + - run: CC=clang CXX=clang++ meson setup build --default-library=static -Db_sanitize=memory --buildtype=debugoptimized --wrap-mode=nodownload -Dauto_features=disabled -Dtests=enabled -Dexperimental_api=true + - run: meson compile -Cbuild -j9 + - run: meson test -Cbuild --print-errorlogs | asan_symbolize | c++filt clang-cxx2a: docker: @@ -135,8 +123,8 @@ jobs: executor: win32-executor steps: - checkout - - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-i686 zip - - run: pip3 install meson==0.56.0 --upgrade + - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-i686 zip + - run: pip3 install meson==0.60.0 - run: .ci/build-win32.sh - store_artifacts: path: harfbuzz-win32.zip @@ -158,8 +146,8 @@ jobs: executor: win64-executor steps: - checkout - - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build gtk-doc-tools python3 python3-pip git g++-mingw-w64-x86-64 zip - - run: pip3 install meson==0.56.0 --upgrade + - run: sudo apt update && DEBIAN_FRONTEND=noninteractive sudo apt install -y ninja-build python3 python3-pip git g++-mingw-w64-x86-64 zip + - run: pip3 install meson==0.60.0 - run: bash .ci/build-win64.sh - store_artifacts: path: harfbuzz-win64.zip @@ -198,7 +186,6 @@ workflows: ignore: /.*/ - fedora-valgrind - alpine - #- archlinux - asan-ubsan - tsan - msan diff --git a/third_party/harfbuzz-ng/src/.codecov.yml b/third_party/harfbuzz-ng/src/.codecov.yml index abd04ca9ff52..40928b9325f1 100644 --- a/third_party/harfbuzz-ng/src/.codecov.yml +++ b/third_party/harfbuzz-ng/src/.codecov.yml @@ -1,8 +1,10 @@ -comment: off +comment: false coverage: status: project: default: - threshold: 1% - patch: off + informational: true + patch: + default: + informational: true diff --git a/third_party/harfbuzz-ng/src/.github/workflows/cifuzz.yml b/third_party/harfbuzz-ng/src/.github/workflows/cifuzz.yml index 07e4cd575366..7d6e24669654 100644 --- a/third_party/harfbuzz-ng/src/.github/workflows/cifuzz.yml +++ b/third_party/harfbuzz-ng/src/.github/workflows/cifuzz.yml @@ -1,5 +1,9 @@ name: CIFuzz on: [pull_request] + +permissions: + contents: read + jobs: Fuzzing: runs-on: ubuntu-latest diff --git a/third_party/harfbuzz-ng/src/.github/workflows/configs-build.yml b/third_party/harfbuzz-ng/src/.github/workflows/configs-build.yml index 9f4fd78e69bc..b81ce92b0f30 100644 --- a/third_party/harfbuzz-ng/src/.github/workflows/configs-build.yml +++ b/third_party/harfbuzz-ng/src/.github/workflows/configs-build.yml @@ -11,7 +11,7 @@ permissions: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v3 diff --git a/third_party/harfbuzz-ng/src/.github/workflows/linux-ci.yml b/third_party/harfbuzz-ng/src/.github/workflows/linux-ci.yml index f67f5d3fedb4..3ec2eea47317 100644 --- a/third_party/harfbuzz-ng/src/.github/workflows/linux-ci.yml +++ b/third_party/harfbuzz-ng/src/.github/workflows/linux-ci.yml @@ -12,46 +12,60 @@ permissions: jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 - - name: install dependencies - run: sudo apt-get update && sudo apt-get install pkg-config gcc gtk-doc-tools libfreetype6-dev libglib2.0-dev libcairo2-dev libicu-dev libgraphite2-dev python3 python3-setuptools ninja-build gobject-introspection libgirepository1.0-dev - - run: sudo pip3 install fonttools meson==0.56.0 gcovr==5.0 - - name: run - run: meson build -Db_coverage=true --auto-features=enabled -Dgraphite=enabled -Dchafa=disabled -Dragel_subproject=true -Doptimization=2 - - name: ci + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }} + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install \ + gcc \ + gobject-introspection \ + gtk-doc-tools \ + libcairo2-dev \ + libfreetype6-dev \ + libgirepository1.0-dev \ + libglib2.0-dev \ + libgraphite2-dev \ + libicu-dev \ + ninja-build \ + pkg-config \ + python3 \ + python3-setuptools + - name: Install Python Dependencies + run: sudo pip3 install fonttools meson==0.56.0 gcovr==5.0 + - name: Setup Meson + run: | + ccache --version + meson setup build \ + -Dauto_features=enabled \ + -Dchafa=disabled \ + -Dgraphite=enabled \ + -Doptimization=2 \ + -Db_coverage=true \ + -Ddoc_tests=true \ + -Dragel_subproject=true + - name: Build + run: meson compile -Cbuild + - name: Test run: meson test --print-errorlogs -Cbuild - - - name: generate documentations + - name: Generate Documentations run: ninja -Cbuild harfbuzz-doc - - name: deploy documentations + - name: Deploy Documentations if: github.ref_type == 'tag' run: .ci/deploy-docs.sh env: GH_TOKEN: ${{ secrets.GH_TOKEN }} REVISION: ${{ github.sha }} - - # waiting for https://github.com/rhysd/github-action-benchmark/issues/36 to happen - # - name: benchmark - # run: build/perf/perf --benchmark_format=json > perf/result.json - # - name: store benchmark result - # uses: rhysd/github-action-benchmark@b2ee598 - # if: github.event_name != 'pull_request' - # with: - # name: C++ Benchmark - # tool: 'googlecpp' - # output-file-path: perf/result.json - # gh-pages-branch: gh-pages - # github-token: ${{ secrets.PERSONAL_GITHUB_TOKEN }} - # auto-push: true - # alert-threshold: '150%' - # comment-on-alert: true - # fail-on-alert: true - - - name: cov + - name: Generate Coverage run: ninja -Cbuild coverage-xml - - uses: codecov/codecov-action@v3 + - name: Upload Coverage + uses: codecov/codecov-action@v3 with: file: build/meson-logs/coverage.xml diff --git a/third_party/harfbuzz-ng/src/.github/workflows/macos-ci.yml b/third_party/harfbuzz-ng/src/.github/workflows/macos-ci.yml index a6b6d3dbf889..e84cb38b35f0 100644 --- a/third_party/harfbuzz-ng/src/.github/workflows/macos-ci.yml +++ b/third_party/harfbuzz-ng/src/.github/workflows/macos-ci.yml @@ -14,17 +14,47 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v3 - - name: install dependencies - run: HOMEBREW_NO_AUTO_UPDATE=1 brew install pkg-config freetype glib glib-utils cairo icu4c graphite2 gobject-introspection gtk-doc ninja - - run: pip3 install fonttools meson==0.56.0 gcovr==5.0 - - name: run - run: PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" meson build -Db_coverage=true -Dcoretext=enabled -Dgraphite=enabled -Dauto_features=enabled -Dchafa=disabled -Doptimization=2 - - name: ci + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + key: ${{ github.job }}-${{ runner.os }}-${{ runner.arch }} + - name: Install Dependencies + run: | + export HOMEBREW_NO_AUTO_UPDATE=1 + export HOMEBREW_NO_INSTALL_CLEANUP=1 + brew install \ + cairo \ + freetype \ + glib \ + gobject-introspection \ + graphite2 \ + icu4c \ + meson \ + ninja \ + pkg-config + - name: Install Python Dependencies + run: pip3 install fonttools gcovr==5.0 + - name: Setup Meson + run: | + export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:/usr/local/opt/libffi/lib/pkgconfig" + ccache --version + meson setup build \ + -Dauto_features=enabled \ + -Ddocs=disabled \ + -Dchafa=disabled \ + -Dcoretext=enabled \ + -Dgraphite=enabled \ + -Doptimization=2 \ + -Db_coverage=true \ + - name: Build + run: meson compile -Cbuild + - name: Test run: meson test --print-errorlogs -Cbuild - - - name: cov + - name: Generate Coverage run: ninja -Cbuild coverage-xml - - uses: codecov/codecov-action@v3 + - name: Upload Coverage + uses: codecov/codecov-action@v3 with: file: build/meson-logs/coverage.xml diff --git a/third_party/harfbuzz-ng/src/.github/workflows/msvc-ci.yml b/third_party/harfbuzz-ng/src/.github/workflows/msvc-ci.yml index 57aef04cbe37..57ab3af2cea9 100644 --- a/third_party/harfbuzz-ng/src/.github/workflows/msvc-ci.yml +++ b/third_party/harfbuzz-ng/src/.github/workflows/msvc-ci.yml @@ -14,6 +14,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [windows-2019, windows-latest] include: @@ -26,33 +27,35 @@ jobs: name: ${{ matrix.name }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - uses: ilammy/msvc-dev-cmd@v1 - with: - arch : ${{ matrix.ARCH }} - - name: Upgrade pip - run: | - python -m pip install -U pip - - name: Install Dependencies - run: | - pip install --upgrade meson ninja fonttools - - name: Build - run: | - # This dir contains a pkg-config which meson will happily use and later fail, so remove it - $env:path = ($env:path.Split(';') | Where-Object { $_ -ne 'C:\Strawberry\perl\bin' }) -join ';' - - meson setup build ` - --wrap-mode=default ` - --buildtype=release ` - -Dglib=enabled ` - -Dfreetype=enabled ` - -Dgdi=enabled ` - -Ddirectwrite=enabled - - meson compile -C build - - name: Test - run: | - meson test --print-errorlogs --suite=harfbuzz -C build + - name: Checkout + uses: actions/checkout@v3 + - name: Setup Ccache + uses: hendrikmuhs/ccache-action@v1.2 + with: + variant: sccache + key: ${{ github.job }}-${{ matrix.os }}-${{ matrix.ARCH }} + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: Setup MSVC + uses: ilammy/msvc-dev-cmd@v1 + with: + arch : ${{ matrix.ARCH }} + - name: Install Python Dependencies + run: | + pip install --upgrade meson ninja fonttools + - name: Setup Meson + run: | + sccache --version + meson setup build ` + --wrap-mode=forcefallback ` + --buildtype=release ` + -Dglib=enabled ` + -Dfreetype=enabled ` + -Dgdi=enabled ` + -Ddirectwrite=enabled + - name: Build + run: meson compile -Cbuild + - name: Test + run: meson test --print-errorlogs --suite=harfbuzz -Cbuild diff --git a/third_party/harfbuzz-ng/src/.github/workflows/msys2-ci.yml b/third_party/harfbuzz-ng/src/.github/workflows/msys2-ci.yml index 0704f4caff5b..d825fd043ad0 100644 --- a/third_party/harfbuzz-ng/src/.github/workflows/msys2-ci.yml +++ b/third_party/harfbuzz-ng/src/.github/workflows/msys2-ci.yml @@ -14,6 +14,7 @@ jobs: runs-on: windows-latest strategy: + fail-fast: false matrix: include: - MSYSTEM: MINGW32 @@ -22,47 +23,51 @@ jobs: MSYS2_ARCH: x86_64 name: ${{ matrix.MSYSTEM }} + env: + # XXX: For some reason enabling jit debugging "fixes" random python crashes + # see https://github.com/msys2/MINGW-packages/issues/11864 + MSYS: "winjitdebug" + defaults: run: shell: msys2 {0} steps: - - uses: actions/checkout@v3 - - uses: msys2/setup-msys2@v2 - with: - msystem: ${{ matrix.MSYSTEM }} - update: true - install: >- - mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo - mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype - mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc - mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs - mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext - mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2 - mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection - mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2 - mingw-w64-${{ matrix.MSYS2_ARCH }}-icu - mingw-w64-${{ matrix.MSYS2_ARCH }}-meson - mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja - mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config - mingw-w64-${{ matrix.MSYS2_ARCH }}-python - mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip - mingw-w64-${{ matrix.MSYS2_ARCH }}-ragel - - name: Install Python Dependencies - run: | - pip install --upgrade fonttools - - name: Build - run: | - meson build \ - --wrap-mode=nodownload \ - --auto-features=enabled \ - -Ddirectwrite=enabled \ - -Dgdi=enabled \ - -Dgraphite=enabled \ - -Dchafa=disabled - ninja -C build - - name: Test - run: | - meson test \ - --print-errorlogs \ - --suite=harfbuzz \ - -C build + - name: Checkout + uses: actions/checkout@v3 + - name: Setup MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.MSYSTEM }} + update: true + install: >- + mingw-w64-${{ matrix.MSYS2_ARCH }}-cairo + mingw-w64-${{ matrix.MSYS2_ARCH }}-freetype + mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc + mingw-w64-${{ matrix.MSYS2_ARCH }}-gcc-libs + mingw-w64-${{ matrix.MSYS2_ARCH }}-gettext + mingw-w64-${{ matrix.MSYS2_ARCH }}-glib2 + mingw-w64-${{ matrix.MSYS2_ARCH }}-gobject-introspection + mingw-w64-${{ matrix.MSYS2_ARCH }}-graphite2 + mingw-w64-${{ matrix.MSYS2_ARCH }}-icu + mingw-w64-${{ matrix.MSYS2_ARCH }}-meson + mingw-w64-${{ matrix.MSYS2_ARCH }}-ninja + mingw-w64-${{ matrix.MSYS2_ARCH }}-pkg-config + mingw-w64-${{ matrix.MSYS2_ARCH }}-python + mingw-w64-${{ matrix.MSYS2_ARCH }}-python-pip + - name: Install Python Dependencies + run: | + pip install --upgrade fonttools + - name: Setup Meson + run: | + meson setup build \ + --wrap-mode=nodownload \ + --auto-features=enabled \ + -Ddocs=disabled \ + -Ddirectwrite=enabled \ + -Dgdi=enabled \ + -Dgraphite=enabled \ + -Dchafa=disabled + - name: Build + run: meson compile -Cbuild + - name: Test + run: meson test --print-errorlogs --suite=harfbuzz -Cbuild diff --git a/third_party/harfbuzz-ng/src/CMakeLists.txt b/third_party/harfbuzz-ng/src/CMakeLists.txt index 97980ef59d8b..e22f2cfdd57c 100644 --- a/third_party/harfbuzz-ng/src/CMakeLists.txt +++ b/third_party/harfbuzz-ng/src/CMakeLists.txt @@ -566,7 +566,7 @@ if (HB_HAVE_INTROSPECTION) # We need to account for the varying output directories # when we build using Visual Studio projects if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*") - set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") + set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") else () set (hb_libpath "$") endif () @@ -816,7 +816,7 @@ if (NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL) make_pkgconfig_pc_file("harfbuzz-gobject") if (HB_HAVE_INTROSPECTION) if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio*") - set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") + set (hb_libpath "${CMAKE_CURRENT_BINARY_DIR}/$") else () set (hb_libpath "$") endif () diff --git a/third_party/harfbuzz-ng/src/COPYING b/third_party/harfbuzz-ng/src/COPYING index 48d1b30f90dc..1dd917e9f2e7 100644 --- a/third_party/harfbuzz-ng/src/COPYING +++ b/third_party/harfbuzz-ng/src/COPYING @@ -2,19 +2,23 @@ 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,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc. -Copyright © 2018,2019,2020 Ebrahim Byagowi +Copyright © 2010-2022 Google, Inc. +Copyright © 2015-2020 Ebrahim Byagowi Copyright © 2019,2020 Facebook, Inc. -Copyright © 2012 Mozilla Foundation +Copyright © 2012,2015 Mozilla Foundation Copyright © 2011 Codethink Limited Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies) Copyright © 2009 Keith Stribley -Copyright © 2009 Martin Hosken and SIL International +Copyright © 2011 Martin Hosken and SIL International Copyright © 2007 Chris Wilson -Copyright © 2005,2006,2020,2021 Behdad Esfahbod -Copyright © 2005 David Turner -Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc. -Copyright © 1998-2004 David Turner and Werner Lemberg +Copyright © 2005,2006,2020,2021,2022,2023 Behdad Esfahbod +Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023 Red Hat, Inc. +Copyright © 1998-2005 David Turner and Werner Lemberg +Copyright © 2016 Igalia S.L. +Copyright © 2022 Matthias Clasen +Copyright © 2018,2021 Khaled Hosny +Copyright © 2018,2019,2020 Adobe, Inc +Copyright © 2013-2015 Alexei Podtelezhnikov For full copyright notices consult the individual files in the package. diff --git a/third_party/harfbuzz-ng/src/METADATA b/third_party/harfbuzz-ng/src/METADATA index de011d3cbab6..8a33eef7b3a3 100644 --- a/third_party/harfbuzz-ng/src/METADATA +++ b/third_party/harfbuzz-ng/src/METADATA @@ -1,12 +1,12 @@ third_party { identifier { type: "ChromiumVersion" - value: "112.0.5615.134" # from https://chromereleases.googleblog.com/2023/04/stable-channel-update-for-chromeos_19.html + value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html } identifier { type: "Git" - value: "https://chromium.googlesource.com/chromium/src/third_party/freetype2.git" - version: "2822b589bc837fae6f66233e2cf2eef0f6ce8470" - # from https://chromium.googlesource.com/chromium/src/+/112.0.5615.134/DEPS#361 + value: "https://chromium.googlesource.com/external/github.com/harfbuzz/harfbuzz.git" + version: "2175f5d050743317c563ec9414e0f83a47f7fbc4" + # from https://chromium.googlesource.com/chromium/src/+/114.0.5735.358/DEPS#355 } } diff --git a/third_party/harfbuzz-ng/src/NEWS b/third_party/harfbuzz-ng/src/NEWS index 8d4389fc67bb..5ed287822d00 100644 --- a/third_party/harfbuzz-ng/src/NEWS +++ b/third_party/harfbuzz-ng/src/NEWS @@ -1,3 +1,211 @@ +Overview of changes leading to 7.1.0 +Friday, March 3, 2023 +==================================== +- New experimental hb_shape_justify() API that uses font variations to expand + or shrink the text to a given advance. (Behdad Esfahbod) +- Various build and bug fixes. (Behdad Esfahbod, Garret Rieger, Qunxin Liu) + +- New API: ++hb_font_set_variation() + +Overview of changes leading to 7.0.1 +Monday, February 20, 2023 +==================================== +- Various build and bug fixes. + + +Overview of changes leading to 7.0.0 +Saturday, February 11, 2023 +==================================== +- New hb-paint API that is designed mainly to paint “COLRv1” glyphs, but can be + also used as a unified API to paint any of the glyph representations + supported by HarfBuzz (B/W outlines, color layers, or color bitmaps). + (Behdad Esfahbod, Matthias Clasen) +- New hb-cairo API for integrating with cairo graphics library. This is provided + as a separate harfbuzz-cairo library. (Behdad Esfahbod, Matthias Clasen) +- Support for instancing “CFF2” table. (Behdad Esfahbod) +- Support font emboldening. (Behdad Esfahbod) +- Support feature ranges with AAT shaping. (Behdad Esfahbod) +- Experimental support to cubic curves in “glyf” table, see + https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md + for spec. (Behdad Esfahbod) +- Various subsetter improvements. (Garret Rieger, Qunxin Liu, Behdad Esfahbod) +- Various documentation improvements. + (Behdad Esfahbod, Matthias Clasen, Khaled Hosny) +- Significantly reduced memory use during shaping. (Behdad Esfahbod) +- Greatly reduced memory use during subsetting “CFF” table. (Behdad Esfahbod) +- New command line utility, hb-info, for querying various font information. + (Behdad Esfahbod, Matthias Clasen) +- New hb-shape/hb-view options: --glyphs, --color-palette, --font-bold, + --font-grade, and --named-instance. (Behdad Esfahbod) +- Miscellaneous fixes and improvements. + (Amir Masoud Abdol, Andres Salomon, Behdad Esfahbod, Chun-wei Fan, + Garret Rieger, Jens Kutilek, Khaled Hosny, Konstantin Käfer, Matthias Clasen, + Nirbheek Chauhan, Pedro J. Estébanez, Qunxin Liu, Sergei Trofimovich) + +- New API: ++HB_FONT_NO_VAR_NAMED_INSTANCE ++HB_PAINT_IMAGE_FORMAT_BGRA ++HB_PAINT_IMAGE_FORMAT_PNG ++HB_PAINT_IMAGE_FORMAT_SVG ++hb_cairo_font_face_create_for_face ++hb_cairo_font_face_create_for_font ++hb_cairo_font_face_get_face ++hb_cairo_font_face_get_font ++hb_cairo_font_face_get_scale_factor ++hb_cairo_font_face_set_font_init_func ++hb_cairo_font_face_set_scale_factor ++hb_cairo_font_init_func_t ++hb_cairo_glyphs_from_buffer ++hb_cairo_scaled_font_get_font ++hb_color_line_get_color_stops ++hb_color_line_get_color_stops_func_t ++hb_color_line_get_extend ++hb_color_line_get_extend_func_t ++hb_color_line_t ++hb_color_stop_t ++hb_draw_funcs_get_empty ++hb_draw_funcs_get_user_data ++hb_draw_funcs_set_user_data ++hb_face_collect_nominal_glyph_mapping ++hb_font_draw_glyph ++hb_font_draw_glyph_func_t ++hb_font_funcs_set_draw_glyph_func ++hb_font_funcs_set_paint_glyph_func ++hb_font_get_synthetic_bold ++hb_font_get_var_named_instance ++hb_font_paint_glyph ++hb_font_paint_glyph_func_t ++hb_font_set_synthetic_bold ++hb_map_keys ++hb_map_next ++hb_map_update ++hb_map_values ++hb_ot_color_glyph_has_paint ++hb_ot_color_has_paint ++hb_ot_layout_script_select_language2 ++hb_ot_name_id_predefined_t ++hb_paint_color ++hb_paint_color_func_t ++hb_paint_composite_mode_t ++hb_paint_custom_palette_color ++hb_paint_custom_palette_color_func_t ++hb_paint_extend_t ++hb_paint_funcs_create ++hb_paint_funcs_destroy ++hb_paint_funcs_get_empty ++hb_paint_funcs_get_user_data ++hb_paint_funcs_is_immutable ++hb_paint_funcs_make_immutable ++hb_paint_funcs_reference ++hb_paint_funcs_set_color_func ++hb_paint_funcs_set_custom_palette_color_func ++hb_paint_funcs_set_image_func ++hb_paint_funcs_set_linear_gradient_func ++hb_paint_funcs_set_pop_clip_func ++hb_paint_funcs_set_pop_group_func ++hb_paint_funcs_set_pop_transform_func ++hb_paint_funcs_set_push_clip_glyph_func ++hb_paint_funcs_set_push_clip_rectangle_func ++hb_paint_funcs_set_push_group_func ++hb_paint_funcs_set_push_transform_func ++hb_paint_funcs_set_radial_gradient_func ++hb_paint_funcs_set_sweep_gradient_func ++hb_paint_funcs_set_user_data ++hb_paint_funcs_t ++hb_paint_image ++hb_paint_image_func_t ++hb_paint_linear_gradient ++hb_paint_linear_gradient_func_t ++hb_paint_pop_clip ++hb_paint_pop_clip_func_t ++hb_paint_pop_group ++hb_paint_pop_group_func_t ++hb_paint_pop_transform ++hb_paint_pop_transform_func_t ++hb_paint_push_clip_glyph ++hb_paint_push_clip_glyph_func_t ++hb_paint_push_clip_rectangle ++hb_paint_push_clip_rectangle_func_t ++hb_paint_push_group ++hb_paint_push_group_func_t ++hb_paint_push_transform ++hb_paint_push_transform_func_t ++hb_paint_radial_gradient ++hb_paint_radial_gradient_func_t ++hb_paint_sweep_gradient ++hb_paint_sweep_gradient_func_t ++hb_set_is_inverted ++hb_subset_input_keep_everything + +- Deprecated API: ++hb_font_funcs_set_glyph_shape_func ++hb_font_get_glyph_shape_func_t ++hb_font_get_glyph_shape + + +Overview of changes leading to 6.0.0 +Friday, December 16, 2022 +==================================== +- A new API have been added to pre-process the face and speed up future + subsetting operations on that face. Provides up to a 95% reduction in + subsetting times when the same face is subset more than once. + + For more details and benchmarks, see: + https://github.com/harfbuzz/harfbuzz/blob/main/docs/subset-preprocessing.md + + (Garret Rieger, Behdad Esfahbod) + +- Shaping have been speedup by skipping entire lookups when the buffer contents + don't intersect with the lookup. Shows up to a 10% speedup in shaping some + fonts. (Behdad Esfahbod) + +- A new experimental feature, “Variable Composites” (enabled by passing + -Dexperimental_api=true to meson), is also featured in this release. + This technology enables drastic compression of fonts in the Chinese, + Japanese, Korean, and other writing systems, by reusing the OpenType Font + Variations technology for encoding “smart components” into the font. + + The specification for these extensions to the font format can be found in: + https://github.com/harfbuzz/boring-expansion-spec/blob/glyf1/glyf1.md + + A test variable-font with ~7160 Hangul syllables derived from the + NotoSerifKR-VF font has been built, with existing OpenType technology, as + well as with the new Variable Composites (VarComposites) technology. The + VarComposites font is over 90% smaller than the OpenType version of the font! + Both fonts can be obtained from the “smarties” repository: + https://github.com/behdad/smarties/tree/3.0/fonts/hangul/serif + + When building HarfBuzz with experimental features enabled, you can test + the “smarties” font with a sample character like this: + + $ hb-view butchered-hangul-serif-smarties-variable.ttf -u AE01 --variations=wght=700 + + (Behdad Esfahbod) + +- The HarfBuzz subsetter can now drop axes by pinning them to specific values + (also referred to as instancing). There are a couple of restrictions + currently: + + - Only works with TrueType (“glyf”) based fonts. “CFF2” fonts are not yet + supported. + - Only supports the case where all axes in a font are pinned. + + (Garret Rieger, Qunxin Liu) + +- Miscellaneous fixes and improvements. + + (Behdad Esfahbod, Christoph Reiter, David Corbett, Eli Schwartz, Garret + Rieger, Joel Auterson, Jordan Petridis, Khaled Hosny, Lorenz Wildberg, + Marco Rebhan, Martin Storsjö, Matthias Clasen, Qunxin Liu, Satadru Pramanik) + + +- New API ++hb_subset_input_pin_axis_location() ++hb_subset_input_pin_axis_to_default() ++hb_subset_preprocess() + + Overview of changes leading to 5.3.1 Wednesday, October 19, 2022 ==================================== diff --git a/third_party/harfbuzz-ng/src/RELEASING.md b/third_party/harfbuzz-ng/src/RELEASING.md index 8d5a4060b6e1..2e5f2bd82ebd 100644 --- a/third_party/harfbuzz-ng/src/RELEASING.md +++ b/third_party/harfbuzz-ng/src/RELEASING.md @@ -17,7 +17,7 @@ - [ ] Based on severity of changes, decide whether it's a minor or micro release number bump. -- [ ] Search for REPLACEME on the repository and replace it with the chosen version for the release. +- [ ] Search for 'XSince: REPLACEME' on the repository and replace it with the chosen version for the release, e.g. 'Since: 1.4.7'. - [ ] Make sure you have correct date and new version at the top of NEWS file. diff --git a/third_party/harfbuzz-ng/src/SECURITY.md b/third_party/harfbuzz-ng/src/SECURITY.md new file mode 100644 index 000000000000..69bb04456caf --- /dev/null +++ b/third_party/harfbuzz-ng/src/SECURITY.md @@ -0,0 +1,20 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it +privately. **Do not disclose it as a public issue.** This gives me time to work with you +to fix the issue before public exposure, reducing the chance that the exploit will be +used before a patch is released. + +You may submit the report in the following ways: + +- send an email to behdad@behdad.org and harfbuzz-admin@googlegroups.com; and/or +- send me a [private vulnerability report](https://github.com/harfbuzz/harfbuzz/security/advisories/new) + +Please provide the following information in your report: + +- A description of the vulnerability and its impact +- How to reproduce the issue + +This project is mostly maintained by two developers, working on a reasonable effort +basis. As such, we ask that you give us 90 days to work on a fix before public +disclosure. diff --git a/third_party/harfbuzz-ng/src/configure.ac b/third_party/harfbuzz-ng/src/configure.ac index f2480c349d30..c863ab83b0b2 100644 --- a/third_party/harfbuzz-ng/src/configure.ac +++ b/third_party/harfbuzz-ng/src/configure.ac @@ -1,6 +1,6 @@ AC_PREREQ([2.64]) AC_INIT([HarfBuzz], - [5.3.1], + [7.1.0], [https://github.com/harfbuzz/harfbuzz/issues/new], [harfbuzz], [http://harfbuzz.org/]) @@ -45,7 +45,7 @@ AC_SUBST(HB_VERSION) # Libtool version m4_define([hb_version_int], - m4_eval(hb_version_major*10000 + hb_version_minor*100 + hb_version_micro)) + m4_eval(60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro)) HB_LIBTOOL_VERSION_INFO=hb_version_int:0:hb_version_int AC_SUBST(HB_LIBTOOL_VERSION_INFO) diff --git a/third_party/harfbuzz-ng/src/docs/Makefile.am b/third_party/harfbuzz-ng/src/docs/Makefile.am index 36da8ae37c35..a9de8eb42181 100644 --- a/third_party/harfbuzz-ng/src/docs/Makefile.am +++ b/third_party/harfbuzz-ng/src/docs/Makefile.am @@ -29,7 +29,7 @@ SCANGOBJ_OPTIONS= # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" SCAN_OPTIONS=--rebuild-types --deprecated-guards="HB_DISABLE_DEPRECATED" \ - --ignore-decorators='HB_EXTERN|HB_DEPRECATED' + --ignore-decorators='HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()' # Header files or dirs to ignore when scanning. Use base file/dir names # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code diff --git a/third_party/harfbuzz-ng/src/docs/harfbuzz-docs.xml b/third_party/harfbuzz-ng/src/docs/harfbuzz-docs.xml index 652a5e470e18..e67ea8c39049 100644 --- a/third_party/harfbuzz-ng/src/docs/harfbuzz-docs.xml +++ b/third_party/harfbuzz-ng/src/docs/harfbuzz-docs.xml @@ -56,7 +56,9 @@ + + @@ -96,6 +98,7 @@ + @@ -115,76 +118,79 @@ API Index - Index of deprecated API - - Index of new symbols in 5.3.0 - Index of new symbols in 5.0.0 - Index of new symbols in 4.4.0 - Index of new symbols in 4.3.0 - Index of new symbols in 4.2.0 - Index of new symbols in 4.1.0 - Index of new symbols in 4.0.0 - Index of new symbols in 3.4.0 - Index of new symbols in 3.3.0 - Index of new symbols in 3.1.0 - Index of new symbols in 3.0.0 - Index of new symbols in 2.9.1 - Index of new symbols in 2.9.0 - Index of new symbols in 2.8.2 - Index of new symbols in 2.7.3 - Index of new symbols in 2.6.8 - Index of new symbols in 2.6.5 - Index of new symbols in 2.6.3 - Index of new symbols in 2.6.0 - Index of new symbols in 2.5.0 - Index of new symbols in 2.4.0 - Index of new symbols in 2.3.0 - Index of new symbols in 2.2.0 - Index of new symbols in 2.1.0 - Index of new symbols in 2.0.0 - Index of new symbols in 1.9.0 - Index of new symbols in 1.8.6 - Index of new symbols in 1.8.5 - Index of new symbols in 1.8.1 - Index of new symbols in 1.8.0 - Index of new symbols in 1.7.7 - Index of new symbols in 1.7.2 - Index of new symbols in 1.6.0 - Index of new symbols in 1.5.0 - Index of new symbols in 1.4.3 - Index of new symbols in 1.4.2 - Index of new symbols in 1.4.0 - Index of new symbols in 1.3.3 - Index of new symbols in 1.2.3 - Index of new symbols in 1.1.3 - Index of new symbols in 1.1.2 - Index of new symbols in 1.0.5 - Index of new symbols in 0.9.42 - Index of new symbols in 0.9.41 - Index of new symbols in 0.9.39 - Index of new symbols in 0.9.38 - Index of new symbols in 0.9.33 - Index of new symbols in 0.9.31 - Index of new symbols in 0.9.30 - Index of new symbols in 0.9.28 - Index of new symbols in 0.9.26 - Index of new symbols in 0.9.22 - Index of new symbols in 0.9.21 - Index of new symbols in 0.9.20 - Index of new symbols in 0.9.11 - Index of new symbols in 0.9.10 - Index of new symbols in 0.9.8 - Index of new symbols in 0.9.7 - Index of new symbols in 0.9.5 - Index of new symbols in 0.9.2 - Index of new symbols in 0.6.0 + Index of deprecated API + + Index of new symbols in 7.1.0 + Index of new symbols in 7.0.0 + Index of new symbols in 6.0.0 + Index of new symbols in 5.3.0 + Index of new symbols in 5.0.0 + Index of new symbols in 4.4.0 + Index of new symbols in 4.3.0 + Index of new symbols in 4.2.0 + Index of new symbols in 4.1.0 + Index of new symbols in 4.0.0 + Index of new symbols in 3.4.0 + Index of new symbols in 3.3.0 + Index of new symbols in 3.1.0 + Index of new symbols in 3.0.0 + Index of new symbols in 2.9.1 + Index of new symbols in 2.9.0 + Index of new symbols in 2.8.2 + Index of new symbols in 2.7.3 + Index of new symbols in 2.6.8 + Index of new symbols in 2.6.5 + Index of new symbols in 2.6.3 + Index of new symbols in 2.6.0 + Index of new symbols in 2.5.0 + Index of new symbols in 2.4.0 + Index of new symbols in 2.3.0 + Index of new symbols in 2.2.0 + Index of new symbols in 2.1.0 + Index of new symbols in 2.0.0 + Index of new symbols in 1.9.0 + Index of new symbols in 1.8.6 + Index of new symbols in 1.8.5 + Index of new symbols in 1.8.1 + Index of new symbols in 1.8.0 + Index of new symbols in 1.7.7 + Index of new symbols in 1.7.2 + Index of new symbols in 1.6.0 + Index of new symbols in 1.5.0 + Index of new symbols in 1.4.3 + Index of new symbols in 1.4.2 + Index of new symbols in 1.4.0 + Index of new symbols in 1.3.3 + Index of new symbols in 1.2.3 + Index of new symbols in 1.1.3 + Index of new symbols in 1.1.2 + Index of new symbols in 1.0.5 + Index of new symbols in 0.9.42 + Index of new symbols in 0.9.41 + Index of new symbols in 0.9.39 + Index of new symbols in 0.9.38 + Index of new symbols in 0.9.33 + Index of new symbols in 0.9.31 + Index of new symbols in 0.9.30 + Index of new symbols in 0.9.28 + Index of new symbols in 0.9.26 + Index of new symbols in 0.9.22 + Index of new symbols in 0.9.21 + Index of new symbols in 0.9.20 + Index of new symbols in 0.9.11 + Index of new symbols in 0.9.10 + Index of new symbols in 0.9.8 + Index of new symbols in 0.9.7 + Index of new symbols in 0.9.5 + Index of new symbols in 0.9.2 + Index of new symbols in 0.6.0 - The current HarfBuzz codebase is versioned 2.x.x and is stable + The current HarfBuzz codebase is stable and under active maintenance. This is what is used in latest versions of Firefox, GNOME, ChromeOS, Chrome, LibreOffice, XeTeX, Android, and KDE, among other places. diff --git a/third_party/harfbuzz-ng/src/docs/harfbuzz-sections.txt b/third_party/harfbuzz-ng/src/docs/harfbuzz-sections.txt index 3a7aa358c775..abed39fee8a2 100644 --- a/third_party/harfbuzz-ng/src/docs/harfbuzz-sections.txt +++ b/third_party/harfbuzz-ng/src/docs/harfbuzz-sections.txt @@ -1,3 +1,4 @@ +
HB_H_IN HB_OT_H_IN @@ -26,33 +27,33 @@ hb_blob_create_from_file hb_blob_create_from_file_or_fail hb_blob_create_sub_blob hb_blob_copy_writable_or_fail +hb_blob_get_empty +hb_blob_reference hb_blob_destroy +hb_blob_set_user_data +hb_blob_get_user_data +hb_blob_make_immutable +hb_blob_is_immutable hb_blob_get_data hb_blob_get_data_writable -hb_blob_get_empty hb_blob_get_length -hb_blob_get_user_data -hb_blob_is_immutable -hb_blob_make_immutable -hb_blob_reference -hb_blob_set_user_data hb_blob_t hb_memory_mode_t
hb-buffer -HB_SEGMENT_PROPERTIES_DEFAULT -HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT hb_buffer_create +hb_buffer_allocation_successful hb_buffer_create_similar -hb_buffer_reference hb_buffer_get_empty +hb_buffer_reference hb_buffer_destroy +hb_buffer_set_user_data +hb_buffer_get_user_data hb_buffer_reset hb_buffer_clear_contents hb_buffer_pre_allocate -hb_buffer_allocation_successful hb_buffer_add hb_buffer_add_codepoints hb_buffer_add_utf32 @@ -79,15 +80,14 @@ hb_buffer_get_segment_properties hb_buffer_guess_segment_properties hb_buffer_set_unicode_funcs hb_buffer_get_unicode_funcs -hb_buffer_set_user_data -hb_buffer_get_user_data hb_buffer_get_glyph_infos +hb_glyph_info_get_glyph_flags hb_buffer_get_glyph_positions hb_buffer_has_positions -hb_buffer_get_invisible_glyph hb_buffer_set_invisible_glyph -hb_buffer_get_not_found_glyph +hb_buffer_get_invisible_glyph hb_buffer_set_not_found_glyph +hb_buffer_get_not_found_glyph hb_buffer_set_replacement_codepoint hb_buffer_get_replacement_codepoint hb_buffer_normalize_glyphs @@ -106,9 +106,11 @@ hb_segment_properties_equal hb_segment_properties_hash hb_segment_properties_overlay hb_buffer_diff +hb_buffer_message_func_t hb_buffer_set_message_func +HB_SEGMENT_PROPERTIES_DEFAULT +HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT hb_buffer_t -hb_glyph_info_get_glyph_flags hb_glyph_info_t hb_glyph_flags_t hb_glyph_position_t @@ -119,18 +121,25 @@ hb_segment_properties_t hb_buffer_serialize_format_t hb_buffer_serialize_flags_t hb_buffer_diff_flags_t -hb_buffer_message_func_t
hb-common +HB_TAG +HB_UNTAG hb_tag_from_string hb_tag_to_string hb_direction_from_string hb_direction_to_string +HB_DIRECTION_REVERSE +HB_DIRECTION_IS_BACKWARD +HB_DIRECTION_IS_FORWARD +HB_DIRECTION_IS_HORIZONTAL +HB_DIRECTION_IS_VALID +HB_DIRECTION_IS_VERTICAL hb_script_from_iso15924_tag -hb_script_from_string hb_script_to_iso15924_tag +hb_script_from_string hb_script_get_horizontal_direction hb_language_from_string hb_language_to_string @@ -152,17 +161,9 @@ hb_position_t hb_tag_t hb_script_t hb_user_data_key_t -HB_TAG HB_TAG_NONE HB_TAG_MAX HB_TAG_MAX_SIGNED -HB_UNTAG -HB_DIRECTION_REVERSE -HB_DIRECTION_IS_BACKWARD -HB_DIRECTION_IS_FORWARD -HB_DIRECTION_IS_HORIZONTAL -HB_DIRECTION_IS_VALID -HB_DIRECTION_IS_VERTICAL HB_LANGUAGE_INVALID HB_FEATURE_GLOBAL_END HB_FEATURE_GLOBAL_START @@ -179,20 +180,35 @@ uint16_t uint32_t uint64_t uint8_t - HB_EXTERN HB_DEPRECATED HB_DEPRECATED_FOR
+
+hb-features +HB_HAS_CAIRO +HB_HAS_CORETEXT +HB_HAS_DIRECTWRITE +HB_HAS_FREETYPE +HB_HAS_GDI +HB_HAS_GLIB +HB_HAS_GOBJECT +HB_HAS_GRAPHITE +HB_HAS_ICU +HB_HAS_UNISCRIBE +
+
hb-draw -hb_draw_funcs_t hb_draw_funcs_create -hb_draw_funcs_destroy +hb_draw_funcs_get_empty hb_draw_funcs_reference -hb_draw_funcs_is_immutable +hb_draw_funcs_destroy +hb_draw_funcs_set_user_data +hb_draw_funcs_get_user_data hb_draw_funcs_make_immutable +hb_draw_funcs_is_immutable hb_draw_move_to_func_t hb_draw_funcs_set_move_to_func hb_draw_line_to_func_t @@ -203,13 +219,79 @@ hb_draw_cubic_to_func_t hb_draw_funcs_set_cubic_to_func hb_draw_close_path_func_t hb_draw_funcs_set_close_path_func -hb_draw_state_t -HB_DRAW_STATE_DEFAULT hb_draw_move_to hb_draw_line_to hb_draw_quadratic_to hb_draw_cubic_to hb_draw_close_path +HB_DRAW_STATE_DEFAULT +hb_draw_funcs_t +hb_draw_state_t +
+ +
+hb-paint +hb_paint_funcs_t +hb_paint_funcs_create +hb_paint_funcs_get_empty +hb_paint_funcs_reference +hb_paint_funcs_destroy +hb_paint_funcs_set_user_data +hb_paint_funcs_get_user_data +hb_paint_funcs_make_immutable +hb_paint_funcs_is_immutable + +hb_paint_push_transform_func_t +hb_paint_funcs_set_push_transform_func +hb_paint_pop_transform_func_t +hb_paint_funcs_set_pop_transform_func +hb_paint_push_clip_glyph_func_t +hb_paint_funcs_set_push_clip_glyph_func +hb_paint_push_clip_rectangle_func_t +hb_paint_funcs_set_push_clip_rectangle_func +hb_paint_pop_clip_func_t +hb_paint_funcs_set_pop_clip_func +hb_paint_color_func_t +hb_paint_funcs_set_color_func +HB_PAINT_IMAGE_FORMAT_PNG +HB_PAINT_IMAGE_FORMAT_SVG +HB_PAINT_IMAGE_FORMAT_BGRA +hb_paint_image_func_t +hb_paint_funcs_set_image_func +hb_color_line_t +hb_color_stop_t +hb_color_line_get_color_stops_func_t +hb_color_line_get_color_stops +hb_paint_extend_t +hb_color_line_get_extend_func_t +hb_color_line_get_extend +hb_paint_linear_gradient_func_t +hb_paint_funcs_set_linear_gradient_func +hb_paint_radial_gradient_func_t +hb_paint_funcs_set_radial_gradient_func +hb_paint_sweep_gradient_func_t +hb_paint_funcs_set_sweep_gradient_func +hb_paint_composite_mode_t +hb_paint_push_group_func_t +hb_paint_funcs_set_push_group_func +hb_paint_pop_group_func_t +hb_paint_funcs_set_pop_group_func +hb_paint_custom_palette_color_func_t +hb_paint_funcs_set_custom_palette_color_func + +hb_paint_push_transform +hb_paint_pop_transform +hb_paint_push_clip_glyph +hb_paint_push_clip_rectangle +hb_paint_pop_clip +hb_paint_color +hb_paint_image +hb_paint_linear_gradient +hb_paint_radial_gradient +hb_paint_sweep_gradient +hb_paint_push_group +hb_paint_pop_group +hb_paint_custom_palette_color
@@ -264,23 +346,24 @@ hb_face_count hb_face_t hb_face_create hb_face_create_for_tables -hb_face_destroy hb_face_get_empty +hb_face_reference +hb_face_destroy +hb_face_set_user_data +hb_face_get_user_data +hb_face_make_immutable +hb_face_is_immutable hb_face_get_table_tags +hb_face_set_glyph_count hb_face_get_glyph_count +hb_face_set_index hb_face_get_index +hb_face_set_upem hb_face_get_upem -hb_face_get_user_data -hb_face_is_immutable -hb_face_make_immutable -hb_face_reference hb_face_reference_blob hb_face_reference_table -hb_face_set_glyph_count -hb_face_set_index -hb_face_set_upem -hb_face_set_user_data hb_face_collect_unicodes +hb_face_collect_nominal_glyph_mapping hb_face_collect_variation_selectors hb_face_collect_variation_unicodes hb_face_builder_create @@ -293,113 +376,124 @@ hb_face_builder_sort_tables hb_font_add_glyph_origin_for_direction hb_font_create hb_font_create_sub_font -hb_font_destroy -hb_font_funcs_create -hb_font_funcs_destroy -hb_font_funcs_get_empty -hb_font_funcs_get_user_data -hb_font_funcs_is_immutable -hb_font_funcs_make_immutable -hb_font_funcs_reference -hb_font_funcs_set_glyph_contour_point_func -hb_font_funcs_set_glyph_extents_func -hb_font_funcs_set_glyph_from_name_func -hb_font_funcs_set_glyph_h_advance_func -hb_font_funcs_set_glyph_h_advances_func -hb_font_funcs_set_glyph_h_kerning_func -hb_font_funcs_set_glyph_h_origin_func -hb_font_funcs_set_glyph_name_func -hb_font_funcs_set_glyph_shape_func -hb_font_funcs_set_glyph_v_advance_func -hb_font_funcs_set_glyph_v_advances_func -hb_font_funcs_set_glyph_v_origin_func -hb_font_funcs_set_nominal_glyph_func -hb_font_funcs_set_nominal_glyphs_func -hb_font_funcs_set_user_data -hb_font_funcs_set_variation_glyph_func -hb_font_funcs_t hb_font_get_empty +hb_font_reference +hb_font_destroy +hb_font_set_user_data +hb_font_get_user_data +hb_font_make_immutable +hb_font_is_immutable +hb_font_set_face hb_font_get_face hb_font_get_glyph hb_font_get_glyph_advance_for_direction -hb_font_get_glyph_advance_func_t hb_font_get_glyph_advances_for_direction -hb_font_get_glyph_advances_func_t hb_font_get_glyph_contour_point hb_font_get_glyph_contour_point_for_origin -hb_font_get_glyph_contour_point_func_t hb_font_get_glyph_extents hb_font_get_glyph_extents_for_origin -hb_font_get_glyph_extents_func_t hb_font_get_glyph_from_name -hb_font_get_glyph_from_name_func_t hb_font_get_glyph_h_advance -hb_font_get_glyph_h_advance_func_t +hb_font_get_glyph_v_advance hb_font_get_glyph_h_advances -hb_font_get_glyph_h_advances_func_t +hb_font_get_glyph_v_advances hb_font_get_glyph_h_kerning -hb_font_get_glyph_h_kerning_func_t -hb_font_get_glyph_h_origin -hb_font_get_glyph_h_origin_func_t hb_font_get_glyph_kerning_for_direction -hb_font_get_glyph_kerning_func_t -hb_font_get_glyph_name -hb_font_get_glyph_name_func_t +hb_font_get_glyph_h_origin +hb_font_get_glyph_v_origin hb_font_get_glyph_origin_for_direction -hb_font_get_glyph_origin_func_t +hb_font_get_glyph_name hb_font_get_glyph_shape -hb_font_get_glyph_shape_func_t -hb_font_get_glyph_v_advance -hb_font_get_glyph_v_advance_func_t -hb_font_get_glyph_v_advances -hb_font_get_glyph_v_advances_func_t -hb_font_get_glyph_v_origin -hb_font_get_glyph_v_origin_func_t +hb_font_draw_glyph +hb_font_paint_glyph hb_font_get_nominal_glyph -hb_font_get_nominal_glyph_func_t hb_font_get_nominal_glyphs -hb_font_get_nominal_glyphs_func_t +hb_font_get_variation_glyph +hb_font_set_parent hb_font_get_parent +hb_font_set_ppem hb_font_get_ppem +hb_font_set_ptem hb_font_get_ptem +hb_font_set_scale hb_font_get_scale +hb_font_get_synthetic_bold +hb_font_set_synthetic_bold +hb_font_set_synthetic_slant hb_font_get_synthetic_slant -hb_font_get_user_data -hb_font_get_variation_glyph -hb_font_get_variation_glyph_func_t +hb_font_set_variations +hb_font_set_variation +HB_FONT_NO_VAR_NAMED_INSTANCE +hb_font_set_var_named_instance +hb_font_get_var_named_instance +hb_font_set_var_coords_design hb_font_get_var_coords_design +hb_font_set_var_coords_normalized hb_font_get_var_coords_normalized hb_font_glyph_from_string hb_font_glyph_to_string -hb_font_is_immutable -hb_font_make_immutable hb_font_get_serial hb_font_changed -hb_font_reference -hb_font_set_face hb_font_set_funcs hb_font_set_funcs_data -hb_font_set_parent -hb_font_set_ppem -hb_font_set_ptem -hb_font_set_scale -hb_font_set_synthetic_slant -hb_font_set_user_data -hb_font_set_variations -hb_font_set_var_coords_design -hb_font_set_var_coords_normalized -hb_font_set_var_named_instance hb_font_subtract_glyph_origin_for_direction +hb_font_funcs_create +hb_font_funcs_get_empty +hb_font_funcs_reference +hb_font_funcs_destroy +hb_font_funcs_set_user_data +hb_font_funcs_get_user_data +hb_font_funcs_make_immutable +hb_font_funcs_is_immutable +hb_font_get_glyph_contour_point_func_t +hb_font_funcs_set_glyph_contour_point_func +hb_font_get_glyph_extents_func_t +hb_font_funcs_set_glyph_extents_func +hb_font_get_glyph_from_name_func_t +hb_font_funcs_set_glyph_from_name_func +hb_font_get_glyph_advance_func_t +hb_font_get_glyph_h_advance_func_t +hb_font_funcs_set_glyph_h_advance_func +hb_font_get_glyph_v_advance_func_t +hb_font_funcs_set_glyph_v_advance_func +hb_font_get_glyph_advances_func_t +hb_font_get_glyph_h_advances_func_t +hb_font_funcs_set_glyph_h_advances_func +hb_font_get_glyph_v_advances_func_t +hb_font_funcs_set_glyph_v_advances_func +hb_font_get_glyph_kerning_func_t +hb_font_get_glyph_h_kerning_func_t +hb_font_funcs_set_glyph_h_kerning_func +hb_font_get_glyph_origin_func_t +hb_font_get_glyph_h_origin_func_t +hb_font_funcs_set_glyph_h_origin_func +hb_font_get_glyph_v_origin_func_t +hb_font_funcs_set_glyph_v_origin_func +hb_font_get_glyph_name_func_t +hb_font_funcs_set_glyph_name_func +hb_font_get_glyph_shape_func_t +hb_font_funcs_set_glyph_shape_func +hb_font_draw_glyph_func_t +hb_font_funcs_set_draw_glyph_func +hb_font_paint_glyph_func_t +hb_font_funcs_set_paint_glyph_func +hb_font_get_nominal_glyph_func_t +hb_font_funcs_set_nominal_glyph_func +hb_font_get_nominal_glyphs_func_t +hb_font_funcs_set_nominal_glyphs_func +hb_font_get_variation_glyph_func_t +hb_font_funcs_set_variation_glyph_func +hb_font_funcs_t hb_font_t hb_reference_table_func_t -hb_font_funcs_set_font_h_extents_func -hb_font_funcs_set_font_v_extents_func -hb_font_get_extents_for_direction hb_font_get_font_extents_func_t hb_font_get_font_h_extents_func_t +hb_font_funcs_set_font_h_extents_func hb_font_get_font_v_extents_func_t +hb_font_funcs_set_font_v_extents_func hb_font_get_h_extents hb_font_get_v_extents +hb_font_get_extents_for_direction hb_font_extents_t hb_glyph_extents_t
@@ -450,30 +544,33 @@ hb_icu_script_to_script
hb-map -HB_MAP_VALUE_INVALID +hb_map_create hb_map_allocation_successful -hb_map_clear hb_map_copy -hb_map_create -hb_map_del +hb_map_clear +hb_map_get_empty +hb_map_reference hb_map_destroy +hb_map_set_user_data +hb_map_get_user_data +hb_map_set hb_map_get -hb_map_get_empty +hb_map_del +hb_map_has hb_map_get_population +hb_map_is_empty hb_map_is_equal -hb_map_get_user_data -hb_map_has hb_map_hash -hb_map_is_empty -hb_map_reference -hb_map_set -hb_map_set_user_data +hb_map_update +hb_map_next +hb_map_keys +hb_map_values +HB_MAP_VALUE_INVALID hb_map_t
hb-ot-color -hb_color_t HB_COLOR hb_color_get_alpha hb_color_get_blue @@ -483,16 +580,19 @@ hb_ot_color_glyph_get_layers hb_ot_color_glyph_reference_png hb_ot_color_glyph_reference_svg hb_ot_color_has_layers +hb_ot_color_has_paint +hb_ot_color_glyph_has_paint hb_ot_color_has_palettes hb_ot_color_has_png hb_ot_color_has_svg -hb_ot_color_layer_t hb_ot_color_palette_color_get_name_id -hb_ot_color_palette_flags_t hb_ot_color_palette_get_colors hb_ot_color_palette_get_count hb_ot_color_palette_get_flags hb_ot_color_palette_get_name_id +hb_color_t +hb_ot_color_layer_t +hb_ot_color_palette_flags_t
@@ -502,35 +602,21 @@ hb_ot_font_set_funcs
hb-ot-name -hb_ot_name_id_t -HB_OT_NAME_ID_INVALID -hb_ot_name_entry_t hb_ot_name_list_names hb_ot_name_get_utf16 hb_ot_name_get_utf32 hb_ot_name_get_utf8 +hb_ot_name_id_t +hb_ot_name_id_predefined_t +hb_ot_name_entry_t
hb-ot-layout -HB_OT_MAX_TAGS_PER_LANGUAGE -HB_OT_MAX_TAGS_PER_SCRIPT -HB_OT_TAG_DEFAULT_LANGUAGE -HB_OT_TAG_DEFAULT_SCRIPT hb_ot_tag_to_language hb_ot_tag_to_script hb_ot_tags_from_script_and_language hb_ot_tags_to_script_and_language -HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX -HB_OT_LAYOUT_NO_FEATURE_INDEX -HB_OT_LAYOUT_NO_SCRIPT_INDEX -HB_OT_LAYOUT_NO_VARIATIONS_INDEX -HB_OT_TAG_BASE -HB_OT_TAG_GDEF -HB_OT_TAG_GPOS -HB_OT_TAG_GSUB -HB_OT_TAG_JSTF -hb_ot_layout_baseline_tag_t hb_ot_layout_collect_lookups hb_ot_layout_collect_features hb_ot_layout_feature_get_characters @@ -545,7 +631,6 @@ hb_ot_layout_get_glyph_class hb_ot_layout_get_glyphs_in_class hb_ot_layout_get_ligature_carets hb_ot_layout_get_size_params -hb_ot_layout_glyph_class_t hb_ot_layout_has_glyph_classes hb_ot_layout_has_positioning hb_ot_layout_has_substitution @@ -562,6 +647,7 @@ hb_ot_layout_lookup_would_substitute hb_ot_layout_script_find_language hb_ot_layout_script_get_language_tags hb_ot_layout_script_select_language +hb_ot_layout_script_select_language2 hb_ot_layout_table_find_feature_variations hb_ot_layout_table_get_feature_tags hb_ot_layout_table_get_script_tags @@ -569,18 +655,25 @@ hb_ot_layout_table_get_lookup_count hb_ot_layout_table_select_script hb_ot_shape_plan_collect_lookups hb_ot_layout_language_get_required_feature_index +HB_OT_MAX_TAGS_PER_LANGUAGE +HB_OT_MAX_TAGS_PER_SCRIPT +HB_OT_TAG_DEFAULT_LANGUAGE +HB_OT_TAG_DEFAULT_SCRIPT +HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX +HB_OT_LAYOUT_NO_FEATURE_INDEX +HB_OT_LAYOUT_NO_SCRIPT_INDEX +HB_OT_LAYOUT_NO_VARIATIONS_INDEX +HB_OT_TAG_BASE +HB_OT_TAG_GDEF +HB_OT_TAG_GPOS +HB_OT_TAG_GSUB +HB_OT_TAG_JSTF +hb_ot_layout_baseline_tag_t +hb_ot_layout_glyph_class_t
hb-ot-math -HB_OT_TAG_MATH -HB_OT_TAG_MATH_SCRIPT -hb_ot_math_constant_t -hb_ot_math_kern_t -hb_ot_math_kern_entry_t -hb_ot_math_glyph_variant_t -hb_ot_math_glyph_part_flags_t -hb_ot_math_glyph_part_t hb_ot_math_has_data hb_ot_math_get_constant hb_ot_math_get_glyph_italics_correction @@ -591,23 +684,31 @@ hb_ot_math_is_glyph_extended_shape hb_ot_math_get_glyph_variants hb_ot_math_get_min_connector_overlap hb_ot_math_get_glyph_assembly +HB_OT_TAG_MATH +HB_OT_TAG_MATH_SCRIPT +hb_ot_math_constant_t +hb_ot_math_kern_t +hb_ot_math_kern_entry_t +hb_ot_math_glyph_variant_t +hb_ot_math_glyph_part_flags_t +hb_ot_math_glyph_part_t
hb-ot-meta -hb_ot_meta_tag_t hb_ot_meta_get_entry_tags hb_ot_meta_reference_entry +hb_ot_meta_tag_t
hb-ot-metrics -hb_ot_metrics_tag_t hb_ot_metrics_get_position hb_ot_metrics_get_position_with_fallback hb_ot_metrics_get_variation hb_ot_metrics_get_x_variation hb_ot_metrics_get_y_variation +hb_ot_metrics_tag_t
@@ -617,14 +718,7 @@ hb_ot_shape_glyphs_closure
hb-ot-var -HB_OT_TAG_VAR_AXIS_ITALIC -HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE -HB_OT_TAG_VAR_AXIS_SLANT -HB_OT_TAG_VAR_AXIS_WEIGHT -HB_OT_TAG_VAR_AXIS_WIDTH hb_ot_var_has_data -hb_ot_var_axis_flags_t -hb_ot_var_axis_info_t hb_ot_var_find_axis_info hb_ot_var_get_axis_count hb_ot_var_get_axis_infos @@ -634,31 +728,44 @@ hb_ot_var_named_instance_get_postscript_name_id hb_ot_var_named_instance_get_design_coords hb_ot_var_normalize_variations hb_ot_var_normalize_coords +HB_OT_TAG_VAR_AXIS_ITALIC +HB_OT_TAG_VAR_AXIS_OPTICAL_SIZE +HB_OT_TAG_VAR_AXIS_SLANT +HB_OT_TAG_VAR_AXIS_WEIGHT +HB_OT_TAG_VAR_AXIS_WIDTH +hb_ot_var_axis_flags_t +hb_ot_var_axis_info_t
hb-set -HB_SET_VALUE_INVALID -hb_set_add -hb_set_add_range -hb_set_add_sorted_array +hb_set_create hb_set_allocation_successful hb_set_copy +hb_set_get_empty +hb_set_reference +hb_set_destroy +hb_set_set_user_data +hb_set_get_user_data hb_set_clear -hb_set_create +hb_set_set +hb_set_has +hb_set_add +hb_set_add_range +hb_set_add_sorted_array hb_set_del hb_set_del_range -hb_set_destroy -hb_set_get_empty hb_set_get_max hb_set_get_min hb_set_get_population -hb_set_get_user_data -hb_set_has +hb_set_is_empty hb_set_hash +hb_set_subtract hb_set_intersect +hb_set_union +hb_set_symmetric_difference hb_set_invert -hb_set_is_empty +hb_set_is_inverted hb_set_is_equal hb_set_is_subset hb_set_next @@ -666,19 +773,15 @@ hb_set_next_range hb_set_next_many hb_set_previous hb_set_previous_range -hb_set_reference -hb_set_set -hb_set_set_user_data -hb_set_subtract -hb_set_symmetric_difference +HB_SET_VALUE_INVALID hb_set_t -hb_set_union
hb-shape hb_shape hb_shape_full +hb_shape_justify hb_shape_list_shapers
@@ -688,50 +791,50 @@ hb_shape_plan_create hb_shape_plan_create_cached hb_shape_plan_create2 hb_shape_plan_create_cached2 -hb_shape_plan_destroy -hb_shape_plan_execute hb_shape_plan_get_empty -hb_shape_plan_get_shaper -hb_shape_plan_get_user_data hb_shape_plan_reference +hb_shape_plan_destroy hb_shape_plan_set_user_data +hb_shape_plan_get_user_data +hb_shape_plan_execute +hb_shape_plan_get_shaper hb_shape_plan_t
hb-unicode -HB_UNICODE_MAX +hb_unicode_general_category hb_unicode_combining_class -hb_unicode_combining_class_func_t -hb_unicode_combining_class_t +hb_unicode_mirroring +hb_unicode_script hb_unicode_compose -hb_unicode_compose_func_t hb_unicode_decompose -hb_unicode_decompose_func_t hb_unicode_funcs_create -hb_unicode_funcs_destroy -hb_unicode_funcs_get_default hb_unicode_funcs_get_empty -hb_unicode_funcs_get_parent +hb_unicode_funcs_reference +hb_unicode_funcs_destroy +hb_unicode_funcs_set_user_data hb_unicode_funcs_get_user_data -hb_unicode_funcs_is_immutable hb_unicode_funcs_make_immutable -hb_unicode_funcs_reference -hb_unicode_funcs_set_combining_class_func -hb_unicode_funcs_set_compose_func -hb_unicode_funcs_set_decompose_func +hb_unicode_funcs_is_immutable +hb_unicode_funcs_get_default +hb_unicode_funcs_get_parent +hb_unicode_general_category_func_t hb_unicode_funcs_set_general_category_func +hb_unicode_combining_class_func_t +hb_unicode_funcs_set_combining_class_func +hb_unicode_mirroring_func_t hb_unicode_funcs_set_mirroring_func +hb_unicode_script_func_t hb_unicode_funcs_set_script_func -hb_unicode_funcs_set_user_data -hb_unicode_funcs_t -hb_unicode_general_category -hb_unicode_general_category_func_t +hb_unicode_compose_func_t +hb_unicode_funcs_set_compose_func +hb_unicode_decompose_func_t +hb_unicode_funcs_set_decompose_func +HB_UNICODE_MAX +hb_unicode_combining_class_t hb_unicode_general_category_t -hb_unicode_mirroring -hb_unicode_mirroring_func_t -hb_unicode_script -hb_unicode_script_func_t +hb_unicode_funcs_t
@@ -743,13 +846,13 @@ hb_uniscribe_font_get_logfontw
hb-version HB_VERSION_ATLEAST +hb_version +hb_version_atleast +hb_version_string HB_VERSION_MAJOR HB_VERSION_MICRO HB_VERSION_MINOR HB_VERSION_STRING -hb_version -hb_version_atleast -hb_version_string
@@ -760,20 +863,19 @@ hb_style_get_value
hb-subset -hb_subset_flags_t -hb_subset_input_t -hb_subset_sets_t -hb_subset_plan_t hb_subset_input_create_or_fail hb_subset_input_reference hb_subset_input_destroy hb_subset_input_set_user_data hb_subset_input_get_user_data -hb_subset_input_get_flags +hb_subset_input_keep_everything hb_subset_input_set_flags +hb_subset_input_get_flags hb_subset_input_unicode_set hb_subset_input_glyph_set hb_subset_input_set +hb_subset_input_pin_axis_location +hb_subset_input_pin_axis_to_default hb_subset_or_fail hb_subset_plan_create_or_fail hb_subset_plan_reference @@ -784,11 +886,28 @@ hb_subset_plan_execute_or_fail hb_subset_plan_unicode_to_old_glyph_mapping hb_subset_plan_new_to_old_glyph_mapping hb_subset_plan_old_to_new_glyph_mapping +hb_subset_preprocess +hb_subset_flags_t +hb_subset_input_t +hb_subset_sets_t +hb_subset_plan_t hb_link_t hb_object_t hb_subset_repack_or_fail -hb_subset_preprocess -hb_subset_input_pin_axis_location -hb_subset_input_pin_axis_to_default +hb_subset_input_override_name_table +
+ +
+hb-cairo +hb_cairo_font_face_create_for_font +hb_cairo_font_face_get_font +hb_cairo_font_face_create_for_face +hb_cairo_font_face_get_face +hb_cairo_font_init_func_t +hb_cairo_font_face_set_font_init_func +hb_cairo_scaled_font_get_font +hb_cairo_font_face_set_scale_factor +hb_cairo_font_face_get_scale_factor +hb_cairo_glyphs_from_buffer
diff --git a/third_party/harfbuzz-ng/src/docs/meson.build b/third_party/harfbuzz-ng/src/docs/meson.build index 9da1fd564ee3..faf558a7705f 100644 --- a/third_party/harfbuzz-ng/src/docs/meson.build +++ b/third_party/harfbuzz-ng/src/docs/meson.build @@ -1,8 +1,3 @@ -if build_machine.system() == 'windows' - message('Skipping gtk-doc while building on Windows') - subdir_done() -endif - if not find_program('gtkdoc-scan', required: get_option('docs')).found() message('Not building documentation as gtk-doc was not found') subdir_done() @@ -41,6 +36,7 @@ html_images = [ ] ignore_headers = [ + 'hb-features.h', 'hb-gobject.h', 'hb-gobject-enums.h', 'hb-gobject-enums-tmp.h', @@ -53,7 +49,7 @@ gnome.gtkdoc('harfbuzz', meson.current_build_dir() / '..' / 'src', ], scan_args: ['--deprecated-guards=HB_DISABLE_DEPRECATED', - '--ignore-decorators=HB_EXTERN|HB_DEPRECATED', + '--ignore-decorators=HB_EXTERN|HB_DEPRECATED|HB_DEPRECATED_FOR()', ], mkdb_args: ['--source-suffixes=h,cc', '--xml-mode', @@ -63,4 +59,6 @@ gnome.gtkdoc('harfbuzz', html_assets: html_images, ignore_headers: ignore_headers, dependencies: [libharfbuzz_dep], - install: true) + install: true, + check: get_option('doc_tests'), +) diff --git a/third_party/harfbuzz-ng/src/docs/subset-preprocessing.md b/third_party/harfbuzz-ng/src/docs/subset-preprocessing.md new file mode 100644 index 000000000000..637da2865431 --- /dev/null +++ b/third_party/harfbuzz-ng/src/docs/subset-preprocessing.md @@ -0,0 +1,228 @@ +# Introduction + +Subset preprocessing is a mechanism which can significantly speed up font subsetting operations. +It works by prepopulating datastructures from the source font which can be used in later subsetting +operations to more quickly produce the subset. Preprocessing is useful in cases where multiple subsets +will be cut from the same source font. + +# Usage + +```c++ +hb_face_t* preprocessed = hb_subset_preprocess (source_face); + +... + +hb_face_t* subset = hb_subset_or_fail (preprocessed, subset_input); +``` + +# Additional Details + +* A subset produced from a preprocessed face should be identical to a subset produced from only the + original face. The preprocessor does not change the functionality of the subsetter, just speeds + things up. + +* The preprocessing operation may take longer than the time it takes to produce a subset from the + source font. Thus the main performance gains are made when a preprocessed face is reused for + multiple subsetting operations. + +* Currently the largest performance gains are seen when using a preprocessed face for CFF subsetting. + +* The preprocessed face may contain references to the memory backing the source face. If this memory + is fully owned by a harfbuzz hb_blob_t* then it will automatically be kept alive for the lifetime + of the preprocessed face. However, if this memory is not fully owned by a harfbuzz hb_blob_t* then + it is necessary to ensure that the memory is kept alive for the lifetime of the preprocessed face. + + +# Performance Improvements + +Here is the performance difference of producing a subset with a preprocessed face vs producing +a subset with the source face: + +Benchmark | Delta Time (%) +----------|----------------- +BM_subset/subset_glyphs/Roboto-Regular.ttf/10_median|-56% +BM_subset/subset_glyphs/Roboto-Regular.ttf/64_median|-33% +BM_subset/subset_glyphs/Roboto-Regular.ttf/512_median|-28% +BM_subset/subset_glyphs/Roboto-Regular.ttf/1000_median|-11% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/10_median|-56% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/64_median|-33% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/512_median|-21% +BM_subset/subset_glyphs/Roboto-Regular.ttf/nohinting/1000_median|-9% +BM_subset/subset_glyphs/Amiri-Regular.ttf/10_median|-67% +BM_subset/subset_glyphs/Amiri-Regular.ttf/64_median|-48% +BM_subset/subset_glyphs/Amiri-Regular.ttf/512_median|-21% +BM_subset/subset_glyphs/Amiri-Regular.ttf/4096_median|-9% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/10_median|-66% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/64_median|-50% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/512_median|-8% +BM_subset/subset_glyphs/Amiri-Regular.ttf/nohinting/4096_median|-9% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/10_median|-85% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/64_median|-71% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/512_median|-3% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/1400_median|4% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-84% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-72% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|0% +BM_subset/subset_glyphs/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|0% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/10_median|-30% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/64_median|-24% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/512_median|-3% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/1000_median|-3% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-30% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-3% +BM_subset/subset_glyphs/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|-5% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10_median|-96% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/64_median|-90% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/512_median|-74% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/4096_median|-25% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/10000_median|-23% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10_median|-95% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/64_median|-90% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/512_median|-73% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/4096_median|-24% +BM_subset/subset_glyphs/Mplus1p-Regular.ttf/nohinting/10000_median|-11% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10_median|-84% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/64_median|-77% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/512_median|-70% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/4096_median|-80% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/10000_median|-86% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10_median|-84% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/64_median|-78% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/512_median|-71% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86% +BM_subset/subset_glyphs/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/10_median|-59% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/64_median|-55% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/512_median|-67% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/2000_median|-68% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/10_median|-60% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/64_median|-58% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/512_median|-72% +BM_subset/subset_glyphs/SourceSansPro-Regular.otf/nohinting/2000_median|-71% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/10_median|-70% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/64_median|-64% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/300_median|-73% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/10_median|-71% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/64_median|-68% +BM_subset/subset_glyphs/AdobeVFPrototype.otf/nohinting/300_median|-72% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/10_median|-90% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/64_median|-82% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/512_median|-31% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/4096_median|-9% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/6000_median|-22% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/10_median|-88% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/64_median|-83% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/512_median|-31% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/4096_median|-16% +BM_subset/subset_glyphs/MPLUS1-Variable.ttf/nohinting/6000_median|-18% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/10_median|-44% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/64_median|-18% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/512_median|-2% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/900_median|-6% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/10_median|-45% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/64_median|-17% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/512_median|-15% +BM_subset/subset_glyphs/RobotoFlex-Variable.ttf/nohinting/900_median|-3% +BM_subset/subset_codepoints/Roboto-Regular.ttf/10_median|-20% +BM_subset/subset_codepoints/Roboto-Regular.ttf/64_median|-16% +BM_subset/subset_codepoints/Roboto-Regular.ttf/512_median|-12% +BM_subset/subset_codepoints/Roboto-Regular.ttf/1000_median|-10% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/10_median|-24% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/64_median|-14% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/512_median|-15% +BM_subset/subset_codepoints/Roboto-Regular.ttf/nohinting/1000_median|-9% +BM_subset/subset_codepoints/Amiri-Regular.ttf/10_median|-51% +BM_subset/subset_codepoints/Amiri-Regular.ttf/64_median|-37% +BM_subset/subset_codepoints/Amiri-Regular.ttf/512_median|-12% +BM_subset/subset_codepoints/Amiri-Regular.ttf/4096_median|-1% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/10_median|-49% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/64_median|-35% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/512_median|-6% +BM_subset/subset_codepoints/Amiri-Regular.ttf/nohinting/4096_median|-1% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/10_median|-82% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/64_median|-9% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/512_median|0% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/1400_median|0% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/10_median|-82% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/64_median|-13% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/512_median|-3% +BM_subset/subset_codepoints/NotoNastaliqUrdu-Regular.ttf/nohinting/1400_median|2% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/10_median|-40% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/64_median|-26% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/512_median|-5% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/1000_median|3% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/10_median|-43% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/64_median|-24% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/512_median|-2% +BM_subset/subset_codepoints/NotoSansDevanagari-Regular.ttf/nohinting/1000_median|2% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10_median|-83% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/64_median|-67% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/512_median|-39% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/4096_median|-20% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/10000_median|-25% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10_median|-83% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/64_median|-65% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/512_median|-42% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/4096_median|-34% +BM_subset/subset_codepoints/Mplus1p-Regular.ttf/nohinting/10000_median|-21% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10_median|-69% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/64_median|-69% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/512_median|-70% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/4096_median|-84% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/10000_median|-83% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10_median|-71% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/64_median|-68% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/512_median|-70% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/4096_median|-86% +BM_subset/subset_codepoints/SourceHanSans-Regular_subset.otf/nohinting/10000_median|-88% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/10_median|-45% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/64_median|-48% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/512_median|-57% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/2000_median|-66% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/10_median|-43% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/64_median|-50% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/512_median|-63% +BM_subset/subset_codepoints/SourceSansPro-Regular.otf/nohinting/2000_median|-72% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/10_median|-69% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/64_median|-66% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/300_median|-74% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/10_median|-70% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/64_median|-71% +BM_subset/subset_codepoints/AdobeVFPrototype.otf/nohinting/300_median|-75% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/10_median|-66% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/64_median|-46% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/512_median|-15% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/4096_median|-5% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/6000_median|-16% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/10_median|-66% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/64_median|-45% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/512_median|-14% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/4096_median|-11% +BM_subset/subset_codepoints/MPLUS1-Variable.ttf/nohinting/6000_median|-27% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/10_median|-38% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/64_median|-9% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/512_median|-3% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/900_median|-16% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/10_median|-39% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/64_median|-12% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/512_median|-4% +BM_subset/subset_codepoints/RobotoFlex-Variable.ttf/nohinting/900_median|-2% +BM_subset/instance/MPLUS1-Variable.ttf/10_median|-68% +BM_subset/instance/MPLUS1-Variable.ttf/64_median|-45% +BM_subset/instance/MPLUS1-Variable.ttf/512_median|-18% +BM_subset/instance/MPLUS1-Variable.ttf/4096_median|-2% +BM_subset/instance/MPLUS1-Variable.ttf/6000_median|4% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/10_median|-69% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/64_median|-46% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/512_median|-11% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/4096_median|4% +BM_subset/instance/MPLUS1-Variable.ttf/nohinting/6000_median|-5% +BM_subset/instance/RobotoFlex-Variable.ttf/10_median|-34% +BM_subset/instance/RobotoFlex-Variable.ttf/64_median|-12% +BM_subset/instance/RobotoFlex-Variable.ttf/512_median|6% +BM_subset/instance/RobotoFlex-Variable.ttf/900_median|-6% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/10_median|-33% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/64_median|-11% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/512_median|3% +BM_subset/instance/RobotoFlex-Variable.ttf/nohinting/900_median|0% diff --git a/third_party/harfbuzz-ng/src/docs/usermanual-clusters.xml b/third_party/harfbuzz-ng/src/docs/usermanual-clusters.xml index 4f2825c0bc27..545afde89ed7 100644 --- a/third_party/harfbuzz-ng/src/docs/usermanual-clusters.xml +++ b/third_party/harfbuzz-ng/src/docs/usermanual-clusters.xml @@ -182,8 +182,7 @@ - Level 0 is the default and - reproduces the behavior of the old HarfBuzz library. + Level 0 is the default. The distinguishing feature of level 0 behavior is that, at @@ -194,7 +193,7 @@ as well as the Zero Width Joiner and Zero Width Non-Joiner code points, are assigned the cluster value of the closest preceding code - point from different category. + point from different category. In essence, whenever a base character is followed by a mark @@ -206,6 +205,11 @@ url="https://www.unicode.org/reports/tr29/#Regex_Definitions">Unicode Technical Report 29. + + This cluster level is suitable for code that likes to use + HarfBuzz cluster values as an approximation of the Unicode + Grapheme Cluster Boundaries as well. + Client programs can specify level 0 behavior for a buffer by setting its cluster_level to @@ -220,13 +224,13 @@ implement backward compatibility with the old HarfBuzz. - Level 1 differs from level 0 by not merging the + Level 1 differs from level 0 by not merging the clusters of marks and other modifier code points with the preceding "base" code point's cluster. By preserving the separate cluster values of these marks and modifier code points, script shapers can perform additional operations - that might lead to improved results (for example, reordering - a sequence of marks). + that might lead to improved results (for example, coloring + mark glyphs differently than their base). Client programs can specify level 1 behavior for a buffer by @@ -242,7 +246,7 @@ This difference can be seen most clearly when HarfBuzz processes - ligature substitutions and glyph decompositions. In level 0 + ligature substitutions and glyph decompositions. In level 0 and level 1, ligatures and glyph decomposition both involve merging clusters; in level 2, neither of these operations triggers a merge. @@ -259,7 +263,7 @@ assign initial cluster values in a buffer by reusing the indices of the code points in the input text. This gives a sequence of cluster values that is monotonically increasing (for example, - 0,1,2,3,4). + 0,1,2,3,4). It is not required that the cluster values @@ -314,7 +318,7 @@
- +
A clustering example for levels 0 and 1 diff --git a/third_party/harfbuzz-ng/src/docs/usermanual-fonts-and-faces.xml b/third_party/harfbuzz-ng/src/docs/usermanual-fonts-and-faces.xml index abf5dc2b426d..39233948bee5 100644 --- a/third_party/harfbuzz-ng/src/docs/usermanual-fonts-and-faces.xml +++ b/third_party/harfbuzz-ng/src/docs/usermanual-fonts-and-faces.xml @@ -55,7 +55,7 @@ shaping. The typeface must be set to a specific point size in order for some details (such as hinting) to work. In addition, if the font file in question is an OpenType Variable Font, then - you may need to specify one or variation-axis settings (or a + you may need to specify one or more variation-axis settings (or a named instance) in order to get the output you need. @@ -256,6 +256,18 @@ hb_font_get_glyph_from_name_func_t: returns the glyph index that corresponds to a given glyph name. + + + + + hb_font_draw_glyph_func_t: gets the outlines + of a glyph (by calling #hb_draw_funcs_t callbacks). + + + + + hb_font_paint_glyph_func_t: paints a glyph + (by calling #hb_paint_funcs_t callbacks). @@ -375,20 +387,6 @@
- - - - -
Working with OpenType Variable Fonts @@ -455,13 +453,66 @@ range actually implemented in the font's variation axis. After all, a font might only provide lighter-than-regular weights, and setting a heavier value on the wght axis will - not change that. + not change that. Once your variation settings are specified on your font object, however, shaping with a variable font is just like shaping a static font. + + In addition to providing the variation axes themselves, fonts may also + pre-define certain variation coordinates as named instances. HarfBuzz + makes these coordinates (and their associated names) available via + hb_ot_var_named_instance_get_design_coords() and + hb_ot_var_named_instance_get_subfamily_name_id(). + + + Applications should treat named instances like multiple independent, + static fonts. + +
+ +
+ Glyphs and rendering + + + The main purpose of HarfBuzz is shaping, which creates a list of positioned + glyphs as output. The remaining task for text layout is to convert this list + into rendered output. While HarfBuzz does not handle rasterization of glyphs + per se, it does have APIs that provide access to the font data that is needed + to perform this task. + + + Traditionally, the shapes of glyphs in scalable fonts are provided as quadratic + or cubic Beziér curves defining outlines to be filled. To obtain the outlines + for a glyph, call hb_font_draw_glyph() and pass a + hb_draw_funcs_t struct. The callbacks in that struct will be called + for each segment of the outline. Note that this API provides access to outlines + as they are defined in the font, without applying hinting to fit the curves + to the pixel grid. + + + Fonts may provide pre-rendered images for glyphs instead of or in addition to + outlines. This is most common for fonts that contain colored glyphs, such as + Emoji. To access these images, use hb_ot_color_reference_png() + or hb_ot_color_reference_svg(). + + + Another way in which fonts provide colored glyphs is via paint graphs that + combine glyph outlines with gradients and allow for transformations and + compositing. In its simplest form, this can be presented as a series of + layers that are rendered on top of each other, each with its own color. + HarfBuzz has the hb_ot_color_glyph_get_layers() to + access glyph data in this form. + + + In the general case, you have to use hb_font_paint_glyph() + and pass a hb_paint_funcs_t struct with callbacks to obtain paint + graphs for glyphs that have them. The hb_font_paint_glyph() + API can handle outline and image glyphs as well, so it provides a unified API for + access to glyph rendering information. +
diff --git a/third_party/harfbuzz-ng/src/docs/usermanual-integration.xml b/third_party/harfbuzz-ng/src/docs/usermanual-integration.xml index 5d31ec2680ce..e208370df31b 100644 --- a/third_party/harfbuzz-ng/src/docs/usermanual-integration.xml +++ b/third_party/harfbuzz-ng/src/docs/usermanual-integration.xml @@ -174,7 +174,9 @@ HarfBuzz provides integration points with FreeType at the face-object and font-object level and for the font-functions - virtual-method structure of a font object. To use the + virtual-method structure of a font object. These functions + make it easy for clients that use FreeType for rasterization + or font-loading, to use HarfBuzz for shaping. To use the FreeType-integration API, include the hb-ft.h header. @@ -308,7 +310,49 @@ it when it is unneeded.
- + +
+ Cairo integration + + + Cairo is a 2D graphics library that is frequently used together + with GTK and Pango. Cairo supports rendering text using FreeType, or + by using callback-based 'user fonts'. + + + HarfBuzz provides integration points with cairo for fonts as well as + for buffers. To use the Cairo-integration API, link against libharfbuzz-cairo, + and include the hb-cairo.h header. For easy buildsystem + integration, HarfBuzz comes with a harfbuzz-cairo.pc + pkg-config file. + + + To create a cairo_scaled_font_t font from a HarfBuzz + hb_font_t, you can use hb_cairo_font_face_create_for_font() + or hb_cairo_font_face_create_for_face(). The former API + applies variations and synthetic slant from the hb_font_t when + rendering, the latter takes them from the cairo_font_options_t + that were passed when creating the cairo_scaled_font_t. + + + The Cairo fonts created in this way make use of Cairo's user-font facilities. + They can be used to render on any Cairo context, and provide full support for + font rendering features, including color. One current limitation of the + implementation is that it does not support hinting for glyph outlines. + + + When using color fonts with this API, the color palette index is taken from + the cairo_font_options_t (with new enough Cairo), and the foreground + color is extracted from the source of the Cairo context. + + + To render the results of shaping a piece of text, use + hb_cairo_glyphs_from_buffer() to obtain the glyphs in + a form that can be passed to cairo_show_text_glyphs() or + cairo_show_glyphs(). + +
+
Uniscribe integration diff --git a/third_party/harfbuzz-ng/src/meson.build b/third_party/harfbuzz-ng/src/meson.build index b80679d3aa13..4f5cc8c7ab12 100644 --- a/third_party/harfbuzz-ng/src/meson.build +++ b/third_party/harfbuzz-ng/src/meson.build @@ -1,8 +1,9 @@ project('harfbuzz', 'c', 'cpp', meson_version: '>= 0.55.0', - version: '5.3.1', + version: '7.1.0', default_options: [ - 'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway + 'cpp_eh=none', # Just to support msvc, we are passing -fno-exceptions also anyway + 'cpp_rtti=false', # Just to support msvc, we are passing -fno-rtti also anyway 'cpp_std=c++11', 'wrap_mode=nofallback', # Use --wrap-mode=default to revert, https://github.com/harfbuzz/harfbuzz/pull/2548 ], @@ -14,7 +15,7 @@ hb_version_minor = hb_version_arr[1].to_int() hb_version_micro = hb_version_arr[2].to_int() # libtool versioning -hb_version_int = hb_version_major*10000 + hb_version_minor*100 + hb_version_micro +hb_version_int = 60000 + hb_version_major*100 + hb_version_minor*10 + hb_version_micro hb_libtool_version_info = '@0@:0:@0@'.format(hb_version_int) pkgmod = import('pkgconfig') @@ -27,17 +28,12 @@ if cpp.get_argument_syntax() == 'msvc' # If a warning is harmless but hard to fix, use '/woXXXX' so it's shown once # NOTE: Only add warnings here if you are sure they're spurious msvc_args = [ - '/wd4018', # implicit signed/unsigned conversion - '/wd4146', # unary minus on unsigned (beware INT_MIN) '/wd4244', # lossy type conversion (e.g. double -> int) - '/wd4305', # truncating type conversion (e.g. double -> float) cpp.get_supported_arguments(['/utf-8']), # set the input encoding to utf-8 ] add_project_arguments(msvc_args, language: ['c', 'cpp']) # Disable SAFESEH with MSVC for libs that use external deps that are built with MinGW # noseh_link_args = ['/SAFESEH:NO'] - # disable exception handling - add_project_arguments(['/EHs-', '/EHc-'], language: 'cpp') endif add_project_link_arguments(cpp.get_supported_link_arguments([ @@ -83,20 +79,35 @@ check_funcs = [ m_dep = cpp.find_library('m', required: false) - -# Try pkgconfig name -freetype_dep = dependency('freetype2', required: false) -if not freetype_dep.found() - # Try cmake name - freetype_dep = dependency('freetype', required: false) -endif -if not freetype_dep.found() - # Subproject fallback, `allow_fallback: true` means the fallback will be - # tried even if the freetype option is set to `auto`. - freetype_dep = dependency('freetype2', +if meson.version().version_compare('>=0.60.0') + # pkg-config: freetype2, cmake: Freetype + freetype_dep = dependency('freetype2', 'Freetype', required: get_option('freetype'), default_options: ['harfbuzz=disabled'], allow_fallback: true) +else + # painful hack to handle multiple dependencies but also respect options + freetype_opt = get_option('freetype') + # we want to handle enabled manually after fallbacks, but also handle disabled normally + if freetype_opt.enabled() + freetype_opt = false + endif + # try pkg-config name + freetype_dep = dependency('freetype2', method: 'pkg-config', required: freetype_opt) + # when disabled, leave it not-found + if not freetype_dep.found() and not get_option('freetype').disabled() + # Try cmake name + freetype_dep = dependency('Freetype', method: 'cmake', required: false) + # Subproject fallback, `allow_fallback: true` means the fallback will be + # tried even if the freetype option is set to `auto`. + if not freetype_dep.found() + freetype_dep = dependency('freetype2', + method: 'pkg-config', + required: get_option('freetype'), + default_options: ['harfbuzz=disabled'], + allow_fallback: true) + endif + endif endif glib_dep = dependency('glib-2.0', required: get_option('glib')) @@ -104,18 +115,36 @@ gobject_dep = dependency('gobject-2.0', required: get_option('gobject')) graphite2_dep = dependency('graphite2', required: get_option('graphite2')) graphite_dep = dependency('graphite2', required: get_option('graphite')) -# Try pkgconfig name -icu_dep = dependency('icu-uc', required: false) -if not icu_dep.found() - # Try cmake name - icu_dep = dependency('ICU', - required: false, - components: 'uc', - method: 'cmake') -endif -if not icu_dep.found() - # Subproject fallback if icu option is enabled - icu_dep = dependency('icu-uc', required: get_option('icu')) +if meson.version().version_compare('>=0.60.0') + # pkg-config: icu-uc, cmake: ICU but with components + icu_dep = dependency('icu-uc', 'ICU', + components: 'uc', + required: get_option('icu'), + default_options: ['harfbuzz=disabled'], + allow_fallback: true) +else + # painful hack to handle multiple dependencies but also respect options + icu_opt = get_option('icu') + # we want to handle enabled manually after fallbacks, but also handle disabled normally + if icu_opt.enabled() + icu_opt = false + endif + # try pkg-config name + icu_dep = dependency('icu-uc', method: 'pkg-config', required: icu_opt) + # when disabled, leave it not-found + if not icu_dep.found() and not get_option('icu').disabled() + # Try cmake name + icu_dep = dependency('ICU', method: 'cmake', components: 'uc', required: false) + # Try again with subproject fallback. `allow_fallback: true` means the + # fallback will be tried even if the icu option is set to `auto`, but + # we cannot pass this option until Meson 0.59.0, because no wrap file + # is checked into git. + if not icu_dep.found() + icu_dep = dependency('icu-uc', + method: 'pkg-config', + required: get_option('icu')) + endif + endif endif if icu_dep.found() and icu_dep.type_name() == 'pkgconfig' @@ -148,7 +177,8 @@ if not get_option('cairo').disabled() # harfbuzz support disabled, so when cairo will lookup freetype2 dependency # it will be forced to use that one. cairo_dep = dependency('cairo', required: get_option('cairo')) - cairo_ft_dep = dependency('cairo-ft', required: get_option('cairo')) + cairo_ft_required = get_option('cairo').enabled() and get_option('freetype').enabled() + cairo_ft_dep = dependency('cairo-ft', required: cairo_ft_required) endif endif @@ -175,10 +205,19 @@ endif if cairo_dep.found() conf.set('HAVE_CAIRO', 1) + check_cairo_funcs = [ + ['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}], + ['cairo_font_options_get_custom_palette_color', {'deps': cairo_dep}], + ['cairo_user_scaled_font_get_foreground_source', {'deps': cairo_dep}], + ] + if cairo_dep.type_name() == 'internal' - conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1) + foreach func: check_cairo_funcs + name = func[0] + conf.set('HAVE_@0@'.format(name.to_upper()), 1) + endforeach else - check_funcs += [['cairo_user_font_face_set_render_color_glyph_func', {'deps': cairo_dep}]] + check_funcs += check_cairo_funcs endif endif @@ -334,7 +373,10 @@ foreach check : check_funcs endforeach subdir('src') -subdir('util') + +if not get_option('utilities').disabled() + subdir('util') +endif if not get_option('tests').disabled() subdir('test') @@ -350,6 +392,9 @@ endif configure_file(output: 'config.h', configuration: conf) +alias_target('lib', libharfbuzz) +alias_target('libs', libharfbuzz, libharfbuzz_subset) + build_summary = { 'Directories': {'prefix': get_option('prefix'), @@ -364,7 +409,8 @@ build_summary = { 'ICU': conf.get('HAVE_ICU', 0) == 1, }, 'Font callbacks (the more the merrier)': - {'FreeType': conf.get('HAVE_FREETYPE', 0) == 1, + {'Builtin' : true, + 'FreeType': conf.get('HAVE_FREETYPE', 0) == 1, }, 'Dependencies used for command-line utilities': {'Cairo': conf.get('HAVE_CAIRO', 0) == 1, @@ -381,6 +427,7 @@ build_summary = { 'Other features': {'Documentation': conf.get('HAVE_GTK_DOC', 0) == 1, 'GObject bindings': conf.get('HAVE_GOBJECT', 0) == 1, + 'Cairo integration': conf.get('HAVE_CAIRO', 0) == 1, 'Introspection': conf.get('HAVE_INTROSPECTION', 0) == 1, 'Experimental APIs': conf.get('HB_EXPERIMENTAL_API', 0) == 1, }, diff --git a/third_party/harfbuzz-ng/src/meson_options.txt b/third_party/harfbuzz-ng/src/meson_options.txt index 9ebba72c6d39..9438202e1bdf 100644 --- a/third_party/harfbuzz-ng/src/meson_options.txt +++ b/third_party/harfbuzz-ng/src/meson_options.txt @@ -29,6 +29,10 @@ option('introspection', type: 'feature', value: 'auto', yield: true, description: 'Generate gobject-introspection bindings (.gir/.typelib files)') option('docs', type: 'feature', value: 'auto', yield: true, description: 'Generate documentation with gtk-doc') +option('doc_tests', type: 'boolean', value: false, + description: 'Run gtkdoc-check tests') +option('utilities', type: 'feature', value: 'enabled', yield: true, + description: 'Build harfbuzz utils') option('benchmark', type: 'feature', value: 'disabled', description: 'Enable benchmark tests') diff --git a/third_party/harfbuzz-ng/src/perf/benchmark-font.cc b/third_party/harfbuzz-ng/src/perf/benchmark-font.cc index 98b6310d2839..cdf33c369c6d 100644 --- a/third_party/harfbuzz-ng/src/perf/benchmark-font.cc +++ b/third_party/harfbuzz-ng/src/perf/benchmark-font.cc @@ -40,7 +40,7 @@ enum operation_t nominal_glyphs, glyph_h_advances, glyph_extents, - glyph_shape, + draw_glyph, }; static void @@ -158,12 +158,12 @@ static void BM_Font (benchmark::State &state, hb_font_get_glyph_extents (font, gid, &extents); break; } - case glyph_shape: + case draw_glyph: { hb_draw_funcs_t *draw_funcs = _draw_funcs_create (); for (auto _ : state) for (unsigned gid = 0; gid < num_glyphs; ++gid) - hb_font_get_glyph_shape (font, gid, draw_funcs, nullptr); + hb_font_draw_glyph (font, gid, draw_funcs, nullptr); break; hb_draw_funcs_destroy (draw_funcs); } @@ -233,7 +233,7 @@ int main(int argc, char** argv) TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond); TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond); TEST_OPERATION (glyph_extents, benchmark::kMicrosecond); - TEST_OPERATION (glyph_shape, benchmark::kMicrosecond); + TEST_OPERATION (draw_glyph, benchmark::kMicrosecond); #undef TEST_OPERATION diff --git a/third_party/harfbuzz-ng/src/perf/benchmark-shape.cc b/third_party/harfbuzz-ng/src/perf/benchmark-shape.cc index 626a59777611..f44b3e58f1aa 100644 --- a/third_party/harfbuzz-ng/src/perf/benchmark-shape.cc +++ b/third_party/harfbuzz-ng/src/perf/benchmark-shape.cc @@ -27,10 +27,18 @@ struct test_input_t "perf/texts/fa-thelittleprince.txt", false}, + {"perf/fonts/NotoNastaliqUrdu-Regular.ttf", + "perf/texts/fa-words.txt", + false}, + {"perf/fonts/Amiri-Regular.ttf", "perf/texts/fa-thelittleprince.txt", false}, + {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", + "perf/texts/hi-words.txt", + false}, + {"perf/fonts/Roboto-Regular.ttf", "perf/texts/en-thelittleprince.txt", false}, diff --git a/third_party/harfbuzz-ng/src/perf/benchmark-subset.cc b/third_party/harfbuzz-ng/src/perf/benchmark-subset.cc index 0451c11d86dd..9b51b794ce67 100644 --- a/third_party/harfbuzz-ng/src/perf/benchmark-subset.cc +++ b/third_party/harfbuzz-ng/src/perf/benchmark-subset.cc @@ -54,18 +54,19 @@ static inline unsigned int ARRAY_LEN (const Type (&)[n]) { return n; } struct test_input_t { const char *font_path; - const unsigned max_subset_size; + unsigned max_subset_size; const axis_location_t *instance_opts; - const unsigned num_instance_opts; -} tests[] = + unsigned num_instance_opts; +} default_tests[] = { - {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000, nullptr, 0}, - {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000, nullptr, 0}, - {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 1000, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4096, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1400, nullptr, 0}, {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000, nullptr, 0}, {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000, nullptr, 0}, {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000, nullptr, 0}, {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000, nullptr, 0}, + {SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf", 300, nullptr, 0}, {SUBSET_FONT_BASE_PATH "MPLUS1-Variable.ttf", 6000, _mplus_instance_opts, ARRAY_LEN (_mplus_instance_opts)}, {SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf", 900, _roboto_flex_instance_opts, ARRAY_LEN (_roboto_flex_instance_opts)}, #if 0 @@ -73,6 +74,10 @@ struct test_input_t #endif }; +static test_input_t *tests = default_tests; +static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]); + + void AddCodepoints(const hb_set_t* codepoints_in_font, unsigned subset_size, hb_subset_input_t* input) @@ -101,23 +106,25 @@ void AddGlyphs(unsigned num_glyphs_in_font, // the subsetting operations. static hb_face_t* preprocess_face(hb_face_t* face) { - #ifdef HB_EXPERIMENTAL_API hb_face_t* new_face = hb_subset_preprocess(face); hb_face_destroy(face); return new_face; - #else - return face; - #endif } /* benchmark for subsetting a font */ static void BM_subset (benchmark::State &state, operation_t operation, - const test_input_t &test_input) + const test_input_t &test_input, + bool hinting) { unsigned subset_size = state.range(0); - hb_face_t *face; + hb_face_t *face = nullptr; + + static hb_face_t *cached_face; + static const char *cached_font_path; + + if (!cached_font_path || strcmp (cached_font_path, test_input.font_path)) { hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path); assert (blob); @@ -125,11 +132,22 @@ static void BM_subset (benchmark::State &state, hb_blob_destroy (blob); face = preprocess_face (face); + + if (cached_face) + hb_face_destroy (cached_face); + + cached_face = hb_face_reference (face); + cached_font_path = test_input.font_path; } + else + face = hb_face_reference (cached_face); hb_subset_input_t* input = hb_subset_input_create_or_fail (); assert (input); + if (!hinting) + hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING); + switch (operation) { case subset_codepoints: @@ -149,7 +167,6 @@ static void BM_subset (benchmark::State &state, break; case instance: -#ifdef HB_EXPERIMENTAL_API { hb_set_t* all_codepoints = hb_set_create (); hb_face_collect_unicodes (face, all_codepoints); @@ -161,7 +178,6 @@ static void BM_subset (benchmark::State &state, test_input.instance_opts[i].axis_tag, test_input.instance_opts[i].axis_value); } -#endif break; } @@ -178,6 +194,7 @@ static void BM_subset (benchmark::State &state, static void test_subset (operation_t op, const char *op_name, + bool hinting, benchmark::TimeUnit time_unit, const test_input_t &test_input) { @@ -186,36 +203,57 @@ static void test_subset (operation_t op, char name[1024] = "BM_subset/"; strcat (name, op_name); - strcat (name, strrchr (test_input.font_path, '/')); + strcat (name, "/"); + const char *p = strrchr (test_input.font_path, '/'); + strcat (name, p ? p + 1 : test_input.font_path); + if (!hinting) + strcat (name, "/nohinting"); - benchmark::RegisterBenchmark (name, BM_subset, op, test_input) + benchmark::RegisterBenchmark (name, BM_subset, op, test_input, hinting) ->Range(10, test_input.max_subset_size) ->Unit(time_unit); } static void test_operation (operation_t op, const char *op_name, + const test_input_t *tests, + unsigned num_tests, benchmark::TimeUnit time_unit) { - for (auto& test_input : tests) + for (unsigned i = 0; i < num_tests; i++) { - test_subset (op, op_name, time_unit, test_input); + auto& test_input = tests[i]; + test_subset (op, op_name, true, time_unit, test_input); + test_subset (op, op_name, false, time_unit, test_input); } } int main(int argc, char** argv) { -#define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit) + benchmark::Initialize(&argc, argv); + + if (argc > 1) + { + num_tests = (argc - 1) / 2; + tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t)); + for (unsigned i = 0; i < num_tests; i++) + { + tests[i].font_path = argv[1 + i * 2]; + tests[i].max_subset_size = atoi (argv[2 + i * 2]); + } + } + +#define TEST_OPERATION(op, time_unit) test_operation (op, #op, tests, num_tests, time_unit) TEST_OPERATION (subset_glyphs, benchmark::kMillisecond); TEST_OPERATION (subset_codepoints, benchmark::kMillisecond); -#ifdef HB_EXPERIMENTAL_API TEST_OPERATION (instance, benchmark::kMillisecond); -#endif #undef TEST_OPERATION - benchmark::Initialize(&argc, argv); benchmark::RunSpecifiedBenchmarks(); benchmark::Shutdown(); + + if (tests != default_tests) + free (tests); } diff --git a/third_party/harfbuzz-ng/src/perf/run.sh b/third_party/harfbuzz-ng/src/perf/run.sh deleted file mode 100755 index c7dc6e0c2417..000000000000 --- a/third_party/harfbuzz-ng/src/perf/run.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -CXX=clang++ -FONT=fonts/NotoNastaliqUrdu-Regular.ttf -TEXT=texts/fa-monologue.txt - -$CXX ../util/hb-shape.cc ../util/options.cc ../src/harfbuzz.cc \ - -lm -fno-rtti -fno-exceptions -fno-omit-frame-pointer -DHB_NO_MT \ - -I../src $FLAGS $SOURCES \ - -DPACKAGE_NAME='""' -DPACKAGE_VERSION='""' \ - -DHAVE_GLIB $(pkg-config --cflags --libs glib-2.0) \ - -o hb-shape -g -O2 # -O3 \ - #-march=native -mtune=native \ - #-Rpass=loop-vectorize -Rpass-missed=loop-vectorize \ - #-Rpass-analysis=loop-vectorize -fsave-optimization-record - -# -march=native: enable all vector instructions current CPU can offer -# -Rpass*: https://llvm.org/docs/Vectorizers.html#diagnostics - -#sudo rm capture.syscap > /dev/null -#sysprof-cli -c "./a.out $@" -#sysprof capture.syscap - -perf stat ./hb-shape -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot -#perf record -g ./hb-shape -O '' -o /dev/null $FONT --text-file $TEXT --num-iterations=100 --font-funcs=ot -#perf report -g diff --git a/third_party/harfbuzz-ng/src/perf/texts/fa-words.txt b/third_party/harfbuzz-ng/src/perf/texts/fa-words.txt new file mode 100644 index 000000000000..4937544d8def --- /dev/null +++ b/third_party/harfbuzz-ng/src/perf/texts/fa-words.txt @@ -0,0 +1,10000 @@ +و +در +به +از +ویکی‌پدیا +که +را +این +با +است +رده +برای +کاربر +، +بحث +تصویر +میلادی +ایران +تاریخ +نام +پرونده +آن +یک +ساعت +صفحهٔ +کنید +پیوند +مقاله +صفحه +شما +اصلی +عنوان +یا +تا +سال +هم +من +استفاده +بر +خود +شده +شد +تغییرمسیر +شهرستان +کار +راهنمای +اگر +تکثیر +چه +ویرایش +حق +مقاله‌های +می +فارسی +نیست +دیگر +نوشتن +پنج +بود +زبان +سیارک +امضا +کمک +شیوه‌نامه +منابع +ملی +ثبت +آثار +پانویس +۱۱ +میز +خودآموز +بخش +دارد +خرد +انگلیسی +او +لطفاً +نیز +۱۵ +شماره +پهنا +بنیاد +استان +هر +اثر +می‌شود +مورد +کرد +یادکرد +امیدوارم +راهنما +کنیم +خوش +۱ +ویکی +چیزی +پس +۰ +۲ +شهر +پیش +فهرست +مرجع +خط +آمدید +اطلاعات +اینجا +تاریخی +زیر +منبع +جعبه +جدید +دوره +بیشتر +اینکه +بهتر +یکی +شود +دو +سپتامبر +راهنمایی +پیوندهای +۵ +حذف +۲۰۰۰ +خوب +۳ +نظر +آزاد +قرار +خواهد +تمرین +باشد +بله +پیرامون +سلام +آموزش +۴ +اصل +۱۰ +نه +صفحات +۱۹ +۱۲ +۲۰۱۱، +های +پاس +ولی +توسط +چگونه +برگزیده +بداریم +فقط +ویکی‌پروژه +۲۰۰۱ +روی +سریع +اکتبر +صورت +دست +قهوه‌خانه +۱۴ +دانشگاه +بنیادی +اما +بیاید +ناشر +داشتید، +باید +بروید +الگو +چهار +اول +مارس +کتاب +ایجاد +بازدید +توجه +آنها +پایه +۲۰ +کشور +ساختار +سخ +خوش‌آمدید +مقالهٔ +شده‌است +سازمان +فارسی‌نویسی +بودن +مرکزی +باز +آمریکا +وب +ب +۱۶ +نویسنده +کادر +دسامبر +صورتی +۲۰۰۷ +۱۸ +۲۰۱۰، +کند +فنی +تصمیم +۱۳ +تهران +وجود +۱۷ +نشانی +چطور +چند +کشف +اوت +دانشنامه‌ای +فوتبال +علمی +۲۰۰۸، +درج +۲۰۰۲ +هستند +بگیرید +۲۱ +۲۰۱۱ +نوامبر +مطالب +آزمایش +وی +کاربران +فیلم +ها +ماندن +مقالات +بپرسید +حروف +لذت +جمعیت +بحثم +۶ +ببرید +خوشتان +۸ +مدک +وابسته +ویکی‌پدیانویس +ویکی‌پدیانویسان +۷ +۲۰۰۹، +اسلام +۲۲ +ی +مسایل +آوریل +بنویسیم +۱۹۹۹ +کاربری +علامت +واقع +شوید +اهمیت +۲۳ +کلاس +کردن +ای +آشنا +باشید +نگاهی +کوچک +نکنید +وب‌گاه +پروژه‌های +کرده +۲۸ +می‌توانید +انتخاب +۹ +مکنید +بعد +روز +است، +جستارهای +شدن +نوع +نمونه‌های +۲۴ +نفر +دارید، +بیندازید +خودکار +۲۰۰۶ +نوشته +مطالعهٔ +انبار +عجله +غفلت +فهرست‌شده +مشارکت +اهل +۲۵ +سوال +محمد +بوده +۳۰ +بسیار +بزرگ +میراث +میان +زمان +منابعی +اثبات‌پذیری +جلالی +سیارک‌های +دهستان +مرکز +انجام +فوریه +می‌کند +۲۶ +نام‌های +ما +یعنی +ایرانی +ژوئن +غیر +پایان +یونسکو +حال +پرحجم +چپ +می‌گویم +داشته +جمله +پیام +عمومی +گردشگری +قبل +همین +همچنین +همان +مالک +سپاسگزارم +سال‌های +همه +اندازه +مربوط +ویکی‌انبار +قدر +چون +بیرون +ویکی‌نویسی +داده +کسب +دوم +ویژه +هیچ +فرهنگ +کسی +بروید، +تنها +۲۰۰۳ +دارای +ساخت +افراد +رتب +تازه‌واردان، +مه +محلی +بصب +بین +پتوپ +مقاله‌ها +نیازمند +اسلامی +۲۷ +بی +مرگ +علی +۲۰۰۵ +متون +مطلق +سه +می‌باشد +نیاز +شرکت +۲۹ +۲۰۰۹ +باشگاه +دلیل +زندگی +چاپ +موجود +۲۰۰۸ +نقل +گروه +۲۰۰۴ +انتهای +دارند +محتویات +شاد +موضوعات +جستجوی +۱۹۹۸ +مردم +نشان +موسیقی +ویکی‌مدیا +همراه +ویکی‌گفتاورد +تپه +شورای +دانشنامه +ویکی‌واژه +بدون +مانند +راه +شهرهای +فرهنگی +سیاره +ویکی‌نبشته +ترجمه +فراویکی +حجم +کنونی +طبق +ژانویهٔ +بار +اجرام +روستای +ویکی‌نَسک +تغییر +خوشامد +سرعت +۲۰۱۲، +جنگ +برابر +محل +سر +سپس +سیارک‌ها +عربی +بازیابی +داشت +بازی +ماه +می‌تواند +رو +کنید، +ژانویه +معرفی +بنا +مشترک +چندین +دوران +ندارد +جهان +حقوق +کنم +بالا +ضمن +داد +وبگاه +البته +آب +قدیمی +امکان +جمهوری +قسمت +۰۹ +مفیدند +پیدا +وپ +پروژه +بن +همکاری +۰۸ +تغییرات +كه +منطقه +معماری +چم‌وخم +معرفی‌شده +کنند +هزار +عرض‌جغرافیایی +طول‌جغرافیایی +۰۷ +روی‌نقشه +برخی +آی‌پی +آمار +ویکی‌پدیای +۲۰۱۰ +جای +موضوع +تمام +گرفته +شرقی +فوریهٔ +اخیر +قمری +متوسط +دیگری +غربی +درگاه +ربات +راستی +اولین +۳۱ +باستانی +امنیت +چنین +آلمان +کم +رسمی +جهانی +مطالعه +بررسی +ژوئیه +فعالیت +آغاز +آذربایجان +فکر +اين +الگوی +تیم +لطفا +ژوئیهٔ +صنایع +درود +نامه +تلفن +اقدام +روستا +ایشان +می‌کنند +فارس +حتی +تعداد +دربارهٔ +فعلی +درست +مدیران +گفتگو +حجت +دستی +ستاره +بسیاری +اند +نقش +کلیک +بودند +۰۶ +تولد +کردم +زادگان +شاه +متحده +توضیح +طول +دوست +ذکر +رسیده +مقاله‌ای +قابل +ا +اضافه +مسائل +ایالات +همهٔ +اینترنتی +نام‌گذاری +سیاسی +طور +خیلی +رضا +روستاهای +چپ‌چین +تولید +م +صفحه‌های +ص +برچسب +خانه +شکل +دولت +می‌توان +شامل +می‌نویسید +یادتان +موسسه +جنوب +نرود +نشریه +باشند +۰۰ +آمد +وارد +ه +فرانسه +جوایز +مجموعه +قانون +به‌عنوان +متن +د +۰۵ +جایزه +خبری +سید +ویکی‌خبر +گفته +اساس +سیاست‌های +جنوبی +سایت +آری +ممکن +نمی +بنویسید +روسیه +فیلم‌های +مهٔ +سوم +تشکر +جام +۱۳۸۵ +حدود +کامل +عرض +شمارهٔ +قاجار +ماني +عکس +اجازه +تصحیح +آرش +علوم +نظری +جای‌های +اشاره +دانشنامهٔ +گرفت +کردند +جان +فرهنگی، +مختلف +بانی +توضیحات +ارتفاع +موارد +میلاد +مثل +مرمت +ژورنال +شعر +محتوای +بیش +چرا +شمال +خواهر +می‌کنم +خم +فصل +شروع +تشکیل +چم +سرشماری +دهه +مشکل +ساخته +زبان‌ها +گونه‌های +مدت +مجموعه‌ای +زیادی +بهترین +درباره +موافق +دیرینگی +نتیجه +هست +آلبوم +ادامه +جهت +خراسان +شرح +ایران‌شهر +زیستی +پیشرفته +می‌دهد +راهنماهای +صفحه‌ی +افغانستان +هماهنگی +قلعه +اصفهان +بالای +جغرافیایی +شخصی +نسبت +می‌شوند +تصنيف +مطرح +عناوین +بوده‌است +۰۱ +۱۳۸۶ +زمین +سازی +حزب +سی +آن‌ها +سرشناسی +انقلاب +مي +واژه‌ها +مهم +سایر +می‌آید، +دکتر +مساحت +قطعنامه +۰۴ +شدند +مرد +درگذشتگان +پرونده‌های +باعث +نکاتی +اعلام +نامگذاری +پروژه‌ای +زبانه +سیستم +انتفاعی +یادداشتی +کتابچه +پرسیدن +۰۳ +چندرسانه‌ای +قول‌ها +هرکسی، +ویکی‌گونه +خوانندگانش +کیلومتر +سطح +زمینه +اهالی +ر +سؤال، +حسین +اصطلاح‌نامه +موقت +سندباد +بود، +تبدیل +سبک +بنویسیم؟ +روش +میثم +زمانی +۱۳۸۷ +دسترسی +کد +انگلستان +برنامه +رنگ +تحت +هاروارد +ن +مدیر +امیروبات +جرم +جلد +وقتی +گودال +نگاره +شمالی +۰۲ +پاسخ +آیا +تر +منتشر +شوند +انتشارات +مخالف +مسجد +بایگانی +هماهنگ‌کننده +کپی +متر +مجلس +۴۰ +دهید +شاید +آنجا +گل +کاربرهای +ناسا +دوستان +جناب +پیشنهاد +ان +دی +یافت +آسمانی +۱۳۸۸ +هنوز +نخستین +مذهب +نویسندگان +زنده +ایالت +ماسه‌بازی +احمد +آنهاست +کنار +شبکه +بازی‌های +مشخص +ژاپن +نمود +وقت +کشورهای +خواندن +معروف +اروپا +اشتباه +کرمان +سن +معرف +پهلوی +درجه +سوی +ام +محیط +بحثتان +روزنامه +گونه +۱۹۹۷ +طرف +کل +داستان +علت +الگوهای +آمریکایی +تو +آمده +بین‌المللی +داتک +امیر +انتشار +قوانین +شماره‌دار +دادگان +موفق +رشته +خاطر +دارم +خورشیدی +حسن +معنی +ک +زنان +انتقال +پی +حکومت +لازم +به‌آفرید +تپه‌های +نام‌صفحه +شابک +زن +قرن +دهد +عمل +بازیگر +تصاویر +رئیس +ممنون +عزیز +یاد +گفت +هفته +دین +رای +وضعیت +فرار +درخواست +سیاست +سمت +حالت +پسر +کوه +پرچم +طی +ادبیات +الله +کلی +کشف‌شده +بازیابی‌شده +غرب +فرودگاه +۱۳۹۰ +سپاس +واژه +توابع +ابعاد +کمربند +دور +مدرک +مبدا +مازندران +کننده +مدیریت +دوستدار +وجه +مهدی +نمایش +هجری +هنر +ابتدا +ده +رسید +اعضای +انسان +امام +مثال +دادن +آخرین +اسرائیل +قول +نمایید +حضور +رود +خودتان +زیاد +جا +توصیه +مناطق +عراق +مطلب +پرسش +خان +عضو +حسام +حداقل +باستان +ارائه +۵۰ +مواد +کمی +خارج +دما +چین +وزارت +اوج +خروج +طبیعی +پزشکی +ستاره‌شناسی +فراموش +پایین +کاری +اکنون +بعضی +میانگین +نشده +هزاره +نشر +مهندسی +شد، +آباد +خودم +اسپانیا +خاص +دوران‌های +۱۳۸۹ +جریان +منظور +طریق +ترتیب +بناهای +بیان +دارید +روستایی +سطحی +شیخ +نسخه +حرکت +بنده +سده +اجتماعی +طراحی +حرف +خودروهای +ویکی‌گزارش +نو +هند +استاد +به‌شما +دوباره +توان +نظامی +بلکه +سری +همسر +هنری +شیراز +مفیدی +جمع +علم +خانواده +انتخابات +آلمانی +فاصله +نیروی +مرتبط +نمونه +پدیا +فرمایید؛ +شناخته +چگالی +دیده +معتبر +مناسب +قرآن +میلیون +واحد +۴۵ +مهر +تبریز +هنگام +گسترش +طبقه‌بندی +۱۹۹۶ +فلسفه +کرمانشاه +گردید +گذشته +دنیا +زیرا +قدرت +مثلا +ببینید +لیگ +دریافت +انحراف +نام‌رسمی +می‌آید +حمله +گرانش +توسعه +افزایش +چشم +مکان +عدد +ابهام‌زدایی +دانش +موضوعی +نزدیک +شخص +آنان +دیگران +بازیکنان +آقای +کاشف +تلویزیونی +زاده +بسته +جایی +خدا +حاضر +شرق +می‌شد +حساب +پدر +داشتید +نقض +پیش‌شماره +ایتالیا +کاربرد +سعی +رفت +برد +‌بودن +کاربردها +تناوب +۳۵ +معمولاً +زبان‌های +بهمن +۳۲ +عباس +حضیض +پدیدآور +انجمن +فیزیک +نگاه +فعال +نور +نسخه‌ها +ریاست +هستم +فلکی +فرد +مسیر +اجازه‌نامه +جامعه +آلبدو +مصر +آنومالی +کلمه +نیم‌محور +بریتانیا +۱۹۹۵ +پر +پاک +ت +۱۹۹۳ +بازیگران +بخشی +فرانسوی +داخلی +خبر +سئوال +محمود +باشد، +امروز +کرده‌است +ارتباط +درصد +؟ +تاریخچه +ملل +اصلاح +معیارهای +همچون +؛ +طرح +شده‌اند +هدف +عالی +وقایع +میدان +محسوب +حل +باغ +استان‌های +خودش +قطع +ایران، +۳۳ +۳۴ +اش +دنبال +شهری +تعریف +دانشکده +انواع +دار +ورزشگاه +نقشه +کوتاه +شمار +ق +مدرسه +کمتر +آرامگاه +عصر +عبارت +بیست +تن +خرابکاری +المپیک +تیر +می‌رود +خیابان +بازار +نامزد +میرزا +داخل +اندازه‌تصویر +پایگاه +رضوی +سؤال +۱۹۹۰ +الان +گرامی +نبود +خوبی +۳۷ +خارجی +گیری +آورد +برچسب‌تصویر +۴۸ +سیستان +۱۹۹۴ +آزادی +رشد +نباید +پرسشی +۱۳۸۴ +حد +۳۶ +ملیت +رشدجمعیت +تازه +میانگین‌دما +عدم +نیروهای +تراکم‌جمعیت +سؤالی +نام‌های‌قدیمی +بنابراین +ارتش +شب +داشتن +علاوه +ابن +شمارروزهای‌یخبندان +میانگین‌بارش‌سالانه +پل +تصویب +میانه +خرداد +گیلان +سنگ +کنترل +بهزاد +کیفیت +می‌‌نویسید +۴۱ +درگذشت +علیه +گزارش +شیعه +خور +۳۸ +جزیره +ره‌آورد +دسترس +دستگاه +نام‌محلی +تگزاس +جز +همیشه +۴۲ +اجرا +کوشش +پخش +رد +۴۶ +متحد +اسفند +وزیر +خواننده +بهبود +اثبات +سفید +نظرخواهی +شرایط +جمله‌خوشامد +ترکیه +۴۴ +همدان +قم +۳۹ +می‌گیرد +۴۳ +بلوچستان +چیز +دسته +خوزستان +گنو +ترانه +کدام +خودرو +۵۵ +۴۷ +باقی +بندی +۵۱ +بخوانید +۱۹۹۲ +خواهند +صد +ناحیه +۵۳ +کاهش +۱۹۹۱ +میشود +مذهبی +۴۹ +ساختمان +اولیه +مقابل +۵۲ +سبز +وحید +۵۷ +مشهور +متوجه +تهیه +کافی +آنچه +ترک +افزودن +می‌شود، +جدا +۱۳۸۲ +چهارم +تقسیم +نژاد +معنای +کشاورزی +صفوی +براساس +سیاه +هایی +آسیا +تمامی +تحقیق +۱۹۶۰ +ساسانیان +نوشتار +رادیو +۵۶ +۵۴ +اسم +ارزش +دهانه +اقتصادی +ابراهیم +نخست +فرزندان +۵۹ +هاي +شهرها +دقیقه +حالا +دستور +امور +رابطه +پارک +جنبش +دختر +ج +قالب +بیماری +نام‌های‌دیگر +محوطه +بازیکن +کشته +دارد، +مشهد +منتقل +شهریور +مرداد +کیلومتری +پرداخت +۵۸ +تخصصی +۲۰۱۲ +مرده +دهیار +صنعتی +ش +خدمت +پشت +فشار +می‌کرد +تلاش +مدیاویکی +تلویزیون +میزان +سال‌بنیاد +قبلی +انرژی +بدست +نظام +حوزه +پا +بودم +یزد +پ +هفت +ازدواج +است؟ +فضای +نظریه +اختلاف +حمایت +خواهم +مجله +رفته +اجرای +می‌گردد +برتر +متولد +کره +خاک +برگزار +سرزمین +بدن +کرده‌اید +مسابقات +اقتصاد +ندارم +بعدی +قبول +خلیج +آخر +کمیته +فروردین +مادر +کارگردان +می‌کنید +سال‌ها +کسانی +مصرف +جدول +جشنواره +آنرا +دید +فرزند +عرب +کاملا +آمل +پادشاه +دیدگاه +آذر +اشکانیان +سفر +متفاوت +وزن +نیویورک +داشتند +بیشتری +موزه +یه +می‌رسد +خاصی +دل +دهستان‌های +آنکه +استقلال +پنهان +مجوز +نوعی +کردید +لرستان +جغرافیا +ترکی +محسن +هوایی +۱۹۸۱ +فروش +مقام +مقدار +۱۶۱۵ +قزوین +حالی +عمر +لزوم +میل +آبی +دقت +اصلا +اطلاع +رخ +شکست +اعمال +اینترنت +موتور +دومین +شهید +تحقیقات +تاسیس +برخورد +روم +ماده +محله +لینک +راست +امروزه +کرده‌اند +بازگشت +جواب +پارس +یونان +رتبه +ز +شده، +۱۳۸۱ +اساسی +نقطه +گردد +موجب +سخن +تقویم +نکته +می‌دهند +مستقل +جامع +اردیبهشت +هستید +سینما +مدل +کانادا +گاه +آورده +حفظ +ثابت +ـ +احترام +بوشهر +مربع +۱۹۸۸ +روابط +سیمرغ +درون +زیرنویس +کن +نظرم +ترکیب +بهار +بد +پادشاهی +دلار +شیمی +تعیین +بابل +نفت +دولتی +مدتی +نظرات +درستش +کاتالوگ +گاهشماری +لحاظ +ساده +بخش‌های +شوروی +باب +بی‌بی‌سی +گرفتن +دادم +مثلاً +گروه‌های +ندارند +کردستان +حاصل +شود، +انسانی +گرم +روشن +مسکن +خون +۱۳۸۰ +رسیدگی +مفهوم +خمینی +گیاهان +ساز +آهنگ +ترین +هرمزگان +۱۹۸۹ +صاحب +کارهای +اغلب +عبدالله +مشغول +۱۰۰ +شناسی +محمديان +گفتم +مختصات +دهند +یونانی +رایانه‌ای +یکم +ستارگان +کتاب‌های +ایرانیان +آوردن +صنعت +کند، +صحبت +فناوری +نمی‌شود +آینده +واگردانی +کتابخانه +برجسته +امر +نقد +مخصوص +بزرگی +آبان +نتایج +براي +یافته +لقب +متاسفانه +مالکیت +مشاهده +عرضه +کارت +گاهی +شش +دفاع +مایکل +اداره +خبرگزاری +دره +مسئله +صحیح +ولایت +گروهی +رودخانه +مقدس +مراسم +کشورها +باد +تاکنون +خلاف +علاقه +ارومیه +مرحله +ورود +۲۰۰۷، +تکمیل +موقعیت +رویدادها +تفاوت +ایستگاه +شیمیایی +مگر +ضد +ژاپنی +استاندارد +دریای +۱۹۸۰ +معاصر +زندان +غیرقابل +عملیات +دریایی +خصوص +برخوردار +لندن +شیوه +آقا +مشابه +سخت +خلاصه +دفتر +برنده +سنت +پاپ +جلوگیری +قدیم +ورودی +اسکار +بطور +چر +بندر +مرا +راک +نیشابور +نیستند +۱۵۱ +مشکلی +آتش +کشوری +تابستانی +امپراتوری +بررسی‌های +آن، +اس +میکنم +پارسی +تشخیص +شاعر +خدمات +س +عهده +نیمه +مشکلات +نیست، +آشنایی +بصورت +تأسیس +درمان +ابزار +آموزشی +نوروز +بروجرد +تواند +قتل +تحصیل +دیدم +مدرس +دانشگاه‌های +جمهور +محدود +برج +آبشار +دانشجویان +احتمال +رفتار +اعتماد +اطراف +هشدار +همواره +قطعنامه‌های +محمدرضا +پاریس +ساله +کالیفرنیا +وسیله +اصول +درخت +سالگی +۱۹۷۷ +پیشه +داریم +شخصیت +قصد +نداشته +می‌گوید +جشن +ویرایش‌های +ادبی +بهره +سنتی +فوق +کنید؛ +تام +آ +بانک +دهم +استرالیا +دقیق +نامیده +نفوس +فراهم +می‌توانند +بدین +اختیار +چشمه +دادند +يا +اردبیل +پست +خانوار +قهرمانی +منصور +سرخ +روسی +۱۳۸۳ +شبیه +بشر +قرمز +قطر +سبب +کشتی +برده +صدا +یکسان +شمسی +مجدد +اکثر +جالب +تک +گلستان +پنجم +فراوان +يك +نرم‌افزار +توهین +اتحادیه +عشق +ظهیری +گورستان +بلژیک +بکار +رستم +سرشناس +‌ها +هیئت +علیا +مقالاتی +رباتیکی +هنگامی +لطف +بختیاری +روح +ارجاع +تقریبا +۱۹۷۳ +ع +سپاه +‌های +یکدیگر +نموده +رمان +کرد، +جنسی +بزرگترین +پیشرفت +دعوت +بقیه +کلمات +شهرت +مرکزی، +رایانه +یمن +تخت +معادل +صادق +وسط +خوانندگان +تلفظ +اتفاق +امامزاده +تحصیلات +خانوادگی +حقیقت +خورشید +نوری +نقاط +پایتخت +بند +گوگل +مانده +نزدیکی +سعید +امید +نشود +نر +مسعود +سلطان +ادغام +سفلی +دریا +لاتین +اجماع +خوانده +سابق +ریاضی +درستی +فضایی +دلایل +برندگان +بعدها +متعلق +پیشین +شدم +هنرمند +درس +ذخیره +کارگردانی +نباشد +دانقولا +اون +تابع +مالی +صدای +بلند +بارگذاری +بخش‌ها +اینگونه +اواخر +ریشه +نشد +کاخ +ریز +فرض +قانونی +برق +جلوی +کودکان +نزد +قاسم +آهن +زنجان +نگارش +شدت +می‌گویند +جایگزین +جاده +می‌کردند +مفید +زرشک +لیست +محور +ویکیپدیا +رایج +مناسبت‌ها +خلق +مراکز +ساری +عامل +نقاشی +رسیدن +کارشناسی +۱۹۸۴ +خ +زده +رعایت +انگلیس +اطلاعاتی +ورزشی +مقایسه +منبعی +بازبینی +حافظه +حتما +عربستان +مستقیم +گیرد +الدین +۱۹۸۲ +علیرضا +تعدادی +ورزش +برادر +گذاشته +تهران، +محصولات +زندگینامه +هوا +۱۹۸۶ +۶۰ +کس +پوشش +حکم +قهرمان +خانه‌های +حاج +خواهش +گردآفرید +نوبل +نرم +رهبری +خیر +تجاری +نوشت +۱۹۸۵ +جوان +واقعی +نظیر +سند +سرانجام +منجر +اعداد +فی +واقعا +نبرد +مردان +جغرافیای +شدید +روند +ویرایشی +دشت +رده‌بندی +پرحجم، +گذاری +افشار +۱۹۷۸ +زدن +سوئد +خویش +ماهی +خالی +درآمد +آمریکای +مسلمانان +کجا +می‌باشند +طوری +اید +دکمهٔ +احمدی +درد +۱۹۸۷ +شاعران +گویا +نداشت +هـ +سالهای +ششم +شیر +دچار +تاثیر +زیست +دینی +سریال +نماد +راجع +مطالعات +مراجعه +لحن +خطر +پرسپولیس +حضرت +مکتب +دامنه +بروید؛ +زیبا +بافت +مسلمان +کامیار +محافظت +ناوبری +نهایت +کلیسای +هشت +تکرار +پرورش +توزیع +معمولا +وبلاگ +طولانی +تجربه +ظاهر +گسترده +ممنوع +پیروزی +چهل +گاز +عکاسی +کاملاً +احساس +همچنان +تفسیر +چک +مترجم +مشخصات +اینها +تایید +۱۹۷۹ +توکیو +ال +سمنان +۲۰۰ +رهبر +بیت +سومین +خورده‌است +پاکستان +۹۰ +همانند +فردی +ملحق +کامپیوتر +سوریه +پدرش +اوایل +پول +سوره +تقویم‌های +آفریقا +کتاب‌ها +دنیای +همانطور +دودمان +هدایت +باره +سلسله +موسوی +قضیه +غیره +صرف +آید +ايران +پک +طبقه +حاکم +داریوش +گوناگون +زهرا +اسماعیل +زمین‌لرزه +اعتبار +بعنوان +مُروا +توانست +۱۳۷۹ +تدوین +اهواز +سبزوار +جکسون +نمایندگان +مقاومت +آی +برداشت +گشت +قلم +تنظیم +نگاری +هلند +باور +نهاد +سینمای +تمدن +فرهنگستان +کردی +ویندوز +سوئیس +کانی +نویسی +ممتنع +مانی +پشتیبانی +جو +رده‌ها +ساکن +شهرک +روزی +صحنه +اصطلاح +تئاتر +جستجو +جلو +فردا +جیمز +کی +هرگز +چیست؟ +حمل +توصیف +گیتار +ری +والدین +۱۹۷۶ +حفاظت +رشت +سابقه +کودک +کنون +فعالیت‌های +عوض +اعتراض +نسل +دریاچه +مرز +باشگاه‌های +کهگیلویه +میکند +دادگاه +تصویری +خانم +مخالفت +نصب +آل +افرادی +چاه +نماینده +نگه +عملکرد +جدیدی +۱۹۷۰ +ي +مهمترین +آمده‌است +محمدعلی +بدهید +اتحاد +شرکت‌های +موج +رم +کشیده +تحلیل +نظارت +تابلوی +شهرداری +محصول +متعدد +نماید +قوم +مصطفی +جزایر +گرمی +عقب +صلح +شعار +ارسال +جی +نوشته‌های +غلط +۱۹۷۱ +سازنده +نکرده +مواردی +جوانان +حمام +دورهٔ +تبریک +بگذارید +دانشگاهی +مس +ماند +خداوند +مهاجرت +ضبط +ست +احتمالا +لبنان +دوربین +خودشان +عبور +ارشد +بنام +فرمان +عبارتند +مطابق +خرم‌آباد +بالاتر +سد +تقریباً +اکبر +دیدن +موفقیت +مدرن +نگهداری +۷۰ +عوامل +پای +جایگاه +۸۰ +ف +زادروز +پرواز +خلیفه +هفتم +ماشین +هرچند +هسته‌ای +عناصر +اسناد +گنبد +لا +نهایی +تدریس +طلایی +زابل +چندان +اروپایی +ظاهری +صفر +اول، +اشعار +دبیرستان +معلوم +برنامه‌های +نخواهد +زد +بیفزایید +خصوصی +وظیفه +ادعا +عزیزی +عمده +انتظار +آن‌لاین +قبلا +مبارزه +هستند، +خسته +فرصت +رفتن +مشارکت‌ها +گرامی، +سراسر +۱۹۸۳ +پیروز +گویش +رفع +جزو +گفتاورد +متال +مکزیک +۱۳۵۷ +امپراتور +اطلس +اسپانیایی +پنجاه +شاپا +بیمارستان +پیامبر +بستک +می‌کنیم +اشکال +تقسیمات +الکتریکی +درک +سلطنت +لباس +دهنده +نشست +اعدام +اقوام +شاخه +سلام، +الگوریتم +چپچین +شان +خواست +مدال +امارات +جبهه +باشم +مطبوعات +مستعار +نیازی +عادی +چینی +افتخار +کهن +نا +مثبت +شخصیت‌های +خطوط +ویلیام +سلطنتی +منطقی +اطمینان +جعفر +سقوط +روزهای +گرفته‌است +طبیعت +باشیم +رده‌های +ترتیب‌پیش‌فرض +شبه +موافقم +یهودیان +تربیت +دیوید +معاون +پرندگان +ملت +دیوان +تی +پلیس +ملک +نيز +هنرمندان +عین +تماس +حرفه‌ای +آستانه +بماند +واکنش +٬ +زحمت +عمان +حافظ +نیم +منفی +آسیای +تابستان +جدی +قابلیت +ساختن +آسیایی +رجوع +شهرستان‌های +معین +نیستم +ناشی +تهیه‌کننده +داشته‌است +دانشمندان +صبح +اعتقاد +مبارک +سورنا +اساطیر +اصلاً +تذکر +خطی +کاربردی +داشتم +آدم +کتابی +مختلفی +کاربرانی +سرباز +جذب +متغیر +وضع +روزبه +مجازی +گذاشت +بابت +اعلانات +مهمی +فلان +آماده +مصاحبه +باتجربه‌تر +رقص +کلاسیک +گیاه +سامانه +مجبور +نحوه +نبوده +نفوذ +متری +کانال +حیات +گفتمان +جلسه +ارادتمند +درفش +حومه +تصور +خاندان +بهرام +لحظه +برزیل +یهودی +دهخدا +ایتالیایی +رسانه +ل +۱۹۷۵ +مسابقه +خواستم +کابل +نی +اوکراین +موسی +شما، +بگیرد +زرد +هوای +فلسطین +اهداف +است؛ +ولسوالی +غار +بنای +نوشتارهای +مربوطه +اخبار +بودند، +مهم‌ترین +سینمایی +پیمان +۸۸ +همزمان +ها، +احتمالاً +آسمان +شهرک‌های +ابتدای +ندهید +بوجود +آیدا +جانوران +سده‌های +بازداشت +هسته +یادداشت +ایلام +نامی +مجموع +هنرهای +می‌دانند +ادعای +سرویس +بگویم +ظهور +هزینه +کاویانی +الگوها +ضروری +آرام +حذفی +اقیانوس +یی +امتیاز +زمینی +آدرس +باشه +امکانات +بیشترین +طراح +نواحی +مطالبی +مقالات، +بخاطر +لی +آفتاب +بفرمایید +دقیقا +هشتم +توانایی +آیت‌الله +مسیحیت +تبلیغات +محوطه‌های +بارها +ته +سنچولی +يک +الف +متصل +ساسانی +بویراحمد +سروش +نظرتان +ربطی +روایت +بروز +دیگه +پژوهشی +زبانی +۱۳۷۸ +ثانیه +برگزاری +تبلیغ +شاهنامه +نزاکت +قوی +خواجه +پوست +پژوهش +شروین +سنی +میباشد +سرد +بگویید +شکایت +بنی +صدر +مطلبی +اسید +کلید +خسرو +گذشت +طلا +شیرازی +اي +شناسایی +تأثیر +شیرین +می‌کند، +رأی +فردوسی +اگرچه +چهارمین +نمی‌کند +زاپاس +خشک +جنگی +برداری +قادر +بومی +بنابر +ديگر +تقدیم +حاشیه +نگاره‌های +۱۹۷۲ +اختصاص +یونایتد +بردن +اندیشه +حتماً +بودجه +داشت، +افزوده +۱۹۷۴ +بیرجند +عضویت +مستند +بحثی +الکترونیک +امروزی +بیرونی +فتح +معمول +واژگان +ادب +نمی‌توان +مرتضی +اتصال +مخالفان +گویند +ناقص +سفارت +۱۳۷۷ +المللی +قسمتی +چنان +مدفن +فضا +گرچه +ويکيپديا +آمدن +زیبایی +نوشتم +عهد +رای‌گیری +سرمایه +نامعلوم +ردیف +تجارت +نیک +ایل +یافتن +اظهار +گرد +مایل +اعراب +قیمت +چی +مقدمه +خرید +عمق +گمان +هری +معتقد +داده‌است +یوسف +مردتنها +بزرگ‌ترین +فراوانی +مرور +جزء +ناصر +موشک +رومانی +دانست +نادرست +خود، +فایل +تلقی +مشاهیر +بوده‌اند +آواز +ضمنا +بشود +عثمانی +مبنای +قلب +گوش +جمعه +آیت +ویرایشات +هاشمی +دارند، +استادان +فرق +همگی +پرتغال +ذهن +پیر +زیست‌شناسی +پرنده +بتواند +ارمنستان +اتریش +اندکی +آیین +اتاق +قطعه +شناخت +تغییری +۱۹۶۸ +عبری +معیار +هفتاد +روش‌های +نکردن +فاقد +آیه +دم +عید +مکانیک +تک‌آهنگ +نوبت +دیوار +گشتن +درمانی +مطمئن +نصف‌النهار +جنس +تیره +منظومه +بایستی +ریاضیات +مهندس +رییس +بارگذار +هواپیما +میشه +آرژانتین +کلا +کریم +شاهد +گر +سنگی +مسئول +نشانه +فیلمبرداری +نوکیا +جمشید +تغییراتی +کتب +کرج +استناد +شریف +ایرلند +اف +نسخهٔ +چهره +نوید +کنگره +منچستر +رابرت +نباشید +پرویز +مى +نماز +کمال +گونه‌ای +ژان +دلیلی +داری +عالم +اسب +حمید +قرارداد +پیشینه +قره +خروجی +کمونیست +قاسمیان +می‌گیرند +شصت +زمستان +کلمبیا +راهی +محدوده +نام‌ها +میر +لینوکس +میلادی، +بهداشت +اگه +سدهٔ +۵۰۰ +بجای +مغز +پوستر +حاوی +لغت +رسانی +لوگو +مسیح +فرزاد +فرمول +مؤسسه +مفصل +پدید +درام +اردشیر +آفریقای +خرابکار +تامین +داره +اتمی +بزرگان +محکوم +نجات +یادبودهای +ریچارد +رومی +مدار +تخریب +بدانید +درگیری +بیستم +افتاد +محترم +خودروها +نوین +مطابقت +تاجیکستان +نقش‌های +افزار +مراجع +اتومبیل‌های +عزیز، +ضعیف +امضاء +بیگانه +فرا +اکثریت +هرات +می‌یابد +پنجمین +میکنند +کنندگان +فعلا +۸۵ +نکات +ارتباطات +خواهید +مجمع +کنی +یابد +منطق +دیدار +دویست +دوستانه +آوری +آلبوم‌های +اتهام +بینی +مسیحی +گری +آنلاین +ویژگی +ادوارد +امنیتی +برایتان +كرد +دیگر، +عام +اصرار +بودید +تبلیغاتی +حاجی +هرچه +۱۹۶۴ +انتقاد +برسد +شک +توانید +ویژگی‌های +خوی +۶۴ +زادگاه +مساله +فیزیکی +هخامنشی +غذایی +نمی‌دانم +سامسونگ +گرفتند +تاج +موقع +۱۹۶۹ +فاطمه +سخنرانی +سختی +استدلال +۱۳۷۶ +شهردار +ار +سلیمان +متهم +مذکور +عملی +چندی +پدیای +صادر +منتظر +٪ +ضرب +تیم‌های +تل +حسینی +گیر +سراب +تیرداد +ویکی‌سازی +تان +مشروطه +کوچکی +مردمان +ویکی‌پدیا، +مجاز +محاسبه +بزنید +جنگل +مجموعه‌های +واقعیت +سان +قومی +صفحه‌ها +قطب +تالار +خواب +تاکید +گاه‌شماری +امین +لذا +آسیب +هیات +قد +میلیارد +کوچولو +برقرار +بالایی +شیعیان +قاضی +برگرفته +عنصر +معانی +ارتباطی +شبکه‌های +درود، +۳۰۰ +مراحل +لهستان +معمولی +نوار +محس +۸۹ +قبیل +سیر +دهیم +شاخص +عیسی +ترور +دمای +تکامل +کبیر +درگیر +سونی +یاری +۱۹۵۰ +آگاهی +نیوز +پیوست +رچ +خدای +کودکی +مرتب +رژیم +روبات +ابتدایی +میتوان +هشتاد +زادهٔ +کشت +بازسازی +وسایل +بتوان +مجارستان +پیاده +میان‌ویکی +فرمانده +۸۷ +تهدید +ویک +محرم +نهم +احمدی‌نژاد +۶۵ +خورد +رسول +تمیزکاری +بندانگشتی +گیاهی +سیاست‌ها +این‌که +کلیه +بهشت +هندی +مشکوک +فکری +عقیده +اشغال +نویس +ستون +خارجه +۱۳۸۶، +۸۶ +نمی‌گیرد +کارخانه +دانشجو +پیوسته +خاطرات +پادشاهان +۱۹۶۷ +غذا +زرتشت +سود +خوشحال +رساند +آر +فیلمی +می‌پردازد +تری +لایه +سپهرنوش +ظاهرا +مصدق +کویت +مال +احداث +کانون +مد +فرماندهی +مرحوم +مواجه +۱۳۹۰، +بايد +افتاده +دوم، +گردیده +کارل +وگرنه +ندارد، +ترجمهٔ +ساحل +جم +طرفی +نگهدار +شرط +روان +آبتین +جوانبخت +سازهای +الکترونیکی +پور +نود +جمعی +راحتی +حیوانات +داروهای +دستگیر +بابک +حداکثر +دانش‌آموختگان +حلقه +راستای +اراک +نادر +اثری +زبانهای +برندارید +رشته‌های +بستن +برگردان +آبشارها +ریزی +مراغه +دروازه +پذیرش +نمایی +مدیریتی +منصفانه +واژهٔ +جانب +متعددی +رسد +گوید +شغل +زاهدان +نمای +رواج +واضح +عده‌ای +می‌مانند +ایوان +چوب +نکند +فلسفی +معنا +نمی‌تواند +خورده +سو +باند +ماهواره +مرغ +دشمن +کوه‌های +سرطان +دبی +پرداخته +ایکس +آشکار +کاشان +بغداد +ببخشید +ششمین +منظورم +جلب +دیر +مـهـران +زند +مناسبی +خانگی +تجزیه +بالغ +می‌داند +علامه +جولای +برگ +سیستم‌های +سیستم‌عامل +کاوه +۷۵ +دراپر +مدارس +ظاهراً +رنگی +دهه‌ها +چیست +تظاهرات +مربی +سازمان‌های +برپایه +متشکرم +دوازده +ایراد +گیتاشناسی +می‌برد +اسامی +او، +دارد؟ +بورکینافاسو +تجهیزات +شاهزاده +دربار +دانم +زاویه +قاره +رهبران +گ +سرود +ابهام +۱۳۷۵ +ایمیل +پیغام +فرآیند +دالبا +ح +پستی +ظرفیت +بشه +سیتی +هستیم +پرتاب +کمدی +توی +فجر +این‌جا +گرگان +می‌دانم +جواد +شاتل +خطاب +الهی +گرایش +ملا +دانشمند +فیلتر +نسبی +شوم +داستان‌های +نمایشگاه +تربت +ممنونم +آگوست +پایدار +مشارکت‌هایتان +منطقه‌ای +تنگ +مقیاس +شریک +جزئی +هویت +بدهد +نوشتهٔ +بابا +ادیان +۱۹۶۵ +جورج +هفتمین +تصرف +آهنگساز +پاورقی +دلیلتان +حس +کوچه +رقابت +نمایند +رها +مقامات +منطقهٔ +قلعه‌های +فن +مادرش +متخصص +تکنولوژی +سالی +کیفیتی +زمین‌شناسی +می‌دهم +مک +کشتار +سنگین +می‌نویسد +نکردم +ید +پرو +بدان +باران +دخالت +درختان +جوانی +آنگاه +حسب +حرفه +سندی +چگونگی +تبار +توافق +کتابهای +اطلاق +نامناسب +مایکروسافت +۱۹۶۶ +ارشاد +فردوس +صوتی +روزگار +نمودند +سگ +دارو +خاورمیانه +معلم +گره +ون +سوخت +مترو +آموخت +نشده‌است +شماست +هتل +حدیث +نداریم +پیدایش +۱۳۷۰ +میانی +کنند، +عقاید +پیچیده +غ +قهوه +فرشته +نحوهٔ +عجیب +جداگانه +هشتمین +جزئیات +همشهری +مبنی +کاتولیک +اصفهانی +حملات +جاری +پویان +انگلیسی، +برخلاف +نيست +اشخاص +مجید +سیمای +کانی‌های +تغذیه +مربیگری +برنامه‌نویسی +‌پدیا +فدراسیون +اجرایی +سیصد +احمدآباد +می‌خواهید +جنگ‌های +پیگیری +حوادث +اخیراً +دیجیتال +تکیه +مریم +الی +۱۹۴۸ +كند +عده +اقدامات +شعاع +تخیلی +ماه‌های +۶۶ +آزمایشی +شده‌است، +واژه‌های +دشتی +موافقت +قهرمانان +جلال +اچ‌دی +الفبای +نفس +پایانی +پانصد +برایش +ترجیح +خواند +سلول +عصبی +کوخرد +آب‌انبار +۶۲ +مفاهیم +شنبه +بالاخره +دانسته +هواپیمای +نهمین +ایالتی +مو +فارغ +پلی +دروغ +اداری +استقبال +مسئولیت +داده‌اند +فدرال +ترانه‌های +نوازندگان +چای +دههٔ +تراکم +فهرست‌های +مردی +زمرہ +گورستان‌های +سوالات +عباسی +سردار +محک +ترکیبی +رقم +سعودی +نرم‌افزارهای +بازرگانی +برلین +نروژ +مارتین +فوت +دیدنی +کنفرانس +فارسی، +اهر +نجف +پذیرفته +اینست +ملکه +سرخط +كرده +زنی +قلمرو +بخصوص +امی +بهائی +نقاش +کازرون +تار +گرفته، +نظم +۷۲ +خودداری +شمس +صفحه‌ای +بیمار +واقعه +هادی +۸۴ +خاتمی +بارسلونا +سرچشمه +زنز +برچسب‌های +منتخب +بحرین +واشنگتن +پاتر +کرده‌ام +شاهین +زرین +مارک +توپ +وقوع +حدی +آذری +شاگردان +معبد +آرمان +۱۹۶۲ +بیماری‌های +بچه +فعالان +کوروش +دارویی +اوقات +اوست +می‌کنند، +قضاوت +ین +دست‌اول +فریدون +تئوری +نمی‌توانید +دوستی +حقیقی +زندانی +مقطع +راستش +۱۹۶۳ +شاپور +۱۹۵۶ +آکادمی +بازنویسی +ارمنی +۱۹۶۱ +مهران +مردمی +ندارید +گذاشتن +کوتاهی +فقه +تنکابن +درجه‌بندی +ژنرال +مایع +طرفداران +مدارک +بدلیل +پیشنهادی +باشند، +ذرات +دانشجویی +نگارخانه +نیت +کیلوگرم +سردشت +ایده +تسلیم +برادران +هزاران +حادثه +مرتضا +خواستار +نهضت +نرسی +آمیز +استودیو +قدمت +مجموعهٔ +مغناطیسی +قطعات +عمران +توجهی +فیلم‌ها +كار +۶۳ +رسم +درب +مبتنی +امواج +تمایل +احزاب +روحانی +ء +اردن +۶۱ +عمارت +می‌دانید +گفتار +دزفول +داوری +کا +حقوقی +زمستانی +فولاد +امریکا +مزرعه +بوده، +رساله +رامین +جراحی +محقق +ابزارهای +ویکی‌ +پزشک +قبلاً +ضلع +سرور +مجاهدین +اخلاق +گراف +مانع +مشارکت‌کنندگان +قشلاق +نوازنده +پرده +۱۹۵۳ +شیروان +کاظم +اریکسون +طیف +مسکو +۱۹۳۰ +۶۸ +مقابله +لوله +علی‌آباد +واقعاً +معدنی +طباطبایی +شاهان +تاريخ +ودر +ماهان +یوشیمیتسو +۱۹۴۵ +نمونه‌هایی +البرز +چهارمحال +مالزی +۱۹۵۸ +خودرویی +بیاورید +آبادی +مخابرات +می‌دهید +رودبار +جور +یحیی +كتاب +وین +می‌داد +غلامرضا +طایفه +سطر +خواهیم +جانشین +اقامت +توده +مشارکت‌های +برود +جویا +می‌روند +نتیجهٔ +اختیاری +اساتید +آگاه +ساوه +قدس +ناخالص +چرخ +پردازش +خرم +به‌ +کاربردهای +فیلسوفان +طب +زمانه +وحدت +افغان +منوچهر +طرز +بوسیله +مدیری +اخذ +اصلاحات +فرهاد +۱۳۷۳ +بایرن +تور +۸۲ +بست +راحت +تقلید +لهجه +قرون +افسانه +۶۷ +منزل +۰۰۰ +رکوردز +تأثیرات +افتتاح +بزرگتر +هندوستان +نقره +بهشتی +پذیر +عظیم +سیم +خواص +اعتراضات +سخنان +رزیدنت +مسجدهای +هرگونه +می‌آورد +این‌ها +دقیقاً +بسکتبال +صوت +بوئین +۱۲۰ +۱۵۰ +شور +زودی +توانند +سربازان +رویداد +خب +بنیان +چلسی +زیبای +شورش +خامنه‌ای +برایم +درخواستی +روان‌شناسی +جسم +ممنوعیت +اهورا +چقدر +ابوالحسن +سالن +صحت +می‌خواهد +۹۶۴ +نرخ +اختلال +رویدادهای +خراب +تونی +دایره +دبیر +۸۱ +۱۳۶۸ +دانشگاه‌ها +تقویت +زلزله +دهانه‌های +کوهستانی +محض +۱۹۵۴ +نبودن +بين +کارکنان +جملات +خاکستری +دادید +فرایند +دارا +وفيات +چهارصد +خصوصیات +چارلز +گفتند +ستاد +۱۰۰۰ +پیتر +انگلیسی‌زبان +مجتمع +وسعت +می‌شدند +۱۳۷۴ +نیروگاه +گذار +قوچان +تحصیلی +دهی +میلان +نمی‌کنم +فرم +پستانداران +گردن +۱۳۷۲ +۱۹۴۰ +جناح +شوشتر +پذیری +لیبی +اسلامی، +بحث‌های +سوء +همسرش +قفل +اسکندر +تحلیلی +تحمل +فعلاً +۱۳۵۴ +میوه +مصنوعی +ارزیابی +روزانه +مدعی +دانمارک +فرستاده +شناسه +صبر +شطرنج +گفتید +وسیع +گام +گوشت +کرده، +رصد +کوهدشت +اینطور +نوجوانی +ملت‌های +محمدی +۶۹ +لشکر +بزرگراه +۱۹۵۲ +پاینده +۴۰۰ +جانبی +ایول +تجدید +نیست؟ +حامد +نشریات +توماس +مجازات +قیام +گپ +سینا +۷۸ +بس +وظایف +کوهستان +اینجاست +میدهد +کارها +سالها +یادبود +آبادان +طبس +خوردن +روزه +مسکونی +اعظم +دموکرات +خشونت +۸۳ +هوشنگ +تخصص +سیما +منظر +علمیه +سالم +پیکسل +کمکی +خواسته +ایرج +مدنی +گفتن +آذربایجانی +ره +اتمام +آلاباما +۱۹۲۰ +ابی +بام +فقیه +کیلومترمربع +عوارض +۱۳۵۰ +ترس +بازگردانی +سعدی +موثر +کلیبر +انقلابی +وبسایت +روانی +موردی +دختران +روس +بم +پاک‌کن +داشته‌اند +یوتی‌سی +صدها +پانویس‌ها +نفتی +ورزقان +کمبود +نابود +فرانک +دان +۷۶ +جرج +جدایی +کیهان +نامش +تبریزی +کتیبه +حکومتی +قسمت‌های +صرفا +ك +۷۱ +اندازی +قدم +منحصر +عموم +پهنای +پدیده +روغن +رسانه‌های +اطلاعات، +سایت‌ها +اکران +سلامت +بالاترین +پیروی +۱۹۵۱ +مصداق +۷۳ +شکار +مباحث +پوویا +٭ +فاصلهٔ +فاز +۷۷ +حالیکه +شهریار +۱۹۵۷ +درخشان +آن‌جا +تنهایی +نکرد +عدالت +می‌نماید +مقبره +سانسور +داده‌ها +شاهرود +تخمین +نشست‌های +۱۹۳۶ +جین +روبرو +پس‌زمینه +نیرو +اخلاقی +داستانی +سینه +چ +شاهنشاهی +مولانا +گاو +استخوان +گرگ +دکتری +اند، +کشف‌های +سنندج +۷۴ +ساحلی +برهان +پیش‌نمایش +کردم، +دوره‌های +۱۳۵۶ +آغازین +سالانه +بستگی +تخم +۹۹ +سیگنال +ویکی‌پروژهٔ +ناقض +خودمان +کرد؟ +ویرایشگران +داوران +برداشته +۱۳۷۱ +یکمین +ریزشگاه +سوار +سلاح +شایسته +سفیدپر +غزه +ترکیبات +لاله +اولی +گذر +جک +ذیل +دراز +۹۵ +پان +درصورت +ایرانشهر +عرصه +پیروان +پردازنده +زایش +مدینه +انفجار +کمپانی +فرشتهٔ +واحدهای +حرارت +بعداً +۱۹۴۹ +همینطور +استخراج +ملاقات +فرو +پارامتر +منتقدان +آزمایشگاه +نوشته‌شده +اصطلاحات +بتوانند +مشتری +متوقف +اجباری +مسلح +سلجوقیان +کندی +اسکاتلند +فیلسوف +می‌سازد +زود +۷۹ +رجبی +هفتصد +تقی +معدن +مار +فراز +ایالت‌های +ایمان +ابراز +ممسنی +رادیویی +سرکوب +پیوندها +۱۹۵۹ +توزیع‌کننده +کشید +بال +۱۳۵۸ +۱۹۵۵ +شفاف +کلام +یکبار +رصدخانه +موسوم +صلاح +اخیرتان +کالج +واز +شیکاگو +جنبه +۱۳۶۹ +عاشق +کک +خنثی +امیرکبیر +آنقدر +زبان‌شناسی +مشاور +نمایشگر +دا +مِنْ +آرزوی +آئین +می‌آیند +شکلی +۱۳۶۰ +سقف +فرامرز +بحث‌ها +همت +خیام +تصادفی +میتواند +تجاوز +روح‌الله +روستاها +هواپیمایی +گلدن +منظورتان +کرمانی +قله +ضربه +ساکنان +اورشلیم +مجدد، +ویکی‌پ +معتقدند +۱۹۳۸ +محیطی +جعفری +خطا +ویروس +نگار +ث +سال‌ف +ابراهیمی +هشتصد +نکنم +ذوب +رایت +هاست +متنی +نان +اضافی +باله +اصغر +تایلند +را، +پیانو +سکونت +تالیف +اختصاصی +بهتری +ترابری +چو +دیو +زندگی‌نامه +شیشه +قلبی +تحریک +کیش +ستاره‌ای +اختراع +برآورد +سزار +دهستانی +مجسمه +برطرف +سپرده +پارلمان +رمز +درسی +سپاهان +منصوب +۱۹۴۱ +پروانه +جمع‌بندی +فعل +کربن +دژ +تفکیک +قفقاز +ۚ +همراهی +عبدالحسین +بسيار +مواليد +۲۵۰ +پیرو +معاونت +پیرانشهر +۹۱ +معنوی +کاروانسرای +دفن +سیزدهم +ند +اینقدر +هخامنشیان +دستگیری +گل‌های +می‌خواهم +گیرند +متفاوتی +شیلی +مراکش +کنسرت +بدهم +تومان +کهکشان +اوضاع +اندونزی +چنانچه +جایزهٔ +بدهند +کروبی +سکه +گرفته‌اند +می‌شوم +تضاد +ملایر +شیطان +سهم +اخطار +حرم +موافق، +هیتلر +واسطه +ناظر +نمودار +بگوید +تیمور +قصر +مکانی +فرودگاه‌های +۱۹۴۶ +جهاد +مقداری +داد، +اندک +دکترای +فیلیپ +۱۹۳۳ +کارگران +آماری +۹۸ +تست +ى +هستی +میزبان +تقاضای +اوبلاست +شیوه‌نامهٔ +من، +محتوا +مربیان +دیسک +معتبری +زدایی +صعود +حکمت +مخفی +زمینهٔ +دهان +گو +رمضان +ششصد +هم‌اکنون +شکسته +‌است +حرفی +۹۶ +هواداران +تبعید +نشین +توجیه +مکه +جاذبه‌های +منافع +بیفزایید، +عرفان +کشی +آمریکایی‌های +عقل +وفات +سیب +پربارتر +کنه +تألیف +بنیانگذار +دموکراسی +نهصد +یادم +سراسری +تفکر +لارستان +برگزیدگی +رباط +لس +حساس +حبیب +ویکی‌پدی +فرود +همکاران +تشویق +تحویل +باقری +داده‌های +معرض +گلوب +کلیسا +ویکی‌پد +کف +۱۳۶۷ +امضای +بخواهیم +خالد +فلزی +نظرخواهی‌ها +آیات +درگذشته +شباهت +هم‌چنین +تعلق +بگیرند +گوناگونی +نایب +حساسیت +کارگردانان +مغول +سازمانی +دیا +داغ +خواهی +فشرده +ماجرای +زندانیان +تصاویری +بیماران +کهنه +مکمل +بخواهید +رایگان +رویه +ماری +فرمایید +بلورین +فورد +درخواست‌های +سازد +پروتکل +راس +فرقه +وفق +نازی +احتمالی +طلب +اقماری +محدودیت +همایون +۱۱۰ +هیأت +احسان +ابرخس +بخواهد +له +مهرداد +می‌شوند، +سکوت +مهاجر +صدور +بازیگری +آسان +سراغ +اولا +محلول +وان +کوی +الکساندر +لیسانس +خزر +۹۲ +شکنجه +امیررضا +گرجستان +بازرسی +عکاس +۱۳۶۲ +آسیاب +گویی +شود؟ +حیاط +موجهی +ارکستر +ارباب +نویسندهٔ +یخ +السلام +نسب +بوی +۱۹۴۷ +نمي +اعضا +خانوادهٔ +ویکیپدیای +سحابی +شاهی +شیوهٔ +زیارت +تحقیقاتی +فعالیتهای +کاغذ +تهرانی +پروفسور +بریتانیایی +اخیرا +ایرنا +مادرید +۱۳۵۵ +زمینه‌های +ببینم +۱۹۳۴ +می‌بینید، +فیفا +صالح +متداول +ربط +سطوح +ی‌پدیا +خواهدشد +بحران +۱۹۳۹ +افکار +پیراهن +۱۹۳۲ +انتظامی +بلافاصله +ارایه +کمیسیون +راز +محمدحسین +آبیلا +محبوب +سایه +جوامع +داور +۱۹۰۰ +زودتر +ولز +سوخته +تأیید +ابوالقاسم +برادرش +بمب +امتحان +آرتور +فرستاد +صص +دانشجوی +کارگر +هوش +اتفاقا +غلامحسین +قربانی +می‌خورد +احکام +سرزمین‌های +ضمناً +فینال +قبرستان +ضعف +نامهای +گندم +قواعد +تند +تایپ +ماموریت +موسیقی‌دانان +گوشه +دری +مناسبت +ارقام +چاراویماق +مبانی +گذاشته‌اید +ابر +مدخل +یو +شناس +اندازهٔ +غالب +قنات +مبتلا +ویکی‌فا +نوزدهم +مونیخ +کابینه +میرحسین +باقر +۱۹۳۵ +سامان +هلندی +موجودات +فنلاند +برعهده +مدافع +قطار +تغییرات، +فرمانروایی +واگذار +حکیم +آهنگسازان +شوند، +تحول +مرکب +مقادیر +اختیارات +نوشتاری +چندانی +جان، +هکتار +رازی +محله‌های +آوردند +صف +مقاله، +تدریج +نیستید +تسلط +اسلام‌آباد +آزمون +ویرایشاتشان +اصولا +صفت +۱۹۳۷ +می‌شد، +سفیر +تمرکز +شهروند +نمودن +ویتنام +نمایندگی +گردش +سران +فر +ایمنی +خو +مشارکت، +پسرش +می‌ماند +متروی +ختم +علمای +۱۳۶۴ +ران +کودتای +قهوه‌ای +دایرة‌المعارف +لنگه +درونی +سرا +خاموش +منصب +ماد +دومی +کشور، +سوادکوه +خدایان +بی‌طرف +ماجرا +دماوند +بردسکن +ویکی‌نویس +ماهنامه +یادگیری +قابل‌ +هاشم +همگان +روانشناسی +محمدآباد +نگهبان +آفرید +گیرنده +۱۳۵۲ +۱۳۸۹، +ترکان +هوی +دندان +خوش‌آمد +گرفتم +پایهٔ +دانلود +جفت +فهم +گوشزد +متشکل +رسمیت +مقدماتی +جویباری +پيش +کنیم، +استانداردهای +سرجعبه +آنجایی +خیریه +بیش‌تر +في +دکمه +ماندگار +فیروزآباد +بخار +فیلیپین +جلگه +آرامش +۹۳ +رونق +پاسداران +میتوانید +کاووس +۱۳۵۳ +۶۰۰ +مرو +نیافتید، +نداره +نجفی +الهام +میکنید +ناصرالدین +قصه +آمدند +پراکنده +خواهان +روي +مرودشت +مسیحیان +عبدالهی +حسابی +پاییز +جانبدارانه +کی‌پدیا +حین +پلی‌استیشن +اعصاب +می‌توانیم +فرح +نمک +به‌طور +۹۷ +۱۳۵۹ +گرافیک +زمین‌لرزه‌های +منتهی +مستقر +تقدیر +۱۹۳۱ +می‌رفت +افسانه‌ای +برخط‌اند +آبشارهای +برخوردی +عکسی +خاور +مورخ +جمال +باتجربه‌ترند +به‌کار +مطالبتان +راه‌آهن +نفع +پاجعبه +نسخه‌های +بدی +آکادمیک +امتداد +یوشیچی +رضاشاه +تأمین +خواهشمندیم +لو +رئال +خراسانی +سردر +آشپزی +ایرانیکا +شاگرد +سرای +یزدی +نامزدهای +وکیل +نقشهٔ +اکسیژن +شفافیت +یکی‌پدیا +مقیم +ویل +یادآوری +بلوری +شعاعی +قائم +آلن +استانبول +بکنید +عمیق +تایمز +سلماس +بی‌طرفی +بیل +ۖ +بویژه +تک‌آهنگ‌های +می‌باشد، +جماهیر +وحشی +نمایشنامه +روایات +غنی +کسروی +بازتاب +شاملو +اروپای +برنج +بيشتر +اخراج +جمعیتی +اخترسنجی +شوش +خوشنویسی +تقاضا +مکان‌های +کریمی +۱۹۲۹ +دفاعی +برگشت +کنید؟ +معمار +خوش‌حال +قوه +۱۳۶۵ +اکسید +لاهیجان +آئیله +عقاب +پائین +سوالی +کنم، +مان +خواف +انجیل +محاکمه +ور +كنيد +میخی +مرزهای +روشی +بل +آداب +زرتشتی +باشی +جهرم +آور +شهادت +رسیده‌است +سادات +زحمات +بنویسم +شریعتی +بان +مرتبه +آثاری +شه +کابلی +تویوهارا +بیجار +می‌زند +نگران +کر +سیرجان +اماکن +ایلخانی +ماست +گزینه +دوشنبه +شواهد +قاعده +موازی +شتاب +۱۳۶۶ +حال، +ویا +می‌برند +۱۹۲۴ +نت +نجومی +تعارض +سادگی +۱۳۰ +خلافت +تأثیرپذیرفته +طبری +تعقیب +کاشانی +منع +توضیحی +دورود +حبس +بهایی +محاسبات +بگوییم +تنوع +معادله +۱۳۵۱ +کوچکتر +جوی +دورنما +شرایطی +فرماندار +هریوا +پی‌گیری +۱۹۲۸ +می‌نامند +ط +فومن +الجزایر +سیاست‌مداران +۹۴ +مقدم +طرفین +چمن +صفویه +یر +نابودی +رفسنجانی +معادن +۱۳۴۷ +نیل +سانتی +دام +نامه‌ای +ات +یافته‌است +می‌دارد +بقعه +۸۰۰ +پرتو +قید +ظرف +لری +قدیمی‌ترین +انسان‌ها +برنامه‌ریزی +وسطی +مسلم +چالوس +پیشتر +پوشیده +فرزان +میشوند +منظم +تلفن‌های +خوشحالم +تجمع +رنج +آباد، +مختصر +هماهنگ +روشهای +لفظ +چوبی +همين +شادی +وسیعی +گور +کردیم +تندیس +مواقع +الیگودرز +نسبتاً +هٔ +مخصوصا +شی +مشهورترین +می‌خواستم +انها +نهنگ +حرکات +دنباله +قانع +۱۹۴۲ +داوود +می‌کردم +جاوا +تعادل +پزشکان +نحوی +مادی +ردهٔ +گذاشتم +۱۳۶۳ +کمان +بعدا +شرمنده +ویراستار +ایام +اسلواکی +ناراحت +متحرک +تجربی +خاصیت +گیلانغرب +کشتن +مرزی +پرچم‌ها +ذهنی +لر +مساوی +رستمی +کرم +ازبکستان +رضایی +احیا +هنگ +توانم +شکر +مند +کمتری +بردارید +قبر +فرعی +ایم +معارف +پیوندی +اطلاع‌رسانی +بسازید +کردند، +کلیدی +سيستم +لغو +بسیج +سرنوشت +شاخه‌های +طرفدار +سیاوش +کشیدن +پناه +هشترود +ورزشگاه‌های +صفحه، +عارف +ابرکوه +،خرد +دراین +بایر +قلی +دشوار +بیزانس +بهانه +جالبی +قبیله +بیژن +چنانکه +می‌ +بیانیه +آلفا +کارگاه +استوار +کش +پویا +چیزهایی +نمی‌کنند +رهنمود +وصل +کریس +پسوند +مهاجم +جامعه‌شناسی +مجددا +ایر +احتیاج +متأسفانه +خودکشی +۱۳۴۸ +مراتب +یازدهم +خام +نوجوانان +بدانم +طنز +چهره‌های +شبانه +دامغان +مقصد +وزیران +لوح +شهرام +بده +جلا +دشتستان +روزنامهٔ +چهارشنبه +دالاهو +ضریب +تکنیک +سرخس +ولي +دکترا +آنجلس +خرس +مجتبی +نهاوند +مسیه +حسینیه +كنند +ملاک +۳۶۰ +هندسه +ابو +کامپیوتری +۱۳۴۵ +۱۰۱ +صندوق +بلی +آقایی +قالی +۱۹۲۵ +اشتغال +اوستا +خاش +باتری +قربان +رمان‌های +زير +خالص +زدم +باشد؟ +توقف +دوستانی +اجتماع +کوهی +کلاه +قائل +فلز +مطلوب +گربه +نگرانی +زوج +یار +سرپل +نوروزی +۱۹۲۶ +الآن +اختلالات +بریتانیکا +ايجاد +آزار +سا +پروتئین +بادی +مجزا +سانتیمتر +اله +پسران +۱۳۴۶ +دروس +کور +مطلع +نستعلیق +خطرناک +لوگوی +دنده +ویژه‌ای +بهینه +الکترون +سقز +عددی +کاش +جیرفت +راسته +بتوانم +نسبتا +یازده +کمیل +مانفی +انتخابی +نداشتن +حرکتی +کمترین +مرورگر +مقاله‌ی +برنز +انشای +فراتر +وسیلهٔ +انزلی +سوم، +آشور +اجزای +روزنامه‌های +نداشتند +برتری +توقیف +گنجایش +نویسندگی +واشینگتن +وَ +عبد +ماهیت +ترکمن +تابش +برف +اثرات +نمایشی +است‌ +حدس +بین‌الملل +۱۹۲۳ +راوی +بامداد +تنگه +گذراند +اتفاقی +هالیوود +گشته +اسمیت +باش +آلی +ترکمنستان +سوسیالیستی +مجلات +۱۹۱۸ +بدنه +قاهره +خانهٔ +بید +ایرانی، +۱۳۴۰ +پری +اشتباهی +نهاده +وب‌سایت +شهروندان +همایش +خوان +نژادی +عملیاتی +افزود +مخلوط +رودسر +الیزابت +نمونه‌ای +مغزی +قضایی +یان +گالری +بگو +ملقب +ایفا +انیمیشن +بخش‌هایی +شکستگی +سوپر +کانی‌شناسی +ویتامین +می‌دادند +پرجمعیت +درسال +۱۰۵ +ستاره‌های +مدیا +بندپی +تردید +كشور +ماهیان +پوزش +انگار +اسلام، +ايشان +سرپرستی +تاکستان +۱۹۲۷ +۱، +پذیرفت +نما +مشتق +باستان‌شناسی +امامی +اتم +ندیدم +نوشهر +گزیدن +۱۹۱۹ +حیوان +بنظر +کورش +اواسط +رفتند +تبادل +میلی +استون +دانستن +آمریکا، +حصار +آینه +گرایی +قبایل +کبیسه +۱۹۴۳ +۱۹۱۲ +۱۹۱۷ +برقراری +فيلم +نداشتم +سرده +فعالیت‌ها +بوستان +خیال +کارش +کربلا +کنم؟ +سیاست‌مدار +معنایی +آلودگی +شماری +کودتا +پانزده +المعارف +کالبدشناسی +عظیمی +علائم +کنسول +نحو +سوئدی +گرفت، +مازندرانی +مثال، +منسوب +نشدم +ویران +درخشندگی +بندرعباس +ارگ +سامانه‌های +بیمه +انجامید +اردکان +متمرکز +سلولی +مرسوم +صادقی +هيچ +امثال +ولتاژ +مقررات +رکورد +بلخ +نامزدی +پردیس +راه‌های +‌ای +مانده‌است +هدیه +خاکی +کلاً +كنم +جویبار +گرجی +سنجش +بو +مثلث +جمهوری‌های +خاتمه +رشتهٔ +بوش +حسین‌آباد +۱۳۴۹ +جنگلی +عزل +مزار +اختلافات +زاکسن +عشایر +دشمنان +کنگ +یهودیت +الگویی +فرکانس +تحریف +پژوهش‌های +شام +لار +می‌بینید +مریخ +علی‌اکبر +عامه +روزها +زخمی +عبارت‌اند +ویکی‌های +بری +کارائیب +رده‌فرد +رحیم +نگاشته +القاب +قاتل +مکرر +محمد، +ابداع +ویدئو +اسطوره +جامد +ژنتیک +مجاور +سیاسی، +رفسنجان +بعید +مرند +روحانیون +اریک +قریب +نثر +تحریم +موزیک +برداشتن +ارتفاعات +اشکالی +غذاهای +شهاب +بورس +سال، +نقشه‌های +عروس +نخل +محلات +آلبرت +فا +دشمنی +۱۹۴۴ +يكي +جایگزینی +تفاصیل +خدابنده +اقلیت +مشخصی +محاصره +زین +افتخارات +این، +بي +سواحل +اندام +فرماندهان +دانند +دوازدهم +بجز +آرا +بهائیت +۱۹۲۱ +کالا +استقرار +تلخ +تکه +جلوه +امان +نگونبانگونی +فیلمنامه +مترجمان +کتاب، +بستر +تولیدی +باغ‌های +نباشند +انصاری +محمدتقی +ان‌جی‌سی +سلمان +پهن +گستره +سودان +پرهیز +همون +موسسات +جاهای +اشرف +سواد +مصوب +دانه +اينكه +شعبه +تشیع +اپرا +مجری +موضع +۱۴۰ +گلوله +دارایی +آوردم +۱۸۰ +بلد +سیروس +گرمسار +مهارت +پیشاپیش +ساختمانی +باختر +نامید +ایفای +باریک +تعجب +عقد +فرمودید +وطن +گوی +قبرس +محبوبیت +کوچ +جدید، +اخترشناسی +کلمهٔ +ایذه +احوال +پراکندگی +ویرایش‌ها +سانتا +نپال +چرخش +فخرالدین +دستگاه‌های +پاراگراف +می‌توانم +پیکر +بعد، +جای‌ها +یاران +بیگ +پنجره +رامسر +خواه +انکار +می‌کشد +۱۹۲۲ +برعکس +پاره +اکشن +لغات +گردآوری +سهراب +نیز، +عراقی +پاسارگاد +نوجوان +مخفف +هیچگاه +کاندید +بهروز +بناب +تهمت +آفریقایی +جسد +پژوهشگران +موسس +بلاگ +آبخواره +مایه +مجدداً +لقب‌ها +تلسکوپ +استانی +منتقد +داراب +دلخواه +فرش +بارگذاری‌شده +صحرای +نوک +فارسي +رسانه‌ها +ماکو +۱۳۶۱ +استفادهٔ +دستیابی +سرو +بردار +آلبوم‌ها +مکعب +تب +می‌گرفت +وی، +قطعی +اقبال +پلاک +برابری +جوش +التحصیل +بردند +شارل +خشم +سارا +گناه +حوصله +بیافزایید +اصیل +خودمختار +نمی‌دهد +داند +سراوان +صور +یعقوب +شنیدن +اشتراک +دفع +اد +ه‍ +وستفالن +بهائیان +پناهگاه +مسیرهای +هست، +مذاهب +گران +تابعیت +یابی +ولسوالی‌های +اسرائیلی +تاریکی +تعطیل +همکار +زور +خلیل +شوخی +سلول‌های +تنش +کرسی +نصف +می‌افتد +بیات +فضل +نامشخص +تعبیر +۷۰۰ +شو +سوسیالیسم +اب +پرچمک +دموکراتیک +تحولات +بگیریم +گسترده‌ای +آریایی +کیلو +والی +براون +ناچار +گنج +بلندترین +انگشت +محتواهای +۱۳۸۵، +نه؟ +یهود +وضوح +بلوک +بلور +باکیفیت +غير +بدل +نادیده +لاریجان +دلفین +جاز +حاکمان +دوری +آرای +خاوری +شناختی +ماریا +شیب +نیوزیلند +مشکین +منتظری +خریداری +۱۱۵ +جانی +به‌شمار +تعلیم +تأکید +اندازه‌گیری +یافتند +مادری +فون +بادن +کدهای +بدنی +لوئیس +ادامهٔ +مبلغ +صلیب +می‌بایست +آریا +۱۲۵ +بفرمائید +قراردادی +شر +گفت‌وگو +گرینویچ +مولکولی +نیو +سايت +۱۹۱۴ +جزیره‌های +رسیدند +فرمت +قائم‌شهر +تفرش +نظریهٔ +خواستید +هافبک +دائمی +تنیس +می‌دهد، +ماتریس +باخت +سیا +مغرب +سل +اسلحه +ذهاب +دهد، +فرقی +صرفاً +وبلاگ‌ها +نمیشود +راضی +آتن +چراغ +حالتی +شلیک +الیور +اینکار +برپا +آهنگرکلا +لویی +نیما +بجنورد +نهادهای +محروم +نکا +لب +وحش +اعتراضی +ژن +ويكي +عثمان +نیشابوری +بلک +کنندهٔ +موتورهای +رئیس‌جمهور +حکایت +حاکمیت +نفره +هرسین +مالیات +انجام‌دادنی‌ها +خودت +مناقشه +کارهایی +غذای +نوردراین +علل +دیپلم +دادگستری +پیچ +لیورپول +سرپرست +گلی +تفت +جنسیت +امری +صبا +اسفراین +ریخته +برا +ناپلئون +دبستان +ویدئویی +خمیر +انتخاباتی +گفته‌است +ورزشکاران +عادت +آرایه +اعتراف +استخدام +آرامگاه‌های +دوتایی +ارنست +عمدتا +مجهز +زدند +۱۳۳۰ +۱۳۸ +۱۳۳۲ +آلبانی +نشانه‌های +باغین +شعبان +فارسی‌زبان +نیمی +سازگار +زبانان +پیست +کارایی +گرافیکی +کوره +اتیوپی +ساوجبلاغ +مشرق +فِي +سیزده +۱۰۳ +مردم‌شناسی +بلندی +محمودآباد +بتا +۱۰۲ +مراد +افتخاری +سهام +امیدان +دلایلی +غول +۲، +مازیار +عمدتاً +مملکت +۱۳۴۲ +انگیزه +فرنگی +مینودشت +بقایای +ابوالفضل +فاکس +میگوید +همچنين +شعری +لس‌آنجلس +تائید +تاریک +تونس +بستان‌آباد +کارمندان +اسحاق +۱۶۰ +کارگری +پتانسیل +سحر +۱۰۹ +نیازهای +آرسنال +افزون +نظریات +کوبا +فهرستی +آزادگان +کارشناسان +تزریق +کاپیتان +حدودی +فیل +والیبال +ازای +این‌گونه +همانگونه +نداده +سردبیر +تالش +سام +می‌گذرد +آنتی +مجلهٔ +بازی‌ها +رجال +هم‌درازا +دختری +رفته‌است +ابریشم +فلوریدا +بلغارستان +مصری +بلوار +دليل +راه‌اندازی +۱۰۴ +شمشیر +ندا +صادرات +دانیل +هریس +کله +حوزهٔ +نشسته +بیاندازید +۱۲۸ +وبه +تازگی +شورا +سروده +درمورد +شدند، +قطعا +اراضی +می‌گویید +حامی +خوراکی +جایزه‌ها +کویر +مفهومی +رودهای +زمان، +کمیاب +مخاطب +سوابق +سلامتی +علوی +خواندم +نهایتا +هوشمند +همیشگی +همدیگر +سازه +ترویج +مقر +قشم +تغيير +دیروز +مخالفم +نجوم +آرزو +عموماً +افقی +گوشی‌های +رباتیک +کلاته +لورنس +وزیری +پرداختند +رجب +جوزف +سپری +تایوان +مقاله‌هایی +بود؟ +بزند +مرسی +باختری +صلاحیت +نمی‌آید +بهشهر +جماعت +خونی +نوشته‌است +ازنا +مکانیکی +فضاهای +فرمانروایان +رزمی +همسایه +همدانی +۱۹۰۸ +۱۹۰۵ +هردو +۱۱۴ +هرم +شهرکرد +۱۰۷ +آب‌های +متقاعد +شویم +نبود، +نویسان +هم‌زمان +شهر، +صخره‌ای +ارزشمند +۱۳۲۰ +حذفش +سامی +ثانویه +دن +احساسات +بوئینگ +نام، +شبکهٔ +شمرده +طوایف +باری +جبر +اجازهٔ +بزرگ، +بهم +۱۱۱ +جهان، +مولوی +تفریحی +ماساچوست +آنها، +اجتماعی، +طاق +خوشامدید +نیامده +اچ +ملاحظه +کمبریج +زی +برش +می‌گذارد +شدگان +بدو +درحال +چارچوب +شده‌اند، +قطبی +لئون +هیدروژن +کاردانی +درمیان +نقاشان +شنیده +چنين +آتشکده +کوههای +قروه +هجوم +سرهنگ +عکس‌های +تاجگذاری +خرج +۱۳۴۴ +جعلی +آمیزش +راهپیمایی +سرشار +فیروز +دوک +بهداشتی +شکی +ماهواره‌ای +طاهره +زیرصفحه +تسخیر +مخزن +حیدر +اتفاقات +غزل +زهج +بولیوی +کردها +۱۹۰۱ +قند +نخست‌وزیر +بازهم +عصب +مهاباد +پرس +گازی +ابزاری +مبدل +۱۳۵ +میشل +مستقیما +صدام +محکم +فلزات +طنابداران +پروژهٔ +امّا +صحرا +۱۰۸ +جملهٔ +شوهر +هواپیماهای +سعادت +جعل +صفحه‌کلید +اوباما +۱۹۰۶ +انب +اپل +مرخصی +معیارها +دانید +دعا +تلفات +تضمین +آرامی +دائم +شد؛ +چرخه +شجره‌نامه +آفرینش +معادلات +رسما +مزبور +بارش +برکه +نبی +مصالح +والتر +سدیم +بحثش +پیشگیری +پروین +نشود، +می‌گردند +مسافر +راین +بتن +خوشه +طوسی +جونز +وابستگی +اسیر +خیابانی +بت +اینجانب +ببینیم +لیکن +بگذاریم +شراب +انگیز +برروی +حاجی‌آباد +پارسک +اعزام +اعطا +فقر +علي +کارنامه +حجاب +اینک +جمع‌آوری +درهم +خواهشمندم +اینه +گانه +پارچه +گردیده‌است +مداوم +آلوده +حقایق +جعبه‌دندهٔ +بشری +چهارده +۱۳۰۰ +لیلا +بدیهی +مابین +مثنوی +ویدیویی +محققان +رابط +تلمبه +پرفروش‌ترین +استیو +ساختمان‌های +وانتشار +معترضان +وحی +برنامهٔ +بگم +عسل +پرتغالی +فصلنامه +عجب +رفتارهای +وورتمبرگ +امپراطوری +برون +شانزدهم +مدل‌های +آکسفورد +فساد +چیزها +خبرنگار +ذره +کان +کنیم؟ +دامداری +هی +عبدالکریم +کوهرنگ +آنتونیو +ایرادی +۱۱۶ +دریافتی +هرمز +آب، +گـپ +ویکی‌پدیایی‌ها +۱۰۶ +غریب +دلفان +راسل +۱۹۰۷ +گویم +قزاقستان +وحشت +منشور +انتقام +مشروطیت +کیفی +بپردازد +براى +شركت +تعصب +ویلهلم +خطای +متقابل +۲۰۱ +اشکانی +می‌کرد، +بروجردی +طبقات +طالبان +سفارش +فیلمهای +آهنگ‌های +کنستانتین +پیوستن +دیدگاه‌های +چالش +ستایش +نقشی +کهریز +منطقه‌های +خلبان +تنگستان +فروند +حج +خاتم +۱۳۴۱ +گردند +پایتون +گفته‌اند +دانسته‌اند +دانشکدهٔ +تکلیف +بازرگان +نتوانست +بیوگرافی +۱۵۰۰ +بنت +مری +نقص +فانتزی +پژوهشگر +دویچه +کنت +قاجاریه +دوام +حیدریه +جیمی +پویانمایی +قوای +می‌آورند +کامران +متنوع +استراتژی +شمارش +۱۹۰۴ +اعم +داراي +بهبهان +الدوله +تخلف +فراری +ایزد +رأس +انداخت +چرداول +پیش‌فرض +رهنمودهای +بافتا +شناسان +اردو +آبیاری +ترانه‌سرا +روحی +ادیب +فلات +ایست +سلیقه +ماجراهای +باکو +همارس +تراکتورسازی +گم +رابطهٔ +داشتند، +رپ +گز +بگذارد +۱۱۲ +مستندات +زمین‌های +سایت‌های +مبحث +مشکلاتی +بوکان +ابزارها +جبران +تقریبی +زیان +گلپایگان +خوشنویسان +۱۲۲ +بارز +مَا +بوک +اشتباهات +تانک +می‌شده +دهه‌های +واژه‌نامه +خشکی +ایی +اللَّهِ +عفونت +۱۲۳ +باده +نام‌تصویر +بیس +كردن +گچ +زدهٔ +طلای +معکوس +نبودند +رضایت +ثروت +انار +کشاورز +کوانتومی +اژدها +سوراخ +بیلبورد +شاهین‌دژ +بره +اهدا +زیرزمینی +تکراری +صربستان +مراقبت +تروریستی +۱۹۱۱ +متمایز +آملی +برساند +عن +ابهر +معتدل +گفتگوی +املش +می‌بینم +می‌آمد +۱۹۱۳ +ناشناس +وله +جایش +جنبش‌های +توليد +موزه‌های +نمائید +دهمین +برند +تاریخچهٔ +می‌شده‌است +پاسخی +پشتی +تشریح +نمی‌شوند +خویشاوندان +انگشتدان +دكتر +ژانر +فریاد +اخلال +تمشک +سعد +پارسا +۹۰۰ +نامدار +نظامیان +قدری +حمام‌های +مستوفی +گرما +گرا +یادگار +عاشورا +دفعه +بیانی +شنا +استعفا +رسانه‌ای +انحلال +بزرگداشت +فایرفاکس +بتوانید +مؤلف +حامیان +ناحیهٔ +مور +۱۹۱۰ +حیاتی +هرگاه +آنا +جاسوسی +منتج +جابجایی +تولیدات +هاى +قدردانی +۱۷۰ +راست۱ +لیلی +عملاً +میشد +کشورهایی +درجهٔ +حامل +ابوبکر +خصوصا +اختصار +مجاورت +پدیدآورنده +آراء +چپ۱ +گله +یکپارچه +عبارات +جمینای +جزیرهٔ +اسرار +خانواده‌های +بلوز +مونته‌نگرو +بیابان +به‌صورت +دارید؟ +نقطهٔ +ضرورت +وي +کارکرد +هوانوردی +محبت +پارک‌های +واژه‌ای +امامزاده‌های +هریک +کوچکترین +طاهر +حوالی +مطهری +کنگاور +شدهٔ +شبکه‌ها +شیوه‌های +تیراندازی +۱۱۸ +جست +آژانس +سایز +بدن۱ +تکذیب +نقدی +متناسب +دال +بابی +شانزده +هرکدام +ادعاهای +العاده +عنایت +مزدیسنا +انقراض +مقدونیه +۱۲۷ +ندیده +رأی‌گیری +دلو +هندسی +موبایل +تورم +رفتاری +پیامدهای +زید +زادروزها +حیدری +بتوانیم +فوری +علایم +نویسه +غم +خلال +اریل +کاشمر +بز +بردسیر +۱۹۱۵ +حتا +برخط +خرمشهر +همچین +نفری +سالگرد +متخصصان +شاهرخ +صحن +جنین +جشن‌های +یکشنبه +تمیز +ارامنه +چپ۲ +جلسات +مهمان +کجای +روال +۱۳۴۳ +پینک +سبک‌های +هان +بدن۲ +عمودی +افسران +شجریان +نوسنگی +الاسلام +مساجد +صاف +مروارید +جانور +آنهایی +راست۲ +اسکی +ناشناخته +اعتقادات +یم +انگور +ويرايش +گروههای +ترانهٔ +شد؟ +دقیقی +استادیوم +مختلف، +عتیق +توطئه +بالا، +مین +همگانی +تلفنی +می‌دانست +ود +ميان +تشکیلات +روده +مدیره +ونزوئلا +مخصوصاً +مشتمل +انتقادی +تفنگ +برایشان +طالقان +فرانسیس +بازارهای +پایین‌تر +کاروان +به‌جای +الیاف +خامنه +خصوصاً +ظهر +سکس +چهاردهم +ایزو +مسجدسلیمان +الکل +فلاندری +محمدیان +شکوه +کرده‌اید، +اسلامي +سم +کناره +لوازم +نمیدانم +پیامی +فارغ‌التحصیل +باس +کام +بنویسد +بازنشسته +نصر +کاشی +شکارچی +پست‌های +ویلیامز +دهکده +اندر +۱۵۴ +جهانگیر +ملکان +می‌توانست +عبارتی +مسئولان +هلال +مهندسان +غارهای +بیلی +۱۹۱۶ +بنگلادش +حملهٔ +توانستند +پارینه‌سنگی +پولی +خوشبختانه +نموده‌است +امینی +نه، +هما +مشورت +نامحدود +آندره +پلنگ +مخدر +مضمون +برمی +هم، +لاس +دهید، +ویکتوریا +موثق +داود +عذرخواهی +یاهو +رنگ‌های +۱۱۷ +تناوبی +نوشتید +لااقل +شتر +مرکزیت +امن +ترسیم +سیستم‌ها +اتومبیل +آفی +جون +خالق +حرارتی +رسوم +موریس +مارشال +یورو +بانو +اولين +منشورات +غیبت +نوشته‌اند +قدرتمند +شکم +هایش +انداز +رویکرد +علاقه‌مند +خانواده‌ای +دمشق +دربند +برو +آرشیو +۱۹۰۹ +رویش +استخر +آنالیز +گچساران +بکنم +مولا +متفرقه +رحمت +شاخ +۱۳۱۰ +اتفاقاً +اسمش +سهامی +دبلیو +بخشهای +سرتاسر +ویکی‌ها +خیالی +نکنند +تناسلی +م‍انفی +جديد +۱۳۲۴ +کار، +برندهٔ +پیچیدگی +گواهی +زرتشتیان +ناصری +همانجا +رغم +گفتهٔ +۱۱۳ +گرمسیری +طلوع +برترین +درآورد +به‌دست +برقی +سپاهیان +ویژگی‌ها +مر +۱۲۴ +چهاردانگه +جامعهٔ +تحقق +مجاری +می‌گفتند +فروپاشی +چشمه‌های +ساختاری +مسافرت +پیکان +نرم‌افزاری +جد +روشنی +معرفت +تله +می‌کنم، +محرک +مشتریان +بیانگر +سازمانهای +چیزهای +رقیب +فرعون +بیروت +منعکس +تابناک +مشرف +آورده‌است +نمی‌توانم +۱۱۹ +مولکول +نعمت +می‌رساند +فرمانداری +دستکاری +۱۳۳۹ +مت +اردبیلی +مسدود +بله، +رانندگی +۱۲۱ +سایپا +استعداد +پیامبران +داماد +واجب +نسخ +فاضل +عرفانی +بزرگ‌تر +حق‌تکثیر +شخصاً +دگرگونی +عكس +انبوه +آپولو +فنون +افلاطون +حمزه +میانجی‌گری +نظرسنجی +آنتونی +اکوادور +آن‌چه +قذافی +اسکن +خاتون +ناگهان +گونه‌ها +تونل +به‌ویژه +ناگهانی +بدهیم +دوشیزه +آباده +نمی‌توانند +شلوغ +ی، +۱۳۳۵ +خلع +فلوید +ابومسلم +بایت +اعطای +جاسک +پوند +پایداری +تیتر +واپسین +استالین +تعطیلات +آستین +مختلط +تابلو +خنده +نویسه‌های +ثمر +۲۰۰۰، +بازاریابی +حسابداری +تکلم +رنگرزی +نهبندان +۱۳۳۶ +نیلوفر +شرقی، +بداند +فسا +آلیکانته +دیلمی +اجتناب +نیر +سطح‌بالای +اينجا +می‌زنند +کیم +لغتنامه +عاشقانه +فتحعلی +اشیاء +تعمیر +فلانی +استیون +سازماندهی +ویرجینیا +راجر +بگویند +روزنامه‌نگاران +هندو +دیوانسالار +ایستاده +۱۳۳۷ +کرانه +کلسیم +هایدلبرگ +کرواسی +سرانه +الملک +سنگ‌های +ژنتیکی +نیکی +هجرت +مامور +خنک +نمایان +بهرامی +شبستر +واسط +آرایش +مبهم +بسی +بریتانیای +محدودهٔ +بحث‍ +گاما +ده‌ها +نواختن +فروشگاه +خمین +صنعاء، +کنفدراسیون +اموال +هنرپیشه +پارسیان +متوسطه +دامن +۱۲۶ +لک +شیشه‌ای +ابراهیم، +آمادگی +هو +زنجیره‌ای +۱۳۲۸ +بازیهای +سنقر +بدر +آورند +مرجعیت +آلت +اسدآباد +کارلوس +سودمند +نشانگر +رسید، +حوزه‌های +دیار +کنگو +میهن +کلانی +۱۲۹ +افسر +باکتری +معماران +۱۳۲ +سیدنی +کفش +ارادت +می‌خواهند +خر +۳۵۰ +بدترین +تاریخ، +فلسطینی +زاگرس +بیاورد +یانگ +شخصا +تشدید +آدمی +ماهی‌ها +هیچکدام +میناب +بوسنی +ایندیانا +دنباله‌دار +ملوان +روزنامه‌نگار +مؤثر +دستورات +رطوبت +تعامل +کلان +عباس‌آباد +کاملی +احادیث +مدرکی +پاکسازی +۱۳۷ +تفاوتی +ورزشکار +جنبه‌های +غالباً +بود؛ +چنگ +مهاجران +پله +تراز +آمد، +وا +ژ +کوثر +وادی +اتوبوس +کاظمی +خبرگان +موس +تکمیلی +لهستانی +درویش +منم +جعفرآباد +نیا +جاذبه +گیلانی +طلاق +تروریسم +به‌خاطر +آيا +گرفتار +اشعه +می‌پردازند +شخصیتی +آقایان +رفتم +جریمه +مهره +خاستگاه +میان‌ویکی‌ها +بالینی +یزدگرد +ببرد +دوش +چغازنبیل +۳۰۰۰ +فوقانی +۱۳۳۱ +گیلکی +خط‌به‌خط +کاترین +بختیار +کردید، +گردان +ادی +طاها +مدیترانه +ارس +حسن‌آباد +پوشاک +بابلسر +رساندن +کند؟ +بهش +وست +خوشامدگویی +مهار +میبد +فلسفهٔ +وند +آش +سیمین +خوراک +خوزه +ساختند +نياز +عروسی +میگردد +جلفا +بودیم +بکند +۱۳۸۸، +روحانیان +حماسه +پایتخت‌های +مبارزات +احمد، +ارث +محمّد +۱۳۳۳ +کوشک +سنگ‌ها +زشت +دنا +دستیار +گرمایی +ایشون +نامهٔ +تحمیل +گوشی +دوره‌ای +ققنوس +بدانند +شن +انداختن +هفدهم +غالبا +اسدالله +۱۳۴ +شدیدی +ناپذیر +۱۴۴ +گینه +سرمربی +نطنز +کیبورد +محفوظ +آیند +انفرادی +آن‌که +گمانم +توانسته +سال‌شهرشدن +علم‌جو +خرده +درگز +ایستگاه‌های +بکشید +پیش‌بینی +حالات +هرکس +بزودی +کایروس +اوستایی +صفات +مارکسیست +خشت +جنب +عذر +ونیز +آسانی +کریستین +صفویان +اسدی +۱۹۰۳ +تاخیر +خیانت +قوس +قطره +آثارش +سیل +اسکات +مشاغل +شم +بخارا +چاپی +مکتوب +دیدید +انتها +موزیکال +كاربر +منشأ +سمی +لَا +پهلوان +پوسته +درختی +مشابهی +کنیا +عاملی +۱۳۹ +گویید +۱۳۳ +تلاش‌های +اهمیتی +عازم +اسمی +پکن +تصوف +تکاب +حاکی +برت +کنيد +نوروزتان +ببیند +کبوتر +سفرنامه +۱۳۳۴ +تخلیه +آق +زنجیره +انتقادات +کوک +همان‌طور +غربی، +جنجال +فیزیولوژی +سانتی‌متر +بسط +زخم +۱۴۱ +ویکتور +آران +یك +التهاب +دسته‌بندی +جنگنده +ایفتا +ژاک +طاهری +فیض +بهتره +ادعایی +اسد +بودنش +پیک +مسأله +بانوان +بنفش +گشود +باغی +هیدوچ +جسمی +انگشتی +یوهان +لنز +چراکه +رهایی +نگرفته +مقصود +جوراب۱ +آنهم +قمی +سکته +کو +سره +زبانها +برج‌های +مکان‌ها +نشدن +چابهار +پاراگوئه +کتابها +طولانی‌ترین +اولویت +مبارز +استراحت +مشت +حرام +فرمود +نقلیه +کمر +پستان +سرچ +فعاليت +ارتقاء +شانس +خودی +فاتح +مطالب، +گوسفند +میگویند +غلام +وصف +دلم +اظهارات +انتگرال +سوسیالیست +گذارد +ماموران +بادام +چال +ساگه +ایسنا +معده +ریشتر +اعلان +تک‌نفره +بلو +مناطقی +شافعی +می‌گفت +می‌خواند +ثانی +هست؟ +منو +لوث‌شدن +جنایت +برخاست +بوده‌است، +نمی‌باشد +اشراف +نداد +مهربان +الهیات +همه‌ی +زمين +کینگ +رول +والتوزیع، +مدرسهٔ +ترافیک +اتهامات +وای +بهنام +شجاع +سیار +ترسناک +ذات +مختار +عموما +اینتر +فرزندش +داروشناسی +ریسک +۱۹۹ +نیجریه +مظفر +حشرات +میدانید +جبل +آریزونا +نارنجی +کتابخانه‌های +میدانم +آرم +بشمار +اعتباری +کره‌ای +عکس‌ها +پیکچرز +تخته +متمایل +رفاه +شهبازی +میخائیل +تطبیق +نظریه‌های +بلوغ +عزیزم +۱۳۹۱ +محاسباتی +سنجی +مکانیسم +سریعتر +آبشاری +کالاهای +اشک +خانی +سازگاری +مارچ +گرین +قرص +خوانندهٔ +صفی +نازک +داروها +۳، +۱۳۶ +هماهنگ‌کنندهٔ +لینکلن +بانوی +خودروی +پل‌های +۱۳۳۸ +دیوارهای +ورامین +۱۴۵ +اتخاذ +کمیت +دارم، +مذاکرات +حول +برگزید +کارشناس +نامعتبر +سفرهای +رومیان +ربات‌ها +غیراینصورت +انیمه +به‌وسیله +استعمال +صریح +سازه‌ها +رامهرمز +اندیس +رازقنــدی +تثبیت +۱۰، +تصوير +گویش‌های +کتک +طالب +حماس +۱۳۲۹ +علیرغم +۱۴۸ +حزبی +استونی +اوین +غروب +حریف +استراتژیک +شگفت +مرگش +جانسون +پانزدهم +موشک‌های +گن‌آباد +ارتقا +باطل +خورشیدی، +آلفرد +ساموئل +بحرانی +قندهار +كردم +ماکس +گی +میخواستم +بچه‌های +۱۳۲۵ +شرطی +گشایش +زندگي +دایی +یون +فرانس +تورات +گزارشی +۲۲۰ +فیلم، +دهلی +مسافران +سنگر +نخواهم +موش +ریشهٔ +سخنگوی +زنگ +نینتندو +دیوانه +بمباران +مسئولین +استودیویی +شدیدا +تیلور +۱۲۰۰ +قزوینی +لاست +مسلما +ورق +شهرزاد +لطفی +کلات +بارداری +دیواره +باشگاهی +شکستن +تریلر +ممتاز +پرانتز +یوتیوب +بیهوده +ابدی +نباشد، +کیوان +طرح‌های +بدم +کاریکاتور +بدتر +داش +می‌رسید +میانجی +بيش +اختریان +سربیشه +روشنایی +تبیان +بکشد +اراده +چربی +خرما +سلطانی +شيخ +مقا +مستخدم +وب‌گاه‌ها، +نشینی +نرگس +۱۷۵ +تویسرکان +خاطره +برکنار +غیرقانونی +ساواک +نگاره‌ای +سین +شناسنامه +بناها +‌ها، +غرق +شعرهای +مسلط +سرش +اه +برکت +جنگل‌های +سلطه +اقیانوسیه +علما +بنفشه +یال +هولوکاست +دادستان +حلی +اجسام +غواصی +احاطه +والا +بیماریهای +صدوق +ریو +دیویس +ناهید +دهها +نتوانستم +ایکس‌باکس +ول +منبع‌ها +تاریخی، +٫ +کثیر +لیتوانی +شده‌ +بپرسم +قربانیان +جانشینی +سیریلیک +بوستون +یونانیان +دوبار +فرضیه +امروز، +دیده‌ام +عزيز +۱۴۲ +میگیرد +شلوارک۱ +مِنَ +ارسطو +ومبلی +بخواند +۱۹۰ +صوفی +صدق +کارب +گذاشتند +هزینه‌های +فردریک +نوشته‌اید +آو +عمده‌ای +م‍ +هیچگونه +حسی +اللَّهُ +معدود +مارکس +سنگاپور +رایانش +عادل +ریگان +میرسد +الگوریتم‌های +ائتلاف +فریدون‌کنار +بازگا +نگرش +هرحال +بدانیم +کفایت +فین +۱۳۲۷ +باورهای +بازگیر +لردگان +چرا؟ +تعویض +سلجوقی +جستار +نخواهند +می‌نمایند +دهستان‌ها +فرمانروای +خودتون +منتقدین +کلاردشت +اره +لزومی +مرتفع +ویر +سندرم +نیاید +آجر +دانشکده‌های +نمین +مق +تن‍ +اینچ +فوتسال +ساکنین +‍ه‍ +فرانسه، +صفحاتی +۱۹۰۲ +طالقانی +جعبهٔ +غارت +بزرگسالان +لین +۱۶۵ +قیاس +افغانی +نگذاشته‌اید +ساید +نادری +امامان +سنا +سرگذشت +رایش +توجیهتان +بروند +سمفونی +آهنگ‌ها +توس +تم +پنسیلوانیا +خرچنگ +مغان +سجاد +پایینی +تحریر +لوث +شانه +طوفان +اصولاً +کبودرآهنگ +تسمیه +عامیانه +بیشینه +فضاپیمای +بودایی +۱۸۹۰ +اقلیم +مثالی +جشنواره‌های +برایان +میرود +پین +آم +سرگرمی +مزایای +ریال +رسماً +ناحیه‌های +تازه‌ای +می‌دهیم +هارد +مقال +فراهان +دلیلش +میلیمتر +۱۸۰۰ +ماهنشان +سالار +جت +مردگان +فقیر +۱۵۵ +راستا +میکنیم +جوری +شلوارک۲ +پژوهشگاه +نیستند، +۱۴۶ +اینشتین +یخچال +روزمره +ارم +سنین +تحسین +سکه‌های +۱۳۱ +فحاشی +پاپ‌های +عینی +رسانده +رز +بودم، +ارزشی +ستان +باراک +اصلي +الکتریک +نامه‌های +عطار +علمي +بخشید +السلطنه +يعني +غلبه +مستقیماً +منش +رستاق +افراطی +بگیرم +سيد +۱۴۷ +ندارند، +الَّذِينَ +نمونهٔ +کریستال +قایق +نوادگان +سالیانه +می‌پذیرد +احترامات +شیری +سیاهکل +سرب +نصرالله +مانه +گیم +ببر +آستان +زیستگاه +ای، +داده‌ام +لوئی +شریعت +آموز +رتبهٔ +کمک‌های +نقدها +حلقه‌ها +ارتقای +هال +انسانها +پشتو +امیرحسین +سین‌آباد +رشید +۱۴۳ +شیرینی +مذاکره +تعدیل +کارمند +اعضاء +روانه +بنر +معروفترین +خیابان‌های +مشاوره +اکثرا +افت +کنگان +بگذارند +دامنه‌های +رحم +بیدار +تیپ +تنفس +افغانستان، +میشیگان +استعمار +فرخ +گذرگاه +توالی +تایم +جمله‌ای +ولادیمیر +دستوری +تساوی +ساختارهای +جانوری +قسم +۱۳۱۶ +هفده +یقین +صوفیان +می‌نویسند +رومرکز +بک +انگشته +مولف +نگفتم +یورش +ثبات +بیایند +بپرهیزید +وبا +اس‌جی‌اچ +جن +ورزش‌های +لامرد +سپیدان +کبک +عزت +افشین +کامرون +فیلم‌شناسی +پاول +نکنیم +درگیری‌های +رخداد +کیا +عرف +شازند +یکصد +استهبان +می‌گیرد، +نرسیده +ویژهٔ +ابتلا +اینطوری +گارد +بزن +مدتها +وعده +شرف +پيدا +نیدرزاکسن +زواری‌جان +اسدخانی +هندواروپایی +تصویرگر +مختص +استادی +هیپ +امشب +احیای +بنو +امامت +خونریزی +سیگار +کاسه +غرض +معتقدم +ساختم +صفح +روایتی +نمادهای +متوالی +خدایی +نمود، +عجم +آبهای +آمده‌اند +نموده‌اید +لاریجانی +شیوع +زمينه +الا +بیا +آزمایشگاهی +آنتن +قرآنی +بیستون +فاجعه +۱۵۸ +ریه +انعکاس +تقلب +هجدهم +طبرستان +تناقض +مدت‌ها +علمی، +تصنیف +فروغ +دایرةالمعارف +آلمریا +تاسیسات +گونهٔ +هیچکس +ایدز +آوا +۱۴۹ +مديريت +بیاد +پایگاه‌های +زیرصفحه‌های +مقاوم +گمشده +نشدید +نوزاد +سیف +دیفرانسیل +موافقان +بانه +فونت +صفا +واتیکان +اصالت +کتابخانهٔ +یگانه +کیت +ترجیحات +کنوانسیون +نانو +۱۵۳ +آنزیم +كردند +تیمی +۱۸۵ +هستید، +حوض +نویسنده، +ورد +حسنی +پديا +بویین +مادها +ناوگان +بنگاه +اردلان +صومعه +تورنتو +کارولینای +۵۰۰۰ +اشکالات +مسائلی +انداخته +نماند +دستمزد +بخواهم +سرقت +میدانی +ریتم +خوبیدگی +پوستی +اندی +الماس +بزنم +مقدونی +هسن +گروه‌ها +بروجن +تگ +منشی +ملکی +تبعیض +ببین +افق +خشن +کورین +دوی +قوام +ایلینوی +بچه‌ها +تکاملی +دخترش +برانگیز +اصطلاحی +مل +یکان +داراست +عرب‌ها +ناموفق +کبد +کوفی +رودها +پشته +رسالت +مرتکب +معروف‌ترین +نشوند +نبودم +بنیانگذاری +لیبرال +فرید +حوضه +ربع +نوح +سیاهه +تای +خستگی +پدری +برنامه‌ها +فرستادن +بیطرفی +نواب +نزول +استیشن +رادار +پخش‌کننده +سازند +عضلات +سعیدی +کوین +بنویسند +برم +بیایید +حجازی +شده؟ +تالیفات +حسینعلی +نیست؛ +مزاحم +فروشی +آموزان +میکرد +۲۴۰ +بحث، +وارنر +کوری +واکنش‌های +فستیوال +قارچ +لغت‌نامه +تاجیک +شرکتهای +هروی +ویژگیهای +عکسهای +چارلی +باشيد +داشتیم +بومیان +باقیمانده +یافت، +اشاره‌ای +فصلی +عبدی +بزرگوار +بیتی +مُعجَم +نازل +امپراتوران +مهمتر +کانی‌ها +۱۸۹۶ +محمدباقر +شایع +ادریس +که‌ +دهندگان +اعلامیه +به‌نظر +داروی +لیک +اتوماتیک +مي‌شود +فروغی +برآورده +بلا +آدولف +قشقایی +تنفسی +اردوگاه +زنجانی +تنه +گزیده +مریوان +پورنو +کامبوج +تل‌های +رمزنگاری +دامپزشکی +شاهنشاه +قرقیزستان +ارابه‌ران +نمودم +ضرر +بازنگری +دگرگون +بررسي +شده‌بود +ناپدید +متاسفم +نسخه‌ای +اشنویه +پیاپی +عبدالعزیز +۱۶۸ +اسباب +نسبیت +کعبه +مردم، +ذوب‌آهن +آنچنان +ادرار +رنسانس +سوسیال +دهخدا، +تختی +فاطمی +ماشین‌های +پاسکال +مینا +تابعی +سایتی +توانیم +ترين +توران +ادارهٔ +فهرست‌ها +خوشی +معینی +یادآور +مخالفین +دود +مدام +انی +تقاطع +پتاسیم +نساجی +ارد +اندیمشک +داده، +مخالفتی +دونفره +اندیشه‌های +علیزاده +آجری +برسیم +اقدامی +فقهی +اشکان +همبستگی +فرادیرینه‌سنگی +گناوه +کوفه +۱۸۹۹ +اینصورت +عبدالرحمن +لبه +بی‌پایان +میدهند +منشا +مرحلهٔ +بیطرف +کردید؟ +مسخره +مشخصه +عضلانی +اسارت +عنوانی +۱۵۲ +ندارم، +برچسب‌ها +اچ‌آی‌پی +منصوری +۲۱۰ +بینم +مجنون +تعاریف +تعهد +اقتباس +جلیل +می‌کنید؟ +رزن +مسئلهٔ +فرستنده +گان +قاب +کمونیسم +تناسب +ندای +توحید +هواشناسی +کرده‌اند، +منتها +روز، +شوال +لیزر +پس‌از +دزدان +دارد؛ +جنگ‌افزار +جایزه‌های +واحدی +تیموریان +ذكر +کنده +ترش +می‌خوانند +ریش +تمایز +پیشبرد +زندگانی +دلتا +پیش‌از +نقده +ایرلندی +هنرستان +قبال +فرصتی +دودویی +عليه +زیباترین +شاعری +سرما +ایلی‌نوی +شهبانو +پنالتی +بهاری +افتد +فیروزکوه +فایده +۱۶۳ +بروس +نیسان +نکردند +نمیتوان +۱۶۲ +روباه +سقراط +کشته‌شدگان +اورانیوم +عملا +طراحان +ماهیچه +سرم +اوهایو +علاقمند +نویسد +الجزیره +گذشته، +مزارع +گزینش +جنگهای +اطلاعی +نوشته‌ها +پارلمانی +۱۱، +جنابعالی +اسفندیار +امیدوار +ک‌گ +گازهای +کبود +زمین، +تلگراف +لئونیداس +گرمای +کتابخانه‌ها +آشوری +طعم +راد +زنانه +عربی، +جادو +حمیدرضا +جنگ، +جابجا +ماکیان +بیابید +شکاف +گلزار +متفقین +متاخر +سایتهای +بایگانی‌ها +بهره‌برداری +جنایی +کارون +شهدای +میامی +پدیده‌های +هستم، +برکلی +نایین +ببینند +استانداری +۱۶۱ +پسری +شوالیه +کت +شاخه‌ای +مقاطع +آنوقت +اسکو +۱۸۹۲ +نده +رسانید +۲۳۰ +تاسف +هايي +پلدختر +تاجیکی +جاجرم +وضع‌کننده +استر +همنشین +زحمتی +کانادایی +تبلیغات، +زهک +دولت‌های +ترمودینامیک +سوری +خلفای +درآن +فراگیری +ختنه +امیرآباد +تروث +بوم +زاد +خنج +بروم +سومالی +جیم +دیجیتالی +عفو +سوشی +اصفهان، +بلاندی +کوچک‌تر +گمنام +سکوی +نزاع +احتیاط +گردید، +بزنند +علنی +ویلا +۱۳۲۶ +الهه +هدر +ظلم +ناو +می‌کردند، +الحکمة، +یاقوت +حتي +شرکت‌ها +تعلیق +خواستند +کاروان‌سرا +نکتهٔ +رشته‌ای +باهم +بپردازند +درجات +وجودی +بودا +نیوتن +منطبق +نصرت +ال‌جی +سومی +فلش +۱۳۸۵جمعیت +فریم +دوما +ساقه +اسماعیلی +دینامیک +المقحفی، +المُدُن +فیلم‌هایی +فیزیکدان +محضر +آخوند +فراهانی +صید +بسا +الیَمَنِیَة +بنایی +۱۷۳ +می‌گوییم +درآمده +مورخان +یونیکس +جاها +وام +کوتوله +۱۷۶ +ژرفای +موجودی +مرادی +بدنیا +پمپ +پرستاری +می‌شوید +مناره +انقلاب، +برجستهٔ +جذاب +نوشتارها +نمیشه +مایک +امیری +چناران +ــ +گردو +تفویض +دخیل +۱۵۹ +بنیادین +بدیع +سالیان +مواضع +وَالقَبائِل +۱۶۹ +می‌بیند +درگذشتهٔ +داشته، +قنطورس +۱۸۹۸ +تصمیم‌گیری +مشمول +رودان +فراگیر +آمده، +نفهمیدم +۱۸۸۹ +شده‌اید +نفی +افسردگی +می‌دانستند +آلات +قوت +دانه‌های +محمدحسن +عزيزی +جامی +نجم +طرحی +گاندی +جنوبی، +بصره +اروگوئه +شرکت‌ها، +پورت +خجسته +زمانیکه +ریشه‌های +فمینیسم +گاردین +بایست +وار +دیوان‌سالار +فوتبالیست +۱۶۷ +آلمان، +شعله +آناتولی +على +شمالی، +سیمون +ظروف +رستوران +دایر +می‌گذارند +تفاهم +آناتومی +گذراندن +شكل +مرگ‌ها +آهنگسازی +لیتر +دزدی +فرموده +معصوم +اطاعت +تارنمای +فارس، +پلان +هانس +فریدریش +ملی، +روحانیت +اوّل +نتيجه +وادار +صورت، +۱۳۰۴ +ترتیبی +مبارکه +بنیان‌گذار +۱۷۹ +ژوزف +اردستان +افزودم +مطبوعاتی +ارز +جنجالی +نوازندگی +سوزان +دارن +افتادن +هایشان +تحقیقی +سهند +سپاسگذارم +فیزیوتراپی +محافظ +ماشینی +ربر +یدالله +میمون +سیاستهای +نگارهٔ +چه؟ +صراحت +رسته +تجویز +توفیق +مغولستان +کین +وال +ساکورا +پیشروی +متوفی +تازی +دیلم +پل‌دختر +می‌خواست +صدیق +نمی‌بینم +ایلات +درحالی +غلات +نوه +هاله +سیستمهای +کتیبه‌های +سیال +منبر +بیک +۱۳۱۴ +۱۳۱۸ +حسين +۱۷۱ +درشت +سوق +برنامه‌ای +گهواره +دست‌آوردهای +تعبیه +رادیوی +ساسان +درامز +۱۲۹۹ +تجسمی +سیمان +گنجی +کشش +اسلوونی +ویلسون +داماش +إِنَّ +کارتوگرافی +کاشت +دستان +لید +نوازندهٔ +نمی‌شد +قران +ایدئولوژی +کامپکت +ناغان +قرائت +کاراکتر +خانه‌ها +شفاهی +فله‌ای +شهرسازی +اعتصاب +۱۸۱ +ویدیو +شايد +ویرایشگر +پردازد +داده‌اید +حاد +اجتهاد +مرطوب +کلماتی +مهریز +حلال +بیافزایید، +۱۵۷ +همجنس‌گرایان +لینکی +تطابق +باورند +دالاس +إِلَّا +اصولی +کپی‌رایت +الفبا +کیهانی +تاب +شرعی +محتوی +هانری +می‌دهند، +یوگسلاوی +بگذارم +تداوم +گریز +نشده‌اند +شناخته‌شده +انعطاف +اندک، +دعوا +کری +تبیین +احساسی +ساعات +معاصر، +پیشوند +طبع +میاندوآب +اخترفیزیک +مطمئنا +پرسید +انگل +برکناری +رولینگ +حفاری +زیارتگاه +منتسب +پیام‌های +گسسته +طريق +باخ +۱۳۲۳ +کلیساهای +معصومه +شهروز +متناوب +۱۸۹۵ +پن +ابراهيم +۱۳۱۳ +بطوریکه +رابین +آموخته +میدان‌های +تاریخ‌نگاران +بکر +میش +پخته +قلمداد +رویا +باشید، +سیستانی +قومیت +جرمی +لوس +آفرین +تلف +خوارزمی +محتوایی +سول +دبط +جُستارهای +می‌نمود +روزنامه‌ها +یت +دگر +بانکی +سدان +متغیرهای +یابند +بکارگیری +انتاریو +کوسه +۱۶۴ +بلخی +بیم +خلخال +حائری +۱۸۹۳ +آورده‌اند +نقطه‌ای +علمجو +استیل +سلولهای +گوگرد +میتوانند +گوارش +سبزی +۱۶۰۰ +جوراب۲ +زیرین +ميشود +پنبه +آورد، +حرفهای +لنگرود +فریمان +سلاح‌های +میانگین‌جریان +غبار +مردانه +مؤسسهٔ +اسراییل +تک‌نواز +۱۶۶ +لکی +خبرنگاران +پالایشگاه +مصلحت +۱۷۷ +مجروح +پرستش +دوگانه +مدفون +ولیعهد +سرزمینی +آق‌قلا +اساسا +بهر +ملي +كنار +روستاي +کلاس‌های +سفره +نرمال +وری +کیف +۱۸۸۰ +۱۹۸ +زدید +زراعت +رهنمودها +توضيح +۱۷۲ +۱۹۲ +پدیدار +وایت +بمانند +لرد +دستم +ایسلند +لیقوان +نیافتم +باتشکر +تئودور +عبادت +تبديل +نکردید +مسلحانه +دیزنی +رانش +فرهنگ‌های +مخاطبان +دول +کتابت +سلیم +ایرانی‌تبار +غلظت +شونده +۱۲، +اوراق +سامانی +اقتصادی، +۲۵۰۰ +شخصیت‌ها +فحش +سربازی +هشداردهنده +ندرت +۳۲۰ +می‌شه +۱۸۹۷ +فروهر +صلی +سیوند +انجمن‌های +بعلاوه +ترشح +فرج +جاي +بخیر +محراب +کارتان +هجده +قریه +ربیع‌الاول +ضخامت +بارندگی +بح +نسیم +زهره +جادویی +تالاب +جنون +بروی +۱۳، +فیلد +کریسمس +میزبانی +می‌کنید، +آپلود +برگزیدگان +یش +خانواده‌اش +کریستوفر +بیننده +توکلی +می‌سازند +لنگ +تداخل +مقدمات +۱۸۹۴ +الوند +مع +گناباد +مزدا +رکن +عیلام +ترقی +منکر +معامله +اینچنین +کول +سازمان‌ها +مأموریت +موعود +دولت‌آباد +بلبل +طولی +می‌رسند +اجاق‌کندی +ديگري +ندارد؟ +براین +مصور +اعتقادی +فرخزاد +درباره‌ی +خداآفرین +گفتاری +خوانی +پارامترهای +تهاجم +آیوی +توضیحاتی +بشرویه +۹۷۸ +کیست +نداشت، +شهروندی +برخي +۱۵۶ +سمرقند +نوا +كمك +لامپ +عماد +رام +اينکه +ضمیمه +بنابراین، +تصویربرداری +سیبری +یوفا +کلر +گوجه +حیف +سواری +۱۳۱۲ +طارم +۲۶۰ +اباد +عنوان‌های +مركز +مقوله +گوستاو +مرعشی +بحر +تون +انصار +جداسازی +تصفیه +سازندگان +ببنید +محافل +نقره‌ای +تیرماه +پیاز +سرسبز +انه +چشمان +تایباد +اشیا +طرد +گوهر +نکن +هرزگوین +اقلید +خاص، +ثالث +علی‌رضا +آنگونه +مستمر +عضوی +هامبورگ +پورتال +تویوتا +رامیان +هخامنش +اردل +قاطع +گنجینه +روشنفکران +تصادف +۱۹۷ +جزیی +مؤسس +روبروی +آلاسکا +خوشه‌مهر +آرد +صالحی +سونامی +کشیش +پروس +انحصاری +کاسته +دوستانش +گاوران +دلالت +۱۸۴ +اصحاب +جزیره‌ها +مهدوی +آبیک +افزايش +مزیت +جوابی +صغیر +منحنی +رمین +سانتیگراد +دبیرکل +غریب‌دوست +بنزین +اپیزود +استانهای +بهاءالله +سپید +کمونیستی +سوگند +شهباز +اکتشاف +استحکام +مفاد +بسازد +اسکناس +۱۴۰۰ +مبدأ +بخورد +مناظر +زا +پرستی +تمبکا +محرمانه +سکنه +زیتون +رومانیایی +جسارت +عمومی، +دات +آهنی +بینید +مخابراتی +نظرش +مولداوی +العظمی +ولف +ممکنه +راننده +اولاً +وَمَا +وسیله‌ای +موی +بادلو +چرب +مسافت +مکس +۱۷۸ +پودر +عوام +که، +پنجم، +گرگوری +میسر +مفصلی +استبداد +حیدرآباد +آلیس +فیروزه +ریخت +اینان +کروی +وقف +شعارهای +۱۹۶ +سملقان +فروخته +۱۷۴ +نبوده‌است +دیکتاتوری +میدهم +ظریف +معتبرترین +سیاسر +ایرادات +اجماعی +۱۹۳ +منحل +زاید +میخواهم +صاحبان +مهلت +می‌پرداخت +ماهه +جری +بازرس +وَلَا +گلشن +برهنه +نوشته‌ام +می‌شود؟ +صخره +عمو +ابد +بیداری +۱۸۸۸ +۲۷۰ +بعلت +پنیر +حاتمی +خانقاه +رس +شکسپیر +معذرت +پايان +ساختگی +آموختن +فقدان +پاسخگویی +زانو +كوه +لزوما +قمر +شهریاری +بيان +واین +صورتیکه +بدنبال +پاره‌ای +ارمغان +می‌شود؛ +شغلی +دیگ +عنبرآباد +امریکایی +پیشرو +تجربیات +علوم، +پیری‌کندی +ازجمله +به‌نام +صومای +۳۳۰ +۲۶، +اسطوره‌های +منفجره +دستتان +رشته‌کوه +۱۹۵ +برن +بلده +شیعی +رحیمی +رجایی +کجور +۱۵، +تاون +آموزگار +آستارا +هیل +ترانه‌ها +یوری +کلاله +محو +خوانندگی +زار +عیب +افسانه‌های +پخت +نامبرده +پنجشنبه +سور +نروژی +تکنیک‌های +دریاچه‌های +مالدیو +سوسن +کیسه +کاوش +دابودشت +کردن، +زندگان +مقدمه‌ای +موزهٔ +۱۸۸ +برپایی +داگلاس +فضل‌الله +زینب +اللَّهَ +صحرایی +کرت +اذیت +نمی‌رسد +آتشفشان +۱۳۲۱ +بلاروس +انگ +ارگان +بسامد +نشوید +بزرگای +کلارک +۲۱، +بشدت +نقوش +خوشنویس +الفبایی +نخ +رفیق +ناراحتی +رسی +بخواهند +طرفداری +دردسر +۴۵۰ +۱۸۳ +ایرباس +پرت +فرآیندهای +گردشگران +مخرب +میگم +کارتون +نوژن +سفری +صندلی +می‌کرده +نزنید +ج۱ +میخواهید +گنگ +می‌ریزد +پشتکوه +ویکی‌پدیاست +دلاری +ویکیفا +خيلي +بازگشایی +چشمگیری +نیتروژن +بافی +لانه +بدید +آشتیانی +باشد؛ +محققین +۲۴، +یوتا +طرفه +توسعهٔ +کشتی‌های +۲۰۶ +جاستین +شوشتری +اسمیت‌سونیان +طوطی +عباسیان +رده‌ای +زرند +می‌رود، +ابتکار +دهلران +بستان +برجای +۳۸۰ +رمانتیک +ترجمه‌های +کاربرها +بندری +پرداختن +منهتن +پاتریک +طناب +چهارم، +نتواند +بور +دانسته‌های +روحیه +میلاد، +برزنجیر +مرجان +دهند، +شهرستان‌ها +سپرد +داران +استوارت +دوچرخه +طراحي +۱۱۰۰ +خانه‌ای +نوآوری +نامنظم +کامپیوترهای +دیوانسالاری +وفادار +هرودوت +امسال +استثنا +فرانکفورت +مجالس +خدمتتان +کتابداری +لاین +پوران +آنالوگ +برادوست +۲۰۸ +شادباش +می‌شناسند +بولکیمده +می‌نویسم +چالدران +کهنوج +تطبیقی +۱۶، +دیدگاهی +منحرف +شنوایی +تیز +تیغ +موشکی +پرشیانا +امیل +ایزدان +سه‌گانه +پنجه +۱۸۹۱ +۱۳۲۲ +دين +قبله +جهنم +خدماتی +ببرند +مأمور +نیستیم +کلمه‌ای +اعتیاد +فرانکلین +معجزه +ذهنم +بازماندگان +مصوبه +کلینتون +برسند +معاهده +نمیکنم +چندگانه +شهرستانی +لاک +موضوعاتی +خوسف +اسک +خروس +لتونی +وات +کرد؛ +رودکی +خدمتم +تاری +مجلسی +فهمید +هفتگی +کروز +برگرداننده +قیصر +معروفی +فكر +نو، +فضانورد +فتح‌آباد +هورمون +الفاظ +آمازون +بیاوریم +دستهٔ +می‌کردید +بینایی +پافشاری +بردم +دیپلماتیک +سنگینی +ض +نمره +غیرآزاد +فریب +پذیرد +حیطه +اصلی، +تربیتی +محال +ارجمند +می‌یابند +فلج +اربر +اینجا، +آوای +دودانگه +چاه‌بهار +همزه +۲۳۸ +تمبر +انوشیروان +متن‌های +پشتوانه +عجب‌شیر +قسمت‌ها +آشوب +بدرود +نظرشان +ه‌های +روزتان +استفان +گیتاریست +نشده، +دینار +چاره +تیموری +زهی +مغولی +۲۵۶ +هیوستون +الموت +۱۸۷۹ +راگبی +لوکزامبورگ +حیث +عاج +سخت‌افزار +رمانی +نگهبانی +پتروشیمی +چادر +صلیبی +کنکور +کانسار +بلوچ +زاهدی +هستید؟ +دوبله +طیفی +نشریه‌های +زنبور +حزب‌الله +اخوان +اجزاء +ژنو +دعای +مزمن +سخنی +نهایتاً +اندرو +میشوم +۱۸، +دارمشترانگ +می‌دارند +سه‌شنبه +حفره +زرندیه +ذخایر +۱۳۱۹ +زنجیر +سبکی +قیمتی +جنیفر +۲۰، +تعمید +آبگرم +حکمرانی +پلاستیک +بی‌نزاکتی +تماشاگر +لایحه +بازه +تحکیم +موضعی +جویی +محافظة +شاه، +ما، +۳۰، +آمبرلا +کلرادو +هیجانی +مجتهد +گیاه‌شناسی +اضطراب +جنگ‌افزارهای +۱۹، +ادوار +مسیری +چمران +پایه‌های +گیتاشناسی، +نمی‌کنید +گیل +متین +آدلر +۱۷، +بعدش +باکس +یاس +حکمیت +کیلوبایت +بریده +هموار +معقول +کروم +۱۸۸۶ +غزنوی +نوش +بازنشستگی +گوینده +یک‌نمونه +هنر، +میاد +عظمت +جهش +جانبداری +شبكه +آسا +استاندار +۲۰۹ +فرانسیسکو +بریتنی +محدودیت‌های +بشکه +بنگرید +تاثیرات +آسفالت +گیج +کاروان‌سراهای +فراموشی +گلدار +ترتیب، +يافت +همینجا +بدخشان +۲۵، +تمدید +زيادي +هستش +رضا۱۶۱۵ +بودی +مهرماه +اسکندریه +لزوماً +سیستمی +هارون +نگفته +می‌دانیم +سایوز +آن‌را +نوزده +بمبئی +فان +میدانند +۱۸۷ +دانستند +اجاره +فورت +مراقب +نفرت +نوی +۲۰۴ +تدریجی +تهی +نورآباد +گزاره +کلامی +نتیجه‌ای +پانک +هاكل +عفونی +بسر +پیشگامان +بلاغ +زئوس +بريفين +گزارش‌های +نمایندهٔ +سیالات +۱۸۲ +فارسان +جلدی +فلک +تحقیر +فهمیدم +ناتو +سایرین +شناور +انستیتو +نیکو +مارکسیسم +تبعیت +تفریح +زبان، +گلوگاه +بقیهٔ +کمپین +احراز +بودن، +محکومیت +کماکان +بستری +تروریست +سرواژهٔ +دانمارکی +آمستردام +همی +داوید +کافیست +دنی +رون +۶۰۰۰ +لابد +کانتری +سس +کسری +می‌فرمایید +سیاستمدار +حریم +معنویت +عسکری +بخشیدن +محصور +مدافعان +گرایش‌های +واگن +حجر +سرداران +مشهود +یافتم +تنسی +نهر +دارالفنون +نمايش +بسياري +سابقهٔ +یتیم +توپولوژی +۱۴، +نگارشی +جمعيت +تنبیه +کیو +سقط +شریفی +کما +میکروبیولوژی +دیابت +تاتنهام +منقرض +تاتی +محمددین +انگليسي +فارسی‌سازی +زمینهای +شهدا +۰۸، +متکی +کوه‌ها +دزد +کنایه +مشایخ +ارزان +ماسه +هرمان +تنظیمات +اونجا +خار +هیلاری +چنار +خزانه +شکاری +عجایب +رنو +قراردادن +جابر +سروستان +مستطیل +مجموعه‌ها +بهمیی +یکسال +سرخرگ +نادرشاه +لیاقت +دوستار +وارده +کاستیا +لرزه +اى +بجا +نم +مغولان +امارت +کشاورزان +طبی +کجاست؟ +نبح +نمایم +للطباعة +بکنند +داستان‌ها +آمیخته +تاريخي +اندازه‌ای +پیکار +مستعمره +کوهپایه +تصدیق +۱۳۱۵ +فیلترینگ +۰۹، +آدینه +توبه +بصری +بکنیم +هوتک +فیلم‌نامه +پشتون +زمره +حبیبی +اسکندری +نیایش +هائی +رقابت‌های +داوطلب +ازش +بنظرم +دلیجان +رضی +مصاحب +پرون +بازگو +آگهی +قولی +سیسیل +انگلیسی‌ها +مکاتب +حبیب‌الله +سانسکریت +توکل‌آباد +نموده‌اند +حیوانی +پروژه‌ها +گیتی +فالتز +سنگسار +بخت +میلانی +مارکوس +نید +شدیم +۲۲۴ +مش +فصول +کتابش +می‌خواهیم +مشی +آنی +مادهٔ +میکردند +یکا +طلبان +عهدنامه +الملل +ارکان +کاربریتان +جلال‌الدین +ایرونی +یونس +آبراهام +فرشتگان +فارسی‌زبانان +۲۰۳ +۳۵، +ناتمام +موظف +ایت +می‌زنم +ییلاق +منی +كم +گریه +بسازیم +سیبک +انجا +موفق‌ترین +۱۳۰۷ +ثروتمند +گریخت +زمان‌دار +تروا +ژرمنی +برنارد +تشكر +ژنریک +راهبردی +گره‌های +پارسی‌گوی +بندهای +مبادله +اسفندیاری +سرتیپ +خوارزم +کلاغ +ياد +ايراني +نجف‌آباد +سولفات +كامل +ناظری +شهرستانهای +أَنْ +میگ +پادگان +مرتضوی +زياد +کلود +مقاصد +بهارستان +دیکتاتور +باستان، +۳۱، +اسکای +الکلی +میباشند +پارتی +بیاورند +لایه‌های +پرتقال +آمیزی +۴۰، +۱۸۶ +رستاخیز +خرگوش +فیبر +لیبرالیسم +مخترع +ۗ +تعمیم +برمی‌گردد +تل‌آویو +خورش +مولد +ستم +باغات +نژادهای +ضربات +آنست +ارواح +جوار +اپرای +تحتانی +آنتوان +زحمتش +۱۸۸۲ +بازگشتی +رفت، +۱۸۹ +هوگو +گیلاس +۲۰۵ +دستاوردهای +قضائیه +۴۰۰۰ +مستقلی +رعنا +بخوان +۵۶، +سوزی +تلاشی +هرکسی +میلی‌متر +هفته‌نامه +برومند +کباب +سرمایه‌گذاری +پلاتین +دنیس +وگاس +قرآن، +نصرت‌آباد +۲۲۵ +۱۹۱ +بافق +ژاله +آبریز +صدد +املاک +مقاله‌ +بوانات +پژو +زمان‌ها +کامیاران +پگاه +۲۰۲ +حرف‌های +ترغیب +حک +مسطح +دی‌وی‌دی +جانبه +سفیران +غدد +هستند؟ +مدرسه‌های +۵۲، +منبع‌دار +چاله +نائین +مدير +عکاسان +آب‌خورده +فیات +خبرنامه +مشهدی +استرالیایی +سیامک +بگیر +شایان +درسته +نامند +ویرایشهای +گل‌ها +مایا +گروه، +آتشفشانی +کرده‌است، +نیمهٔ +آزادشهر +رانده +علاقه‌ای +ثریا +متشکر +ولت +فرزانه +صورت‌های +دانشگاههای +وز +ویدئوی +جنازه +برتون +جلوه‌های +تغییرمسیرهای +بیانیه‌ای +دون +نبوی +یک‌بار +رک +حزب‌های +مدارهای +میگویم +كنيم +معلق +تماشاگران +نش +نصیر +۱۹۴ +رضاخان +گردد، +کنسول‌های +قسمتهای +شورشیان +دقیق‌تر +مداخله +علاءالدین +استنباط +مصرفی +باردار +اهورامزدا +ادبيات +باهنر +مقرر +عزاداری +كلمه +خونین +محدودی +نمی‌دارد +ذوق +پرسش‌های +بریم +قشر +۳۸، +صالح‌آباد +محسنی +تخلص +شکل‌های +شوی +رنگ‌ها +توربین +مگابایت +فسفات +واجد +اهانت +محفل +برحسب +گیگا +گيرد +۱۸۷۰ +صنفی +تن‌تن +برگردانده +دایناسور +لای +می‌بینیم +۰۴، +فرمائید +سیارات +۵۱، +تص +سرودهای +معترض +ممكن +متا +می‌شویم +ثلاث +گفته‌های +بی‌طرفانه +هاپ +نهان +ادارات +عجیبی +جنایات +دستورالعمل +پارا +نهادند +ام، +فتنه +فواصل +۱۸۵۰ +توریستی +مرمر +دیتابیس +۴۲، +کلیات +۱۸۸۳ +لنین +بلكه +کاتوزیان +میسیسیپی +معاویه +یوونتوس +کشاورزی، +هوافضا +كوخرد +فاریاب +محيط +نکنید، +میترا +رنگین +آلپ +آلومینیوم +ملودی +سیاستمداران +گمر +اسکان +مختصری +قشون +جوادی +رباتی +۲۱۱ +جایز +۲۷، +محمودی +كاربران +یافته‌اند +بگذریم +محوری +زمان‌های +۲۲، +انصراف +میلا +ساير +۲۱۴ +تصریح +۳۶، +۲۸، +آلباسته +وظیفهٔ +آذرشهر +خدمه +بارانی +فیزیک‌دانان +۱۸۸۴ +تماشای +۱۳۱۱ +نويسنده +علامرودشت +افزاری +گلشیری +عملیات‌های +داس +ناخواسته +هوتن +واسه +ثانیا +لینه +سنج +اروپا، +ایلیا +بازمانده +بشریت +شناسی، +۱۷۰۰ +کالیفرنیا، +نکرده‌ام +سیلیکات +آزاده +کامنت +یونیکد +آمدم +احضار +توده‌ای +فرایندهای +بیماری‌ها +آخه +تبلور +۰۷، +۲۰۷ +مونوبوک +تصمیمات +اختراعات +جشنوارهٔ +مشاهدات +ریزشگاه‌ها +۲۹، +فیلادلفیا +یزید +سکولار +خشایارشا +سنتور +محافظه +کاپ +نادرستی +علی، +محیط‌های +منفرد +اهتمام +القاعده +علاقهٔ +لرزش +عصبانی +پسند +لیل +۲۲۶ +جدای +جواهر +ژولیوسی +کوچک، +شمیرانات +بخوانند +ربیع‌الثانی +۵۰، +۲۳۵ +توپخانه +نیکلاس +ویستا +فردیناند +۲۸۰ +تشییع +نمیکند +موسیقی، +نیرومند +۱۸۷۸ +غفاری +بفتا +هویدا +صدیقی +سلیمانی +سياسي +شهرضا +جوانرود +انتشاراتی +شخصه +۵۵، +آسیاب‌های +خوب، +راههای +والنشر +حماسی +عکسها +۲۱۲ +۱۸۸۵ +تعریفی +قاسمی +مصادف +مفرغ +گشتاور +۱۸۷۵ +شکل‌گیری +طهماسب +موجودیت +ستاره‌ها +آوردید +سازه‌های +۲۱۷ +ببریم +ارسنجان +بیدگل +مگه +عبادی +فایل‌های +۱۸۷۶ +تبریز، +رهنما +سپر +قاره‌ای +وو +جعبه‌ای +دانش‌نامه +اجتماعي +هیجان +کارتر +نرسید +۳۳، +کارم +نمی‌شود، +نسل‌کشی +نمونه، +صمد +دریک +میله +پلاسما +زاغ‌ده +داروین +۴۴، +ویس +قاچاق +املای +نامیدن +گنجانده +شادگان +نی‌بید +۲۲۲ +تسهیل +هلن +ناپدیدشدن +خط‌ها +ابلاغ +شمع +بازی، +فندقاع +جوهر +پترزبورگ +هخ +سکو +۴۱، +یاسر +۵۷، +مستلزم +آلبومی +کلک +ضخیم +پاشا +۲۳، +۱۸۸۱ +دی‌ان‌ای +حساب‌های +غلامعلی +خواندند +معلمان +همیلتون +مداری +مست +تصویرها +اندیشهٔ +شدیداً +دیواندره +کنن +بشوند +نیامد +مانگا +۱۳۱۷ +چسب +شجاعت +مشتاق +ایرا +دانا +بریتیش +ویکی‌پدیاها +مهم‌تر +روبرت +کافه +ئی +ارضی +دست‌کم +دندان‌پزشکی +مهرآباد +كننده +رضوانشهر +پراگ +پال +فرسایش +درگاه‌ها +راور +میکروسکوپ +فشارهای +آرزومندم +مصاحبه‌ای +ویولن +دریافت‌کنندگان +نجیب +سئول diff --git a/third_party/harfbuzz-ng/src/perf/texts/hi-words.txt b/third_party/harfbuzz-ng/src/perf/texts/hi-words.txt new file mode 100644 index 000000000000..1dc18dcc1597 --- /dev/null +++ b/third_party/harfbuzz-ng/src/perf/texts/hi-words.txt @@ -0,0 +1,10000 @@ +के +में +की +है +का +और +से +को +है। +एक +पर +श्रेणी +वार्ता +भारत +हैं +भी +यह +शीर्षक +पूर्व +लिए +गाँव +ईसा +उत्तराखण्ड +किया +ने +इस +संवत +कि +हिन्दी +जो +। +जाता +गया +या +जिले +वर्ष +जिला +नहीं +कर +साँचा +ही +हैं। +करने +हो +रूप +था +साथ +द्वारा +जन्म +तहसील +फ़िल्म +होता +तथा +बाद +विकिपीडिया +आधार +अन्य +प्राचीन +कुछ +सदस्य +अपने +इसके +प्रदेश +तो +एवं +तक +चित्र +बाहरी +राज्य +जा +प्रकार +सरकार +नाम +दिया +होती +स्वागत +कई +वह +बिहार +करते +सप्तर्षि +जैसे +थे +समय +अनुसार +आदि +वे +सकते +अधिक +वाले +किसी +आधिकारिक +सकता +कड़ियाँ +भारतीय +उत्तर +मण्डल +हुए +न +जाती +प्रखण्ड +हुआ +क्षेत्र +लेख +द +बनी +होने +उसके +करता +इन +अंग्रेज़ी +संदर्भ +थी +था। +शक +कारण +भाषा +बहुत +स्थित +पहले +उनके +प्रसिद्ध +सहायता +जब +दो +अपनी +कोई +सबसे +अलावा +स्थान +होते +कम +विश्व +लिये +ये +जाने +बारे +लेकिन +प्रयोग +उन्होंने +राष्ट्रीय +वर्षों +कहा +पृष्ठ +गए +रहा +आप +देखें +व +एक्स्प्रेस +तरह +मे +करना +शामिल +सभी +प्रमुख +आंध्र +इसी +अमेरिका +प्राप्त +करें +अन्तर्गत +इसे +माना +सितंबर +उस +५७ +इसका +जानकारी +नगर +मुख्य +हुई +शिक्षा +उन्हें +संस्कृत +कलियुग +बीच +गई +विक्रमी +रहे +उपयोग +मार्च +पोर्टल +काम +वेबसाइट +जनवरी +कुमाऊँ +उसे +शहर +जाते +उनकी +लोग +जिसमें +देश +दी +संघ +थे। +भाग +लोगों +जीवन +१ +कार्य +जी +फिल्म +विशेष +बार +ओर +२ +इतिहास +कभी +दोनों +अब +निर्माण +२००९ +पुरस्कार +वाली +शब्द +पताका +अधिकांश +चिह्न +विकास +धर्म +केवल +लिया +ए +दक्षिण +पुराने +जुलाई +यहाँ +नया +स्टेशन +फिर +लगभग +संयुक्त +अलग +आन्ध्रप्रदेश +गढ़वाल +स्थल +दिल्ली +ई +आरम्भ +अपना +जून +विस्तृत +यदि +प्रान्त +इसकी +सूत्र +शुरु +मंदिर +जालपृष्ठ +जिसे +घटनाएँ +कृषि +दौरान +करती +निधन +दिन +संगीत +यहां +तीन +क्योंकि +इसमें +साहित्य +ऑफ़ +मूल +भूगोल +॥ +पास +पटना +नए +हालांकि +सिंह +प्रदर्शित +प्रतिरूप +अप्रैल +बात +विषय +टेनिस +२०१० +प्रतियोगिता +प्रचलित +कहते +विज्ञान +विभिन्न +अगस्त +ऑफ +पद्धति +छत्तीसगढ़ +सन् +जाना +शुरू +बना +समूह +अनेक +थी। +ता +प्रामाणिक +मध्य +रही +सूची +संख्या +व्यक्ति +ऐसा +गणना +प्रति +आज +तब +उनका +क +इलाहाबाद +ऐसे +मैं +काल +हम +युद्ध +गया। +वाला +श्री +आदर्श +स्थिति +सी +सकती +दिसंबर +प्रदान +विक्रम +विश्वविद्यालय +रेलवे +बड़े +सामूहिक +किया। +किए +राज्यक्षेत्र +यातायात +उन +चार +उपरोक्त +दर्शाता +बन +अर्थ +अलीगढ़ +दूसरे +तौर +गयी +५८ +अन्तर +उत्तरा +राजा +प्रभा +क्या +घटित +मानकर +विभाग +कैलेंडर +देने +बनाने +खेल +प्रथम +हिंदी +इन्हें +एकल +उसकी +एंड +मसीह +अथवा +अमेरिकी +जहां +उदाहरण +कलाकार +निकाले +आवश्यक +७८ +महत्वपूर्ण +पुरुष +मई +नदी +जिसके +प्रभाव +आम +जूलियन +योगदान +किये +अधारित +ले +अधार +इस्तेमाल +सेवा +३०७६ +जिसका +३१०२ +पंचाग +६६७६ +चर्चा +भोजपुरी +कैसे +उर्दु +कलेण्डर +करके +चाहिए +स +कला +उपलब्ध +जनसांख्यिकी +साल +काफी +फर्रुखाबाद +आगरा +कंपनी +३ +उच्च +अक्तूबर +आ +मेरा +स्तर +नवंबर +नीचे +देता +अध्ययन +जारी +कोड +पहली +प्रणाली +अगर +ओपन +ध्यान +उसका +नामक +बड़ी +जल +नैनीताल +अक्सर +अंग्रेजी +सरकारी +वर्तमान +रंग +जिससे +मेल +पुलिस +रखा +प्रत्येक +हर +बनाया +ट्रेन +सामान्य +दुनिया +भूमिका +लिंक +दे +जबकि +सन्देश +शरीर +पता +भागलपुर +विचार +जहाँ +लगा +लेकर +बड़ा +वर्ग +आगे +छोटे +तथ्य +समाज +पानी +इससे +उसने +देशों +महिला +इसलिए +देना +पर्यटन +एस +परिणाम +अल्मोड़ा +सब +स्थापना +बाह्य +स्थापित +पौड़ी +दल +माध्यम +आधारित +पश्चिम +प्रदर्शन +सर्वश्रेष्ठ +चीन +शक्ति +बाहर +बी +ऊपर +बेगूसराय +उत्पन्न +हेतु +डी +आशीष +अतिरिक्त +समान +वीं +हिन्दू +गये +परिवर्तन +आधुनिक +लिखा +कुमार +देखा +अंत +मार्ग +मानव +रेल +अक्टूबर +आपको +घर +प्रश्न +दूर +कन्नौज +भटनागर +सामाजिक +प्रकाशित +अभिनेता +देते +कुल +अभी +जिस +होना +आई +४ +पूरी +संबंधित +रहता +ज्ञान +ब्रिटिश +कृपया +हस्ताक्षर +व्यक्तिगत +बिना +नई +रोग +१० +दशक +अधिकार +परिवार +शैली +लेखक +संस्करण +जिनमें +सेना +संबंधी +औरंगाबाद +प्रक्रिया +यात्रा +२००८ +नये +आवश्यकता +ऐसी +स्वयं +होगा +संबंध +चिकित्सा +मात्रा +परियोजना +प्रबंधक +१५ +विकसित +संदेशों +होकर +प्रकाश +पहाड़ी +पहला +आकार +सुधार +जगह +पन्ना +सही +मैथिली +तैयार +नवम्बर +पिता +मुक्त +क्षेत्रों +रचना +१२ +२००७ +पूरा +पी +संस्थान +५ +लोक +१३ +चरित्र +तुलना +हुआ। +लाल +उत्पादन +जनसंख्या +रहते +उसी +इनके +ा +१४ +संदेश +ज्यादा +शताब्दी +मृत्यु +साधारण +पाकिस्तान +मास्टर्स +दूसरी +पुस्तक +भगवान +इनमें +पूर्ण +लाभ +टीम +बैंक +अवधि +भिन्न +खिलाड़ी +ली +सदस्यों +आने +प्रयोक्ता +कार्यक्रम +सीमा +समर्थन +संस्कृति +े +अंतिम +स्कूल +बने +विकि +टी +अ +पाया +नही +र +सदी +फरवरी +मुझे +सन +परिचय +लेने +मेरे +पार्टी +उत्तरी +लिखने +१८ +दिसम्बर +राम +भर +विशिष्ट +मी +क्षमता +प्रयास +सहित +पश्चिमी +सिद्धांत +दर्शन +सभा +किंतु +वर्णन +विधि +श्रृंखला +बजे +संगठन +गीत +एम +बेबल +राजधानी +प्रभावित +पौडी +ठीक +सुझाव +गति +प्रबंधन +व्यापार +सामग्री +ना +एन +दृष्टि +दिया। +पद +ब्रजभाषा +म +सूचना +शोध +नामांकन +अवधी +लोकप्रिय +आन्ध्र +हाथ +रहने +विस्तार +ऑस्ट्रेलिया +वृद्धि +फ़रवरी +११ +जैसा +आर +कहानी +व्यवस्था +क्रिकेट +बागेश्वर +पृथ्वी +चमोली +गांव +युग +यौगिक +कहीं +पूर्वी +२० +सुरक्षा +मुखपृष्ठ +स्पष्ट +१६ +मिलता +देवी +यही +बुंदेली +सामने +प्रवेश +यूरोप +रखने +दिए +जॉन +जिन्हें +दूसरा +पूरे +स्थानीय +आते +नियंत्रण +चीनी +दिखाई +प्रकाशन +ऊर्जा +प्राकृतिक +की। +जैन +लगता +बनाए +अमरीकी +कवि +व्यापक +दर +वजह +वहाँ +परीक्षण +लंदन +प +ी +बदल +जाए +अदिलाबादु +शासक +खोज +द्वितीय +बस्तर +मदद +योजना +ब्रिटेन +प्रस्तुत +जे +धार्मिक +आर्थिक +सहायक +लेखन +शुरुआत +मिल +डॉ +प्रौद्योगिकी +शासन +स्रोत +रायगढ़ +वैज्ञानिक +कमी +आपके +मिनट +पत्र +निर्वाचन +रक्त +ऑफिस +गूगल +संग्रह +उद्योग +राष्ट्र +एशिया +सांस्कृतिक +पदार्थ +इनका +आपका +मुंबई +हिस्सा +दृष्टिकोण +उद्देश्य +वी +ह +दूरी +आता +अनुवाद +वो +पीछे +भूषण +क्रिया +स्वास्थ्य +पैदा +केंद्र +२०११ +अच्छे +पद्म +शब्दों +ऐतिहासिक +गैर +पिथोरागढ +छोटी +६ +सार्वजनिक +कपूर +प्रेम +मुंगेर +रहती +चैनल +समस्या +कनाडा +अंतर्गत +देवनागरी +राष्ट्रपति +जिसने +बैंड +साम्राज्य +कॉलेज +मगही +प्रयुक्त +पुत्र +अनुसंधान +पहचान +निर्मित +किमी +बंद +प्रतिशत +लगे +अंतर्राष्ट्रीय +ताकि +भूमि +मानक +इंग्लैंड +सके +प्रारंभिक +सन्दर्भ +थीं +अंगिका +दिशा +जर्मनी +१९ +संकेत +बच्चों +द्वीप +समाचार +अफ्रीका +घोषणा +रह +बंगाल +भाषाओं +घंटे +हाल +राजस्थान +वहां +आया +उपन्यास +कानून +दिनों +अभिनेत्री +खिलाफ +सदर +अनुमति +हवाई +टीवी +समाप्त +मीडिया +उपचार +हमारे +जनता +नियम +संक्षेप +मन +मिलियन +चौपाल +उपकरण +राज +भीतर +चेन्नई +२८ +कृष्ण +क्लिक +३० +कविता +कथा +सूर्य +प्रेस +वीडियो +स्वतंत्रता +वन +राजनीतिक +आमतौर +देती +दृश्य +न्यू +योग्य +लागू +मिला +बताया +मैच +जिसकी +सा +मीटर +नेटवर्क +रोचक +भोजन +हूँ +मौजूद +धीरे +१७ +संभव +माता +नृत्य +७ +महत्व +परन्तु +आशा +डॉलर +शायद +आयोजित +सम्मान +युगल +कांग्रेस +सफल +उर्दू +उनमें +वापस +चाहिए। +दें +मनुष्य +लाख +महान +निजी +उल्लेख +जैसी +इनकी +व्यवहार +पन्ने +नीति +जाति +एल +पोस्टर +विशाल +बल्कि +संचालित +देखने +विवाह +अच्छा +ख़ान +२६ +इ +कृष्णा +वंश +जापान +केन्द्र +मेरी +तमिल +देख +विजेता +वेब +शिव +सिर्फ +न्यूयॉर्क +भाई +यूरोपीय +राजीव +प्रयोगस्थल +उत्पाद +मंच +पांच +०५ +पंजाब +०४ +राजमार्ग +मॉडल +कंप्यूटर +स्वीकार +अंतर +कार्बनिक +सक्रिय +परंतु +लखीसराय +किलोमीटर +यमकेश्वर +चला +आलेख +पड़ता +उसमें +ज्ञानसन्दूक +आपने +हमें +मान +इंजन +तहत +पत्रिका +अवस्था +९ +चम्पावत +ं +सहयोग +मौलिक +मामले +अच्छी +तिथि +आरंभ +स्वतंत्र +बल +बाजार +८ +प्रारंभ +मूल्य +सरल +वास्तव +यू +उससे +तुम +मैंने +पुनः +सागर +पक्ष +०६ +छोड़ +खाना +अनुभव +टू +तरफ +बस +विजय +महाराष्ट्र +समुद्र +उचित +रेडियो +चल +हटाने +खुद +समीक्षाएँ +जीव +तेल +दिल +उम्र +जर्मन +ग्रंथ +रूस +संपर्क +बौक्स +रखें +गंगा +एल्बम +राय +पाठ +हासिल +निश्चित +सीमित +सात +प्रांत +गई। +नेपाल +दक्षिणी +काव्य +निर्णय +छोटा +२५ +डिजाइन +रात +हों +लगाया +वास्तविक +पूछे +ज्ञात +प्रकृति +कार +गए। +निर्वाचित +तरीके +त +ज +चुनाव +किन्तु +बढ़ +२१ +हो। +जीत +विपरीत +दस +वर्मन +औसत +इंडिया +सम्मानित +२२ +नाटक +अधिनियम +वस्तु +संरचना +मत +सर्वाधिक +लेखों +विश्वास +मास +संकिपा +वायु +शीघ्र +घटना +निम्न +विरोध +सप्ताह +स्वरूप +प्रवेशद्वार +सितम्बर +गुरु +सॉफ्टवेयर +निर्धारित +विद्युत +रक्षा +पूर्णिमा +पड़ा +बावजूद +बेहतर +वर्ल्ड +चुका +भारी +मगध +समुदाय +क्यों +ऑस्ट्रेलियाई +जनगणना +लीग +अंक +मिलती +भागों +बाल +भेज +कप +कोरिया +कर्नाटक +मात्र +हुई। +अत्यंत +तत्व +महाभारत +ओ +अरब +पूजा +निर्माता +रोमन +विदेशी +अल +पर्वत +पिछले +इनसे +पार्क +स्थानों +जिन +धारा +चुके +मिली +जाकर +बदलने +स्वामी +सम्मेलन +२३ +बनाये +अल्मोडा +शो +जंक्शन +मन्दिर +गलत +सफलता +लिपि +पाए +योग +निर्भर +सिस्टम +प्रसाद +गांधी +प्रचार +फ्रांस +वर्मा +जिन्होंने +रहें +बौद्ध +बच्चे +आंदोलन +एच +तंत्र +मोबाइल +कोशिश +अध्यक्ष +गैस +प्यार +सारे +ल +लक्ष्य +अवश्य +लेते +आसपास +चरण +पर्याप्त +आयु +शर्मा +कार्बन +सुरक्षित +कोलकाता +शीर्ष +२७ +मै +समिति +धन +विवरण +सुविधा +खान +आती +जिनके +यद्यपि +मामलों +प्रशिक्षण +सिटी +कैंसर +पात्र +इतना +रिपोर्ट +नेतृत्व +महिलाओं +फल +महीने +सड़क +देव +मान्यता +क्लब +अनंतपुर +क्रम +य +बजाय +साँचे +उप +२४ +विश्लेषण +आनन्द +यूनानी +चाहते +राज्यों +फाइनल +अवार्ड +जुड़े +अत्यधिक +तकनीक +अज्ञात +निकट +सेंट +चलता +रेखा +निर्देशक +इंडियन +मानते +देवता +जांच +हे +पत्नी +इंटरनेट +केरल +जोखिम +रिकॉर्ड +बदलाव +डिग्री +प्रतीक +जाएगा +अतः +पालन +खंड +विष्णु +भौतिक +जिनका +अकादमी +होगा। +गुण +वित्तीय +क्षेत्रफल +कर्नूलु +करें। +भाव +तापमान +०७ +अनुमान +डे +अमरीका +रासायनिक +च +ग +अभिनय +पत्थर +खाता +किस +गणराज्य +टेस्ट +चोर +इत्यादि +शुद्ध +होगी +भिकियासैण +संघर्ष +अंतरराष्ट्रीय +लगातार +माँ +उल्लेखनीय +रखते +लक्षण +जेम्स +ग्रह +प्राय +वही +औद्योगिक +संक्षिप्त +२००६ +विमान +टिप्पणी +नागरिक +ध्वनि +याद +संचार +बराबर +प्रधान +अमेरिकन +पारंपरिक +युक्त +अत +पुरी +प्रतिक्रिया +शाह +चक्र +अवसर +हमेशा +शारीरिक +हंडिया +आबादी +तट +लाइन +विकल्प +अंग +लोकसभा +खाद्य +पर्यावरण +संसार +विवाद +बनने +करीब +व्यक्तियों +० +वैदिक +बिक्री +ब +निम्नलिखित +कोशिका +पार +परमाणु +भवन +समझ +नष्ट +स्वर +दुर्ग +जितना +प्रकट +फॉर +विमानक्षेत्र +रख +रुप +शहरों +तकनीकी +लखनऊ +मुद्रा +हिस्से +झील +आयोजन +इकाई +मील +समस्त +संरक्षण +अंदर +संस्था +परंपरा +सतह +कार्यों +विद्यालय +संसद +अभियान +सिद्ध +मुख्यालय +प्रस्ताव +सीधे +सर्वोच्च +डालकर +वाहन +गुजरात +उपयुक्त +राशि +बोली +सक्षम +अधिकतर +नेशनल +प्राथमिक +मौत +इसने +गणित +अली +व्यवसाय +हवा +मिट्टी +अगले +फिल्मों +चले +डेविड +मिलते +बनाई +महल +आक्रमण +रे +राजनीति +मंत्री +गंभीर +शाखा +अम्ल +हटा +तटस्थ +भविष्य +ईश्वर +आए +वि +दावा +प्रसारण +जीवित +कड़ी +रखें। +लिमिटेड +अन्दर +क्रांति +लिखे +मैदान +धातु +एफ +सम्बन्ध +विलियम +हृदय +संभावना +वातावरण +न्यायालय +लगाने +सैन्य +परिवहन +परिषद +चारों +पवित्र +योगदानकर्ताओ +गुणवत्ता +खगड़िया +शेष +करे +ला +युवा +नियमित +ऑन +सर +पसंद +दबाव +ईरान +लागत +०९ +०८ +२९ +अधिकारी +उनसे +कहना +बोर्ड +ग्रहण +अशोक +स्टार +जान +दिखाया +ग्राम +स्पेन +नीतियाँ +सभ्य +००० +समारोह +संविधान +इटली +आठ +संग्रहालय +तर्क +दूतावास +पाने +लिया। +पाँच +थलीसैंण +लगी +जन +ताप +परिणामस्वरूप +लॉग +लिखी +रॉक +कार्ड +प्रेरित +आगंतुकों +फूल +तेलगू +लेता +मिले +रोगी +आक्षेप +जरूरत +गठन +व्यक्त +भुगतान +मौसम +मीडियाविकि +अन्तर्राष्ट्रीय +पदार्थों +पूर्वाग्रह +रहे। +शादी +पुरा +विषयों +बिलियन +ढंग +आदेश +लंबे +काउंटी +धन्यवाद +मुस्लिम +विरोधी +वेल्स +लिखें। +पुरानी +कांडा +रानी +विभाजित +मिलकर +तारा +वैसे +ईसाई +पू +शिकार +ज्ञानसंदूक +नेता +शास्त्र +कौन +राजवंश +ब्लैक +अस्तित्व +धारी +प्र +०३ +तेजी +रायपुर +संवाद +किनारे +टाइम्स +भार +सिर +उत्तरप्रदेश +छह +आलोचना +दिये +गुप्त +गेम +नियंत्रित +पुराण +उद्यान +डालें। +हिंदू +डीवीडी +परीक्षा +वालों +घरेलू +वस्तुओं +व्याख्या +पौराणिक +अर्थात +फूलपुर +करोड़ +दिवस +लघु +जिसमे +पिथौरागढ +विज्ञापन +पेश +चर्च +घोषित +कंपनियों +पशु +पाएँ +दर्द +चलते +समाधान +माइकल +सामना +पूछें +लड़ाई +जोड़ें। +संपादित +जनरल +विविध +मिश्र +आग +भावना +टिल्ड +कैलंडर +हत्या +ग्रेगोरी +प्रशासन +रिलीज़ +खास +मध्यम +ज्यादातर +अरबी +रानीखेत +देखते +पाई +आसानी +अंश +कश्मीर +नवागंतुकों +प्रभावी +लिख +किताब +जीन +इंडियाना +चूंकि +सत्य +गंगोलीहाट +नामांकित +कोशिकाओं +कार्यालय +छात्र +मस्तिष्क +डेटा +अनुनाद +मंडल +चुकी +नारायण +कर्म +संपूर्ण +प्रतिनिधित्व +पहुंचती +तेज +अपेक्षा +जाएगा। +व्यंजन +आत्मा +वैश्विक +मांग +सेट +इन्होंने +सम्पूर्ण +बदलें +लग +एशियाई +रोड +ऑनलाइन +इस्लाम +दास +संत +पक्षी +बीबीसी +व्यावसायिक +सीज़न +फुट +जानते +संक्रमण +विचारों +चाहता +मतलब +विरुद्ध +रसायन +निवेश +वर्षा +प्रमंडल +संस्कार +केन्द्रीय +अंतरिक्ष +ध्वज +विशेषता +बाकी +थीं। +यूनिवर्सिटी +शंकर +दैनिक +आचार्य +सं +अनुरोध +गायक +मानसिक +जमा +हाउस +मंत्रालय +पहुंच +जॉर्ज +उपस्थित +मार +प्रधानमंत्री +अंततः +घनत्व +थराली +दूध +सेवाओं +वर्णित +नियमों +यूनाइटेड +साथी +विभाजन +आपकी +चौबटाखाल +सम्मिलित +प्रवाह +गोल +हुए। +बिलासपुर +कह +जलवायु +ब्राह्मण +समर्पित +निवास +फोन +प्रमाण +पैमाने +बिजली +रोहित +शांति +अति +उत्पत्ति +तीसरे +आनंद +हमारी +एकमात्र +नुकसान +मिलने +पे +सौ +घटनाओं +मां +प्रायः +भौतिकी +कठिन +माने +घाटी +अधीन +स्थिर +लेना +उपयोगी +रखना +छूटती +द्वार +वेद +चैम्पियनशिप +बिंदु +जुड़ा +कल्पना +आये +संपादन +तारे +दें। +परिभाषित +उ +सिद्धार्थ +जापानी +ऊंचाई +भौगोलिक +समुद्री +आदमी +उपकरणों +स्त्री +वाक्य +निर्देश +मशीन +०२ +सत्र +फुटबॉल +घाट +उपग्रह +पंथ +बहुधा +हाइड्रोजन +लंबी +श +सुंदर +दौर +रखता +फ़ाइल +मोहन +देकर +काला +नंबर +उपस्थिति +दवा +जीवनी +आंतरिक +परिवर्तित +ज्ञानकोष +वहीं +आय +समझा +निगम +वृक्ष +पॉल +बुद्ध +बाज़ार +मराठी +रूसी +जय +ग्रैंड +संचालन +तत्वों +व्यक्तित्व +कीया +३१ +कारणों +बनाना +अपराध +फिल्में +चक +व्यास +चाहे +छोड़कर +नमस्कार +टेलीविजन +डा +वितरण +एक्स +पुराना +रामायण +बेरीनाग +ग्रामीण +सेंटर +लाइसेंस +मित्र +छात्रों +अध्याय +शेयर +अभाव +मानना +विद्वानों +जनजातियां +वैकल्पिक +तुर्की +जैव +पश्चात +नहीं। +डिजिटल +तारीख़ +समीक्षा +हजार +प्रिय +इतनी +अर्जुन +शराब +स्मृति +जीता +उच्चारण +श्रीलंका +बीजापुर +निकल +स्वीडन +सत्ता +संपत्ति +गर्म +बीमारी +अर्थात् +५० +सम्राट +व्रत +मिश्रण +वार्षिक +प्रत्यक्ष +अंकित +रॉबर्ट +समूहों +आपूर्ति +इंजीनियरिंग +कैलिफोर्निया +उनको +गेंद +इच्छा +रन +ऋषि +समस्याओं +आन्दोलन +अपेक्षाकृत +रोम +चाहिये +चलने +गतिविधियों +गाने +विम्बलडन +हैरी +एण्ड +इंच +सेवाएं +वेस्ट +वें +जाये +पहुँच +हूं +श्रेष्ठ +रहा। +हार +अस्पताल +निरंतर +नियुक्त +तारों +ख +केंद्रीय +वर्तनी +धारण +दान +वाराणसी +स्टूडियो +रोगियों +कुकर्म +साधन +जटिल +अक्षर +देंगे +स्कोर +उत्पादों +प्रोटीन +अनिवार्य +२००१ +कायमगंज +सौर +सरगुजा +साबित +ऊँचाई +लीला +सैनिक +स्टेडियम +रायगढ +पर्व +जयपुर +व्याकरण +रावत +इसलिये +करेगा +तीव्र +प्रकाशक +कृतियाँ +प्रसार +नोबेल +सभ्यता +परिसर +अफ़्रीका +राजनैतिक +इलाज +साहित्यिक +सतपुली +लिखित +फ्रेंच +देखे +ऋण +अकबर +सोवियत +हमला +प्रोग्राम +मिस्र +डाला +छत्तीसगढ +आयोग +पुरुषों +रस +सुनिश्चित +पेरिस +साहित्यकार +परिभाषा +डाटा +अर्थव्यवस्था +महाराज +ओम +सह +पेज +जिनकी +वर्ण +दर्ज +भारती +तभी +तय +एसोसिएशन +अनुपात +झारखंड +जोड़ा +पुन +छत्तीसगढ़ी +यानि +लकड़ी +त्वचा +अधिकतम +कोरबा +देखकर +डाल +पुरालेख +कोइल +बढ़ती +सफेद +प्रतीत +कानूनी +चयन +बनता +हाथों +जल्दी +चार्ल्स +ग्रन्थ +रोक +कारक +खाने +अभ्यास +कैरियर +वर्गीकरण +सर्वेक्षण +नारायणपुर +मिश्रित +ें +तमिलनाडु +प्राप्ति +आकर्षित +भेजा +बनाकर +संग्राम +किले +अड्डा +कहलाता +महसूस +मार्क +माल +वजन +फ़्रेंच +ठोस +उपयोगकर्ता +चम्पा +सलाह +भेद +काफ़ी +लोगो +खाते +निर्देशन +स्वर्ण +बनाते +नोकिया +मूर्ति +हद +रोकने +समाप्ति +अकाउंट +कार्यक्रमों +ग्रीक +संधि +लंबाई +निवासी +दौरे +चाहें +क्षेत्रीय +स्थायी +किंग +न्याय +मोटर +संभवतः +बनाता +पेड़ +तल +पति +वां +कराया +शुरूआत +प्रारूप +काले +कांकेर +रखे +पौधों +खेलों +०० +काशी +मस्जिद +हरा +आकर्षण +नयी +रखी +मजबूत +कडप +आजकल +टंकण +साक्षात्कार +तीसरी +खेती +महासागर +लाया +जोड़ +सामान्यतः +सम्बंधित +सुन्दर +रचित +जांजगीर +पृष्ठों +दीवार +उन्होने +विद्या +लाने +पड़ती +संयोजन +तीसरा +पड़ +रोगों +संसाधन +भाषाएँ +मानचित्र +जमीन +देहरादून +मुगल +कोर्ट +कवर्धा +धमतरी +जशपुर +पौधे +कदम +आकर +बढ़ा +अधिकारियों +आरोप +मिलाकर +बढ़ाने +प्रशासनिक +हमले +टाइम +प्रेरणा +उड़ान +शक्तिशाली +पीपी +महासमुन्द +विधानसभा +फीट +प्रगति +स्नातक +सूक्ष्म +जवाब +कम्प्यूटर +अप +छवि +फ़िल्मों +भ +शुल्क +विभूतियाँ +कलाकारों +संकट +संभावित +दिशानिर्देश +जोर +विधान +आहार +गोठ +उपाधि +राजनांदगांव +जम्मू +सतनाम +कर्णप्रयाग +थोड़ा +बाबा +साइट +तथापि +दन्तेवाड़ा +यानी +अमर +मार्टिन +तुरंत +जिले। +लाइव +पुनःप्राप्त +निर्धारण +तत्कालीन +कक्षा +सारी +प्रजातियों +गये। +करो +मूल्यांकन +द्वाराहाट +राजशाही +घई +होगी। +गैरसैण +हॉल +बिल +ऐ +रूपों +मंगल +जानी +चित्रण +नीतियां +शिक्षण +अवधारणा +चेक +किला +तीनों +मारे +इमारत +आवासीय +किंगडम +राजीवमास +चुना +आँकड़े +फलस्वरूप +करेंगे +ज्योतिष +यंत्र +ग्राहक +चित्रों +नौ +सल्ट +उम्मीदवार +कोश्याँकुटोली +बीज +उत्कृष्ट +०१ +कम्पनी +महात्मा +खर्च +केंद्रित +सिन्हा +हाई +प्रबंधकों +मुश्किल +नर +गाँधी +बनाएं +करनी +हूँ। +स्टेट +प् +दार्शनिक +निकाल +मनोरंजन +पुस्तकालय +सोचते +जेल +हिमालय +पा +जहाज +तरल +यूनिकोड +सैन +हास्य +पैर +दि +दी। +खराब +ख़ुदा +कृति +पुष्टि +हल्द्वानी +असम +अर्थशास्त्र +सेवन +ग्रंथों +कड़ियां +बदले +पुस्तकों +हेनरी +रिचर्ड +परम +सके। +पृ +रहना +हल +सर्वप्रथम +सामान +काली +चेतावनी +मनोविज्ञान +बॉक्स +छोड़ने +संगठनों +तारामंडल +हैदराबाद +छिबरामऊ +मुख्यतः +टैग +४० +यहूदी +विद्रोह +दर्शकों +ग्रुप +जोशी +डीडीहाट +सेन +गरुङ +कीमत +पीटर +कृत्रिम +विपणन +प्राण +आस +बुनियादी +वीर +जल्द +ऊपरी +टिप्पणियाँ +नज़र +पहुंचा +लेखकों +ईंधन +गुणों +२००४ +स्ट्रीट +बचपन +लैटिन +मलयालम +हिमाचल +सरस्वती +स्वामित्व +जंगल +भनोली +भक्ति +श्रीकृष्ण +नवीन +मैन +पीढ़ी +शहरी +लव +अररिया +अनुबंध +विश्वभर +स्मारक +पुर्णीमा +देवताओं +पढ़ें +प्रसारित +परिस्थितियों +रास्ते +टाटा +वा +तरीका +विषाणु +अनुप्रयोग +ईरानी +यात्री +संशोधन +क्रमांक +पंडित +ते +माह +मुक्ति +गहराई +सुबह +यहीं +नाथ +संबद्ध +उत्तम +प्रजाति +मापन +गद्य +टीका +वित्त +विख्यात +अवतार +उपनिषद +दीया +मुहम्मद +राजाओं +फैसला +परंपरागत +जर्नल +व्यापारिक +होंगे +एयर +चौखुटिया +मथुरा +लगते +उसको +तनाव +सिंगापुर +उत्सव +पुणे +अभिव्यक्ति +बढ़ावा +इसको +बच्चन +द्रव +अनुरूप +एट +मेट्रो +उत्सर्जन +एलबम +हरियाणा +चलती +वाणिज्यिक +डॉक्टर +चली +मानी +लगा। +लॉस +सैनिकों +सवाल +२००५ +आरंभिक +निदान +अतरौली +कराने +मालिक +देर +तीर्थ +विदेश +यथा +प्रबंध +संपादक +जैविक +दोस्त +मि +अनुकूल +संस्थापक +इंटरनेशनल +स्लैम +सकारात्मक +टाइप +पुस्तकें +रा +मियामी +लगे। +ड +घटक +निदेशक +इतने +प्रतिनिधि +मितुल +अंग्रेजों +दोनो +बांग्लादेश +वनस्पति +बढ़ने +बंदरगाह +आसान +सटीक +मनाया +भू +समकालीन +पाठक +दोष +औपचारिक +डिस्क +बेटी +संदर्भित +निभाई +राव +सूरज +मगर +चलचित्र +मछली +देखी +जगत +ज़्यादा +सर्वर +लम्बाई +ग्रेट +कर्मचारियों +पंजाबी +अगला +शाही +दर्जा +चिकित्सक +विकार +फैला +शुक्ल +प्रजनन +हां +सदा +अग्रणी +नायक +गृह +धन्यवाद। +जालस्थल +आवाज +बनाम +कपकोट +संघीय +बिग +गलती +विविधता +नो +लगती +पेट +रिलीज +विद्वान +अन्तिम +कॉपीराइट +नमक +अधिकारों +प्रणालियों +युकेश +आर्ट +रॉयल +बालक +पश्चात् +हटाया +पर्यटक +आर्य +प्रीमियर +शब्दावली +परत +सिद्धांतों +हमारा +अकार्बनिक +चोट +कौशल +प्रारम्भ +विकेट +गुना +ब्रह्म +आयरलैंड +पेशेवर +इस्पात +ठाकुर +अग्नि +कोश +रुचि +उपनाम +दत्त +उम्मीद +पशुओं +श्रेय +मुम्बई +निकाला +सिख +पदक +कवियों +इसीलिए +मार्शल +बॉलीवुड +खन्ना +प्रवृत्ति +यौन +रचनाओं +उड़ीसा +तेलुगू +आश्रम +अस्पष्ट +माइक्रोसॉफ्ट +महत्त्वपूर्ण +चयनित +शास्त्रीय +कर्मचारी +जैक +खो +विशेषकर +शब्दकोष +स्क्रीन +प्रतिमा +बर्फ +फारसी +महाराजा +ब्लू +शून्य +जरूरी +आनेवालों +दौरा +प्रतिभा +सच +मौजूदा +क्षति +स्थलों +खून +फ़िल्में +प्रशंसा +होटल +सेल +सालों +थ +दुर्गा +हाँ +स्मिथ +बुक +नोट +रचयिता +शिखर +नेहरू +ब्रांड +सुख +समझने +मुंह +महाविद्यालय +ईस्ट +शृंखला +बचाने +आध्यात्मिक +पुल +त्याग +आविष्कार +हजारों +कहता +जाय +प्रक्रियाओं +विलय +दूसरों +जाए। +२००० +वापसी +आकाश +थॉमस +इलेक्ट्रॉनिक +कडियाँ +संगीतकार +परस्पर +मुख्यमंत्री +उपभोक्ता +प्राणी +होनी +आउट +स्व +उपनिषदों +वक्त +कक्ष +यांत्रिक +आंशिक +बांग्ला +संकोच +शनि +ट +हिन्द +पट्टी +लंबा +कन्या +जीवों +नैतिक +किशोर +फ्रांसीसी +वस्त्र +शिकागो +नदियों +संस्थाओं +ो +गतिविधि +कठोर +सोने +कंपनियां +बेटे +प्रतिरोध +दवाओं +न्यूनतम +खैर +गरीब +मेला +निकटतम +स्थानांतरित +लौट +विटामिन +जोड़ने +ब्रायन +यादव +सहारा +अफ्रीकी +सिनेमा +रचनात्मक +नामों +यज्ञ +स्थितियों +तृतीय +हुये +रिंग +पोषण +कहने +उपाय +विशेषज्ञ +चार्ट +क्लासिक +मानवीय +कार्रवाई +एक्सप्रेस +निर्देशित +सम्बन्धित +ग्राहकों +चलाने +अड्डे +चेतना +देखभाल +रंगों +विकी +कल +संबंधों +सम्पर्क +निष्कर्ष +तंत्रिका +वैज्ञानिकों +टॉम +प्रयत्न +२००३ +पाठ्यक्रम +चिंता +३५ +श्रम +बहन +काल्पनिक +डब्ल्यू +कपड़े +डबल्यू +जातियों +खाड़ी +गीता +हाथी +डिज़ाइन +एकीकृत +कन्नड़ +खतरा +प्रस्तावित +खरीद +अन्त +कार्यरत +ग्रीन +विकिरण +असफल +हानि +लोहाघाट +कानपुर +खिलाड़ियों +छ +सूचित +अयोध्या +स्टॉक +चन्द्र +गवर्नर +लिंक्स +फ़ारसी +खनिज +मंदिरों +गिरावट +पोखरी +सारा +आवाज़ +वायरस +विलियम्स +राधा +सेंट्रल +सहमत +बातें +रामनगर +लिंग +श्वेत +लक्षणों +दर्शनीय +बाराकोट +ऐंड +सन्‌ +रास्ता +वसा +शती +बदला +उन्नत +हिन्दुस्तान +३६ +पृष्ठभूमि +हार्ट +सहज +गिटार +इतालवी +पर्यटकों +हरे +खुले +वर +व्युत्पन्न +जाँच +धारणा +मुख +होली +खड़े +प्रतिष्ठित +पड़ा। +बचने +निवासियों +बरो +लेती +पीठ +पाकिस्तानी +रामचरितमानस +आपस +समझौते +महीनों +कर्ण +हिस्ट्री +सो +पोस्ट +पंक्ति +बहु +संशोधित +कोलंबिया +बचाव +रिकॉर्डिंग +थोड़ी +चुने +चौधरी +अंकों +शाम +बातचीत +ओलम्पिक +गर्मी +फ्लोरिडा +गोली +लाइफ +लम्बी +बम +चावल +बातों +वर्गों +आवास +मिशन +सफ़ेद +४५ +दशा +अपलोड +मेडिकल +जानने +कार्यकारी +सकतें +समीप +संयंत्र +नि +आवेदन +मांस +गहरा +तरीकों +छः +कल्याण +लगने +हुसैन +औ +संजय +जंगली +केन +सुपर +सबूत +साफ +क्रमश +लॉर्ड +समझौता +नाडु +अदालत +आगमन +प्रथा +डालने +औषधि +करवाया +जिम्मेदार +यान +पन्नों +महावीर +सकें +परम्परा +मेक्सिको +गोल्डन +गईं +टन +एकदिवसीय +आदि। +ऑल +१०० +प्रदूषण +अणु +चोपड़ा +भा +संरक्षित +प्रभावशाली +पुचः +जुड़ी +प्रोत्साहित +तल्ला +साधना +न्यूटन +लोकप्रियता +भरा +प्रार्थना +बंगाली +द्रव्यमान +व्यावहारिक +ट्रैक +सावधान +बैठक +तुम्हारे +पॉटर +रथ +प्रोग्रामिंग +कही +कमल +मशहूर +नजर +धरती +स्वाभाविक +चेहरे +सकता। +शिशु +कोण +पॉप +मन्त्र +५१ +निवेदन +अकेले +आवृत्ति +३२ +उठा +कवर +गरम +शैक्षिक +वास्तुकला +पाते +खूबसूरत +एसिड +होता। +जायेगा +पड़े +सीजन +नीला +योग्यता +वैध +ग्लोबल +पथ +बीमा +हिस्सों +माप +मैने +बारह +उल्लंघन +जानवरों +प्रवासी +साहब +एजेंसी +हिट +सुविधाओं +सोच +रवि +गीतों +पेन +गुजराती +अगली +दर्शाया +पतन +चित्रित +आकृति +मैसूर +बुद्धि +मंत्र +मनुष्यों +पत्रकार +पेय +विद्यमान +मादा +बोलने +मना +बेस +सहयोगी +हराया +समीकरण +लिखते +फसल +संहिता +लें +तिलक +प्रोफेसर +सीधा +आकर्षक +संज्ञा +मोटे +वार +खगोलीय +क्रमशः +समर्थक +स्नान +नकारात्मक +नक्षत्र +पहुंचने +चित्रकार +दुर्लभ +सिद्धान्त +भाँति +छाया +पूंजी +आलोचक +अपनाया +बेहद +खड़ा +सका +उदय +भूल +यमुना +क्रेडिट +साउथ +नैदानिक +हिल +में। +फ +नील +प्रयोगशाला +५२ +शासकों +मा +हिसाब +इन्हीं +रॉय +गाय +घायल +ऋतु +तार +लम्बे +३८ +संपन्न +क्रिस +कृत +उतना +नामकरण +स्वाद +मनोवैज्ञानिक +भय +नौसेना +हावड़ा +४८ +श्याम +कार्यवाही +हस्तक्षेप +दंड +दुबई +किस्म +अभियांत्रिकी +फ़िल्मफ़ेयर +मोहम्मद +उर्जा +पारित +गोरखपुर +अस्थायी +स्तंभ +मुसलमानों +असामान्य +कैथोलिक +वर्गीकृत +पाप +मनीष +श्रेणियों +भरे +४६ +पढ़ने +बिल्कुल +खुला +उद्यम +मूलतः +जोड़ी +युनाइटेड +दरबार +मद्रास +निकालने +विरासत +संगम +निहित +गिर +कथन +दाब +आवश्यकताओं +कहानियों +ऑक्सफोर्ड +आफ +उन्हीं +आधा +मर +सोसाइटी +ब्लॉग +मल्ला +कालाढूगी +आकलन +अत्यन्त +पकड़ +चाहिये। +भरी +भाषण +आधे +रत्न +टूर +नाना +संस्थानों +कालेज +शल्य +।। +नौकरी +जुड़ने +गा +मास्टर +किरदार +कुशल +पक्षियों +अधिग्रहण +मजबूर +खड़ी +बताते +अनिल +महाद्वीप +हथियार +कलकत्ता +प्लास्टिक +पायलट +स्वस्थ +जिनसे +रचनाएँ +शिवाजी +परिक्रमा +२००२ +भोपाल +पटकथा +खत्म +ड्राइव +रूपांतरण +भक्त +४२ +अन्यथा +उच्चतम +बढ़ता +असर +रेड +घरों +व्हाइट +आना +खाली +जॉनी +राहुल +कमजोर +ब्राज़ील +श्रीमती +चाय +रखकर +ॐ +एपिसोड +मुसलमान +जाया +एडवर्ड +पारी +बांध +विस्फोट +उर्फ +गुरू +डच +प्रमाणित +समग्र +मतदान +कण +पाटी +प्रोटोकॉल +विकिपीडीया +हिंसा +आजादी +तस्वीर +४७ +चुनौती +क्रांतिकारी +शेर +न्यूजीलैंड +ऑक्सीजन +बनते +निगरानी +व्यवस्थित +सर्विस +आखिरी +चिन्ह +समृद्ध +प्रयासों +रेस +पाता +खतरे +उन्हे +पटेल +बादशाह +गर्भ +हमने +चरम +मुखर्जी +चलकर +पाउंड +जातक +टिप्पणीसूची +न्यायाधीश +५५ +अनुच्छेद +शास्त्री +हि +५३ +पेशकश +बिट +गणेश +जीवाणु +संकलन +पीड़ित +ख़ास +बेस्ट +निकलने +लोहे +ऑव +स्वर्ग +सोसायटी +बेल +भट्ट +बढ़ते +दुर्घटना +त्यौहार +संगणक +विनोद +हालाँकि +न्यूज़ +गहरी +पब्लिक +४३ +तीव्रता +पेटेंट +तिब्बत +पीने +इस्लामी +भीड़ +बहादुर +ड्रामा +सुल्तान +हटाए +अन्तरविकि +साक्षरता +विक्टोरिया +सिनसिनाटी +मठ +प्रतिदिन +सम्बन्धी +निबंध +बनाती +नव +विषय। +तेलुगु +वीकीपीडीया +ऊतक +असली +संसाधनों +जानवर +डाक +बाग +डर +स्रोतों +प्रतिबंध +सोमेश्वर +कब्जा +रहित +अवशेष +वरिष्ठ +बेल्जियम +देशी +जीतने +रणनीति +हें +ताल +द्रव्य +खेला +राजस्व +रीति +गयी। +सजा +उपयोगकर्ताओं +बोस +आलोक +आत्म +फ़्रांस +किसान +गणितीय +ज्वालामुखी +अंगों +ों +बनती +४९ +कायम +खिताब +तुलसी +लक्ष्मी +समानता +वयस्क +शिष्य +संतुलन +अचानक +नदियाँ +नीतियों +नागरिकों +जाल +नामित +नेताओं +पात्रों +सिविल +कप्तान +दुश्मन +चमक +अर्जित +मौखिक +स्वभाव +आनुवंशिक +कितने +भागीदारी +चोरी +रोशन +आलोचकों +बोल +गहरे +गेट +स्तरीय +बता +बहस +जावा +खासकर +पड़ने +दौड़ +३७ +निर्माताओं +विशेषताओं +माई +काट +५६ +सृष्टि +फाउंडेशन +संप्रदाय +उपर +प्रखंड +एटा +प्रकरण +अक्षय +स्कॉटलैंड +राजकुमार +इंग्लिश +आइपी +ध्रुव +मैक +अनुमानित +मधुमेह +गौतम +चरणों +कहे +ि +महादेवी +निम्नांकित +कथित +परिणामों +लिखना +गाड़ी +कॉम +लड़की +उद्धृत +ब्लॉक +३९ +टेलीविज़न +एकता +खेलने +कारों +सांसद +चौथे +सहमति +बचा +गाइड +भले +हा +कां +रिसर्च +ज़मीन +आयुर्वेद +बॉब +मुद्दों +सोडियम +तरंग +चालक +बाघ +साइंस +ग्लोब +सकल +मिलान +बताता +जिलों +जिम +पत्रिकाओं +लगाना +वाशिंगटन +बैंकिंग +प्राणियों +ै +ईमेल +३३ +निर्दिष्ट +पोर्ट +पुर्तगाली +चीज़ +बाबू +अखिल +उदयपुर +चोटी +शक्तियों +मापदंड +ण +घातक +माध्यमिक +मारा +जरिए +इकाइयों +५४ +लेजर +विधियों +खण्ड +देखना +कान +प्रस्तुति +३४ +अक्षांश +कइ +मानकों +गुफा +रखती +सुरक्षीत +होम +करियर +कारकों +पत्रकारिता +पृष्ठ। +प्रचलन +अनुक्रम +इगलास +जूनियर +विनिमय +अनुवादक +विद्यार्थी +निर्यात +शब्दार्थ +केन्द्रित +सम्पादन +बोध +ब्रह्मा +फ़ोन +चाल +ध +अंडे +हनुमान +ज़ +बास्केटबॉल +समापन +राग +छोर +साहिब +शांत +यॉर्क +अद्भुत +राष्ट्रों +सदन +प्रसंग +मोशन +तकनीकों +परामर्श +पैसे +एवम +पं +पृथक +सरदार +माया +मारने +लेबल +टु +निचले +अतिथि +महादेव +परियोजनाओं +दर्शक +विकिपीडियन +जगदीश +विकिपरियोजना +मुख्यत +सीमाओं +मुकाबले +प्रताप +यौगिकों +बजट +५९ +अहमद +चलाया +अहमदाबाद +अनुपम +पूर्ति +पिक्चर +स्कूलों +अंग्रेज +स्वीकृति +बसा +धरोहर +आंकड़े +बैटरी +फूलों +बेटा +गर्मियों +प्रबन्धक +जोड़े +महाकाव्य +जन्मे +गानों +वनों +लेन +बाह +एकत्रित +नेपाली +अमीर +नीदरलैंड +कहानियाँ +मेयर +ऑपरेशन +एक्शन +श्रेणियाँ +४१ +चुंबकीय +मृत +मुद्दे +हित +तोड़ +करे। +बर्मा +कहलगाँव +कहाँ +बैंकों +मेले +ग्रहों +परे +ब्रज +ऑस्टिन +सूचीबद्ध +जरिये +दूरभाष +कितना +प्रभावों +वध +वर्णमाला +कितनी +सचिव +पवन +मैक्स +पिछला +सौंदर्य +लो +खबर +वाह्य +प्रचालन +री +प्रभाकर +पहल +प्रभाग +अनुसरण +पहलू +धूम्रपान +रिकार्ड +प्रशांत +अक्षरों +कथानक +पारिवारिक +लाहौर +भाषाओँ +यात्रियों +घास +जनपद +विचारधारा +बिलकुल +सीता +प्रतिष्ठा +निशान +टॉप +अवैध +दूरसंचार +लौह +अतीत +छत +इंक +पूर्णिया +कोर +एलन +उद्योगों +निष्क्रिय +क्यूबा +वेग +स्टील +टाउन +यूनान +साफ़ +अलंकार +विफल +कुत्ते +सम +करना। +मलेशिया +तैयारी +भव्य +ार +पुत्री +इमामगंज +वकील +४४ +संकेतों +मूल्यों +बाई +भ्रम +पाल +ब्याज +गहन +अंतराल +चौथी +प्रतिस्पर्धा +निश्चय +कारोबार +बच +कोटि +साझा +खुल +लन्दन +सार +राज्यपाल +पराजित +स्नातकोत्तर +रात्रि +शानदार +हॉलीवुड +नाटकों +पीला +ब्राजील +ऊंची +पाये +जोशीमठ +सदस्यता +पैरों +हॉट +आँख +शिक्षक +घिरा +फ़ाइलों +कथाओं +बिगाड़ +रुपये +तू +संदेह +लेखा +क्रिसमस +भूकंप +बुरी +हवेली +बीकानेर +जोधपुर +कहलाते +करनेवाले +दशकों +प्रदेशों +कमरे +वुल्फ़ +जितनी +खतरनाक +गुगल +मामला +रक्तचाप +डा० +रविवार +लीये +स्थापत्य +वाहनों +छूट +हों। +प्रो +जातीय +फंड +चौक +सिक्किम +मिस्टर +टूर्नामेंट +रहमान +जड़ +बनवाया +इलाके +गठबंधन +किरण +गोपाल +कागज +शुभ +मिस +एयरलाइंस +लाखों +तत्काल +अवार्ड्स +मौका +गोल्ड +व्यापारी +हरी +सलाहकार +मनु +फ़र्रूख़ाबाद +अपवाद +मूवी +जोन्स +फ्रॉम +शिकारी +ऑडियो +महेश +गौरव +ऊँचा +कब +सतत +पहाड़ +अनिरुद्ध +अध्ययनों +इंदिरा +उपर्युक्त +एकत्र +महर्षि +भर्ती +सोचा +गुरुआ +शुरुआती +अभियान्त्रिकी +जनवादी +पड़ी +आंख +फ़्राँस +गोवा +जैंती +ट्रस्ट +सर्जरी +संयोग +गिरफ्तार +रामपुर +समाजवादी +सृजन +बपतिस्मा +कोष +आराम +मैचों +बसे +पैदल +तलाश +थियेटर +शुष्क +विश्वयुद्ध +प्रतिद्वंदी +परिवर्तनों +एकदम +भ्रूण +मासिक +द्वीपसमूह +माला +फैल +नरेन्द्र +स्टोन +उठाया +सारणी +प्रारम्भिक +बेतालघाट +बीस +त्रुटि +संगठित +क्लास +एड +आयरिश +हू +ललिता +आग्रह +संतान +प्रबल +नहर +डॉन +प्रवाहित +स्पेनिश +बनावट +भाषाएं +करा +प्रोत्साहन +भ्रष्टाचार +उष्णकटिबंधीय +गाना +उपरांत +पोलैंड +बनायी +आएगा। +पादरी +फैशन +बजाए +टूट +सोनी +गले +मलेरिया +बंगलौर +पढ़ाई +क्रिस्टल +चौड़ाई +जोकि +व्यय +मिला। +विवेक +अब्दुल +परिवारों +बाधा +भूत +रंगीन +राजेश +नींव +हाइड्रोकार्बन +पीले +राकेश +बुलाया +इंस्पेक्टर +परिचित +वेतन +इलेक्ट्रिक +तरी +खोला +पदों +मेन +स्तरों +रोजगार +डोमेन +मानता +सेकंड +६० +ईसवी +सिरे +नाइट +गभाना +यथार्थ +लि +कीट +भावनाओं +नरेश +करार +जानता +कार्यकाल +सिडनी +रमेश +परिमाण +भरत +कार्ल +खोल +म्यूज़िक +पठार +शाखाओं +गुप्ता +कार्लो +तिरवा +वर्षीय +चक्रवर्ती +दिव्य +चंद्र +पावर +विथ +पूरक +मुफ्त +ग्रस्त +रोज़ +समुदायों +शैक्षणिक +नीले +भिन्नता +फ़ +देन +जाएँ +अनेकों +काउंसिल +प्रतिद्वंद्वी +माइक +चालू +सम्भव +क्रियाओं +शहीद +विश्वविद्यालयों +चौथा +सदैव +सुधीर +नागपुर +दु +नवाब +स्पर्श +कोट +दलों +लगाए +इतिहासकार +ओवर +फ़तेहाबाद +ऑस्ट्रिया +हार्ड +मुकदमा +स्टीव +चीज +पायी +बादल +आकाशगंगा +आवरण +भेजने +सुनील +कुश्ती +ईसापूर्व +२०० +मुनि +स् +बृहस्पति +प्रयोगों +बयान +खाँ +शब्दकोश +स्वचालित +सिम्बल +पसंदीदा +उत्तराधिकारी +संसदीय +गायन +क्षमा +आतंकवाद +पत्रों +हरिद्वार +लगाकर +अतएव +गार्डन +बैठे +मदन +चौहान +चन्द्रमा +उठाने +जायें +अर्ध +तारीख +डाउनलोड +अनु +ओलंपिक +श्रंखला +दिखाने +अमिताभ +मौर्य +मुताबिक +प्रपात +फोटो +लक्ष्मण +मालूम +देगा +अपील +लेंस +स्पेस +बिन्दु +द्वीपों +स्विट्ज़रलैंड +अर्जेंटीना +पूछा +वोट +अकाल +शत्रु +कबीर +आचरण +सफलतापूर्वक +एक्सचेंज +उत्तराखंड +शिकायत +शंकराचार्य +धारावाहिक +दृश्यों +१९९० +तूफान +सड़कों +अपेक्षित +बाढ़ +प्रोजेक्ट +पहुँचने +हूं। +ग्रांड +उन्नति +कच्चे +स्वीकृत +बहती +व्यायाम +प्रयोजन +एरिक +ऑटो +इंटरसिटी +सरलता +उपनगरीय +अनाज +धातुओं +संकल्प +तेरे +धूप +वंशज +परिपथ +घोड़े +मोक्ष +तालाब +असमर्थ +श्रद्धा +विनाश +सापेक्ष +अद्वितीय +सराय +सुरेश +जनजाति +ट्यूब +रहकर +कैम्ब्रिज +श्वसन +सुविधाएं +सूत्रों +बंध +जंगलों +नेत्र +डीएनए +बिलबोर्ड +आदिवासी +दिखने +गाया +आर्थर +नैशनल +सिक्के +वायुयान +समक्ष +समतल +पिछली +छोड़े। +विधा +सीखने +कालीन +बौद्धिक +विधेयक +सक्सेना +खा +यूनियन +परमात्मा +संस्करणों +योद्धा +पैटर्न +स्त्रियों +कर्तव्य +जातियाँ +वंशावली +कमाई +पैसा +वसंत +कहलाती +एंजिल्स +अपोलो +सिंहासन +इनपुट +बस्ती +दीवारों +प्राधिकरण +संभवत +भालू +केबल +पुष्प +सिंचाई +मानने +कॉल +क्रॉस +अभिगम +उपलब्धि +राजनीतिज्ञ +नोट्स +बे +मेजर +ग्वालियर +प्रजातियां +लॉ +प्रसन्न +यूएस +रहेगा +बुरा +रोल +नली +उक्त +राजकीय +हल्के +हंगरी +पैलेस +बनकर +फेर +पुरे +घड़ी +कविताओं +स्वरुप +सेनानी +अवयव +अनुप्रयोगों +कृतियों +ध्रुवीय +विल +इंडोनेशिया +बहुमत +टिकट +कठिनाई +शासनकाल +कार्यान्वयन +दायित्व +जर्सी +वितरित +मूर +टर्मिनस +सुन +जाएगी +फोर्ड +दीपक +चित्रकला +गरीबी +सेमी +तात्पर्य +संलग्न +आश्चर्य +मेहरा +१९९८ +भंडार +परिषद् +लाइब्रेरी +बंधन +इण्डिया +कोयला +महमूद +सुना +नंदीग्राम +संतोष +यूके +जागरण +बदलकर +नींद +बचे +किसानों +खुशी +स्पोर्ट्स +बलों +भंग +कहानियां +सफाई +रहस्य +कणों +किशन +वृत्त +अरुण +मानस +प्रेमी +हमलों +जीते +नमूने +त्वरित +नम्बर +शरण +आतंकवादी +रंगमंच +टुकड़े +निकलता +ठंडा +खेत +गेम्स +राजेन्द्र +तालिका +तटीय +दिनेश +भंडारण +निकला +मध्यकालीन +५०० +पान +चक्कर +ब्राउन +वाणी +असाधारण +यकृत +बोलते +रोटी +झूठ +पौधा +वेदों +संक्रमित +जितने +खूब +नाभिकीय +ज्यामिति +रेटिंग +जिम्मेदारी +प्रेमचंद +एजेंट +निरीक्षण +लुईस +नित्य +मेमोरी +उतनी +उसपर +पड़ोसी +तुम्हें +वचन +लोकतंत्र +पार्श्व +संवेदनशील +उत्पादित +सीरीज +कॉर्पोरेट +सूचकांक +चैनलों +अनंत +नीतिया +रिकॉर्ड्स +ज़रूरत +भावी +होल +विवादास्पद +पिनकोड +सरकारों +पहलुओं +जादू +तपस्या +विहार +मोटी +रुपए +अपितु +व्यंग्य +सीधी +सिर्फ़ +गुवाहाटी +बेच +नाटकीय +शोर +पुराणों +मरीज +वाजपेयी +तिवारी +रही। +ब्रेक +फैले +विन्यास +भाप +थोड़े +सर्वोत्तम +शशि +पार्वती +रचनाकाल +अदा +गयीं +पुर्णिया +बॉन्ड +बिन +मोंटे +नाक +दीक्षित +जिनमे +अवलोकन +नस्ल +डेनमार्क +वरुण +विभक्त +सैकड़ों +अनुभूति +पंजीकृत +मतभेद +कॉमेडी +कलात्मक +निकाय +तरफ़ +आणि +साथियों +गुलाब +झिल्ली +सोना +संश्लेषण +इलाकों +पण्डित +आया। +रेसिंग +खपत +टेलीफोन +पड़ते +दिलीप +ई० +एकादशी +प्रतिबंधित +फलों +साइड +उपासना +खोटे +प्रिक्स +एचआईवी +आमंत्रित +फार्म +इसपर +रेंज +१९९९ +प्रयाग +मंगोल +शासित +रद्द +अजय +भाजपा +आईएसबीएन +सुमित +एवम् +रजिस्टर +विकीस्रोत +इंदौर +बोइंग +अमृतसर +मकान +पारिस्थितिकी +मैड्रिड +समन्वय +अन्ना +लोहा +कम्युनिस्ट +गण +अवसरों +ब्यूरो +चूँकि +खुली +तन्त्र +राजपूत +समझते +बिहारी +वैष्णव +चैंपियनशिप +प्रतिकूल +सिंड्रोम +बंबई +अमृतपुर +ख्याति +पुर्तगाल +क्यूँ +घ +नारी +अनुभाग +मैरी +गर्भाशय +सर्व +पूर्ववर्ती +चतुर्थ +इमारतों +रेजिस्ट्रेशन +प्रभु +अस्वीकार +साक्ष्य +वॉ +बढ़कर +इनकार +सांस +प्रतिवर्ष +भाषी +बढा +मूत्र +अरारिया +निकलती +क्रिटिक्स +धारक +उपयोगिता +त्योहार +समेत +प्रतिरक्षा +बटन +समर्थ +दा +नगरी +तेज़ +भूतपूर्व +देखता +दमन +अनुचित +श्रीवास्तव +हट +प्रशंसकों +भंडा +तथ्यों +दस्तावेज +ऑपरेटिंग +कोशिकाएं +वाणिज्य +पोषक +धीमी +वियतनाम +स्कॉट +रहीं +घाव +प्रावधान +१९९२ +बैक +श्रीराम +मुकाबला +स्टेट्स +पादप +गणतंत्र +योजनाओं +रोजर +हार्मोन +उत्पादक +टेक्सास +बेहतरीन +फ़्रांसिसी +राजस्थानी +लगाते +बीटा +मान्य +उद्धरण +एज +उद्घाटन +पूर्वोत्तर +हार्डी +यहा +शैलियों +ऋग्वेद +तमाम +बेन +सुभाष +प्रशिक्षित +दुबारा +भीतरी +प्रिंस +हड्डी +मल्ली +बेचने +महत्त्व +आक्रामक +कार्यकर्ता +कटौती +सोमवार +गिर्द +शुरूआती +तिहाई +खरीदने +इट +बिजनेस +असंभव +डिज़्नी +जानकी +ली। +तें +बने। +खेले +दादा +पृथ्वीराज +सांख्यिकी +हुईं +केविन +बनारस +रोशनी +आरती +पीछा +स्थानांतरण +रिश्ते +बर्तन +परिस्थिति +बोले +राष्ट्रीयता +बलि +इंजीनियर +प्रमेय +बुक्स +उनपर +छंद +गुंजन +टॉवर +शाब्दिक +स्वप्न +सुधारने +यूरो +अवध +तत्त्व +निधि +ललित +भांति +विमानों +जलप्रपात +चाहती +आंकड़ों +तेज़ी +मैनेजमेंट +मैट्रिक्स +राजभाषा +आयाम +गुड +पाली +सनहौला +पारस्परिक +जंग +पिक्चर्स +इनको +आस्था +गुलाबी +आजाद +टेक +ऊंचा +एतमादपुर +ब्लोक +प्रतिनिधियों +स्टेशनों +हालत +१९९१ +अटलांटिक +ऊँचे +वेबसाईट +पत्ते +आलू +इन्द्र +परिकल्पना +सुनने +गुलशन +हज़ार +कम्प्यूटिंग +नियुक्ति +पहुँचा +विशेषताएं +आयात +खुदरा +लैंड +मग +महा +फ़िर +अनुयायी +काफलीगैर +डाउन +ओबामा +कैद +सूजन +उपदेश +विवेचन +मोटा +नारंगी +धर्मों +कुमारी +बंदी +ख़त्म +अल्प +कोटा +चीजों +पहाड़ियों +८० +सर्किट +स्रोतहीन +दुकान +हंस +सैद्धांतिक +किरन +देखें। +तलवार +सबके +ब्रदर्स +दोषी +टेलर +बॉल +कटाई +वाद +पक्षों +फ्रैंक +नगरों +वाहक +विश्वसनीय +समस्याएं +पत्थरों +कार्टून +जि +बीसवीं +तिब्बती +गो +भेंट +जगहों +निष्पादन +विक्रेता +खगोल +रोज +कसम +स्मरण +क्रोध +कॉमिक्स +सूर्यवंशी +पोप +भेजे +्य +किरौली +सख्त +ग्रीष्मकालीन +विल्सन +सुदूर +ढांचे +जगन्नाथ +ड्राइवर +गांवों +कश्मीरी +स्वीडिश +वशिष्ठ +पीड़ा +कहकर +नैतिकता +वस्तुत +औषधीय +मैट +ज्योति +नगला +महापौर +गठित +प्रदाता +श् +आर्ट्स +हटाना +ऊष्मा +सकने +मरने +ग्रीस +मिश्रा +हमसे +आपसे +क्वीन +गिनती +शिल्प +मनोनीत +एकड़ +रोकथाम +हितों +आशू +अधिकृत +इर्द +सांता +खुदाई +स्टीफन +विश्वकोश +लायक +विश्वनाथ +गीतकार +मुमताज़ +रूचि +इराक +लम्बा +ग़ैर +वॉशिंगटन +आपसी +भूमिगत +भरपूर +रावण +वन्य +सौरभ +जुड़ +विद्युत् +अद्यतन +जीएसएम +मैकमोहन +सेतु +दूरदर्शन +संवैधानिक +जीवाश्म +डबल +हानिकारक +दर्पण +पूजन +विलयन +िया +लता +उपहार +क़ानून +थिएटर +परिचालन +एकीकरण +प्लेट +हार्डवेयर +समावेश +संचिका +अपशिष्ट +मनमोहन +फाइबर +भारतीयों +दुसरे +आंखों +संस्कृतियों +यंग +सदियों +मत्स्य +युक्ति +फ्रांसिस्को +बर्लिन +लौटने +मेहता +क्षण +पाश्चात्य +गामा +कैमरा +ताजमहल +सर्च +बना। +तल्ली +साधनों +पहचाना +राजा। +मेरठ +जिसको +मधु +रिश्ता +धूल +गायब +मोर +सीरीज़ +इति +सें +सामुदायिक +अनुदान +ड्रम +बडा +कालिदास +ब्रूस +क्षय +मातृवंश +ट्रिपल +प्रगतिशील +गोस्वामी +शनिवार +हल्का +हिन्दुओं +फैली +विष +गर्भावस्था +विस्तारित +मिमी +बा +डेल्टा +आँखों +दीर्घ +गंतव्य +गणितज्ञ +बिली +बल्लेबाज +क्लोराइड +बालों +मैनचेस्टर +यु +निर्णायक +इंगित +मयुर +साप्ताहिक +वैशाली +पूर्णतया +बच्चा +अक्ष +भविष्यवाणी +भ्रमण +हांगकांग +ब्लेक +रेस्तरां +कृपा +परेशान +विकासशील +मांसपेशियों +गोविन्द +प्राकृत +कथाएँ +गुलाम +व्यस्त +मार्गदर्शन +कोंच +कट +प्रतिस्थापित +वैभव +पहने +पाठकों +बातकरें +डॉग +विकिमीडिया +बेदी +पोशाक +चंद्रमा +छिद्र +इमारतें +माउंट +सिफारिश +होगन +उज्जैन +समर्थित +ब्रह्माण्ड +रसूल +श्लोक +राहत +आखिर +एम् +दाल +पकड़ने +मुँह +उत्साह +गर्दन +तुलनात्मक +काटने +पाक +महारानी +ग्रंथि +जरुर +यूरोपियन +आत्महत्या +शर्त +चुम्बकीय +सम्प्रदाय +नवीनतम +हीरो +मशीनों +जयंती +मिथुन +उद्देश्यों +सामयिक +अकेला +परिवेश +मोड +लवण +चिली +रखरखाव +बोलचाल +अभिलेख +चाँद +लें। +सेनाओं +अखबार +दिखा +रूपरेखा +भास्कर +समाधि +विंडोज +बनाया। +भयंकर +अमृत +अरुणा +ऊंचे +खेर +दोबारा +बाध्य +लगी। +नागर +उपन्यासों +हीन्दी +नाट्य +जनक +नमूना +टीमों +आउटपुट +जोस +कोरियाई +मरम्मत +डाक्टर +सूरा +कष्ट +परीक्षणों +बाएं +भरने +वेन +केस +महिलाएं +लुप्त +फ्रेम +द्विवेदी +असरानी +शोषण +नियमितता +इंसान +पद्य +वायुमंडल +पोल +विलुप्त +अपूर्ण +बेचा +लिनक्स +कडी +सतीश +बहरहाल +आयी +हिन्दु +मल +बताने +श्रीनगर +लड़ने +टोक्यो +ऊँची +पर्ल +पितृवंश +नी +दीर्घा +धार +मंदी +फ्री +घंटा +दोपहर +इंस्टिट्यूट +गुर्दे +एचटीएमएल +रजत +अवकाश +सीबीएस +पाना +होती। +फेसबुक +भगवानपुर +पतली +सीट +मोड़ +मक्का +स्पेक्ट्रम +संरचनाओं +इसमे +बुध +ब्लूज़ +अवसाद +अफगानिस्तान +पंजीकरण +जरुरत +अवरोध +ब्राउज़र +टाइगर +विनिर्माण +जालघर +विज्ञापनों +बॉट +ग्यारह +मुजफ्फरपुर +गिनी +परी +मिलेगा +कस्बे +भाषाई +बारी +माँग +गैलरी +मिलन +शुक्र +आर्मेनिया +इंस्टीट्यूट +आत्मकथा +सदस्योंको +प्रतिपादन +टर्मिनल +रहेगा। +पेड़ों +मिली। +कमीशन +योनि +फसलों +गतिशील +भी। +संचरण +प्रभुत्व +उपक्रम +समुचित +दक्षता +द्रविड़ +बन्द +दिखता +मध्यप्रदेश +सारांश +भीम +अस्तित्वहीन +हथियारों +खुराक +प्रकारों +तेरा +ताकत +भगवान् +लेक +समकक्ष +देशांतर +ै। +जोसेफ +आज़ाद +सामान्यत +उपभोग +भीष्म +ऊतकों +खिलाफ़ +लोकमान्य +अन +राजू +अस्थि +दरवाजे +राजनेता +आघात +उपमहाद्वीप +प्रख्यात +टोनी +टुल्सका +विफलता +स्टोरी +बैठ +बनना +स्वतः +भाषाविज्ञान +दृढ़ +अर्थात्‌ +शी +पचास +प्रसिद्धि +अपराधी +डाली +हरि +डकोटा +कोहली +प्लेयर +आश्रय +नाग +बिस्मिल +छात्रवृति +मिनेसोटा +लाए +सकें। +चुनावों +ब्रिज +चिंतन +बिगाड +विमर्श +पहुंचे +होंगे। +वैसा +भूख +दिखें +नॉर्थ +अवस्थित +घेरे +स्ट्रोक +सर्बिया +असल +हिन्दुस्तानी +घन +वीज़ा +महोत्सव +घटकों +बढ़ी +करवा +सुनकर +रावल +घट +प्रायद्वीप +स्वाधीनता +विशेषज्ञों +प्रबंधकोने +कैलिन्डर +धनरूआ +डेली +किलो +जाट +अधिकारिक +माहौल +सीटें +पुरातत्व +पीपल +लीटर +अनुकूलन +गेंदबाज़ी +शीह +वायुसेना +सूर्यगढा +उन्होनें +सिंध +इधर +टैंक +पंच +भूमध्य +अफ़्रीकी +डांस +बलिया +एड्स +जनन +जंतु +समझना +ग्रन्थों +सैम +गुरुत्वाकर्षण +कोमल +जायेंगे +थाईलैंड +टेलिविज़न +दायर +ज़िले +त्रिपाठी +प्राचीनतम +विदेशों +करी +पढ़ा +पर्वतीय +नाइट्रोजन +परशुराम +स्वतन्त्रता +चार्ज +मेहनत +फिलिप +पेट्रोलियम +नदियां +पिंड +उत्तरार्ध +लेनदेन +दीर्घकालिक +आयतन +मूलभूत +टनकपुर +डाटाबेस +औरत +नकल +डि +चैंपियन +मोती +होनेवाले +दिमाग +टेक्स्ट +जीवनचरित +मणिपुर +फील्ड +प्रक्षेपण +निकले +खड़गपुर +करन +९१ +प्रदर्शनी +अनुष्ठान +वक्र +संबोधित +शिविर +वास्तविकता +गोआ +मेटल +भगत +सवार +मजदूर +शतक +मानवता +वॉन +बढ़ाया +दानव +सदृश +१९८९ +विभागों +कमाल +बचत +मिर्च +कॉफी +बडे +कीं +फर्स्ट +स्तन +कोने +संसारके +१९७२ +डुमरिया +क् +आवागमन +१९८० +होम्स +संकलित +पत्तियों +सूखे +मुलाकात +लास +सनातन +सामग्रियों +कुत्तों +रोबोट +खैरागढ़ +कर्नल +राखी +आधारभूत +पालीगंज +स्पेशल +संजीव +अग्रवाल +आस्ट्रेलिया +आधी +सूरत +संक्रामक +मुझसे +मुग़ल +वोल्टेज +अणुओं +ज़रा +सील +खनन +समानांतर +बोला +ग्रे +ष +भागवत +रंजीत +मीनार +पूर्णागिरी +बीरबल +गायत्री +जबलपुर +उजागर +सशस्त्र +कोच +प्रश्नों +बुंदेलखंड +बडी +बदलते +पुर +जीवविज्ञान +राह +प्रशंसक +पर्यावरणीय +लड़कियों +स्टोर +संगत +प्रोफ़ेसर +एलिस +हिंद +पूल +भि +९० +भावनात्मक +प्राथमिकता +वाष्प +ओल्ड +आज्ञा +औजार +गैसों +व्हिस्की +रोका +कहती +जहाजों +सशक्त +दिवसीय +उतार +शान्ति +वृक्षों +प्रचुर +प्रसव +७० +संरचनात्मक +फीचर +फॉक्स +देरी +पुरूष +कीबोर्ड +लाइट +शिलालेख +सपना +व्युत्पत्ति +कद +सजीव +लोकतांत्रिक +स्राव +विन्डोज़ +शॉट +चिह्नित +उधार +जेट +चे +युधिष्ठिर +माधव +आसन +संख्याओं +शेख +घूमने +आक्सीजन +राइट +नियत +इतिहासकारों +एनरॉन +रु +पारम्परिक +व् +सर्वथा +वाद्य +आपदा +दरभंगा +जात +१९७१ +लाभदायक +म्यूजिक +दावे +वोल्डेमॉर्ट +भारतवर्ष +जोकर +राणा +कादर +गढ़ +कनालीछीना +मुकेश +जाएं +क्लार्क +बॉबी +सम्पन्न +भूरे +शोधकर्ताओं +पूर्ववत +अहिंसा +बीमार +जूते +फाइल +नारियल +अमरीश +अवतरण +छेद +शर्करा +सेनापति +एक्सेस +वस्तुएं +वादक +दांत +योगी +चोल +परिष्कृत +श्रमिक +नामांकरण +सबको +जिसपर +इलेक्ट्रॉन +महिमा +क्षैतिज +उत्तरदायी +शूटिंग +कारखाने +आरक्षण +आरेख +किए। +रो +यों +घटनाएं +बाइबिल +दम +वार्ड +ज़रूरी +औचित्य +एव +१९७० +तीस +यूनिट +खेलते +डेटाबेस +मामूली +सफर +अध्यक्षता +आदर +कॉर्पोरेशन +चैतन्य +िक +निरपेक्ष +निकोलस +आसमान +विश्राम +वर्जीनिया +अभिनीत +आन +संरक्षक +दाता +तेरी +जॉनसन +अल्कोहल +दिस +दर्शाते +अन्वेषण +लगाई +जीने +टीबी +३०० +उदाहरणार्थ +करण +चंडीगढ़ +शरद +कास्त्रो +सहकारी +छुट्टी +स्थिरता +जोड़ता +कैल्शियम +वुड्स +ित +सपने +इत्यादि। +प्रजा +सेक्स +शुक्रवार +सर्दियों +चीजें +नाव +फर्म +हॉकी +कहां +विमानक्षेत्रों +१९४७ +चढ़ाई +परवर्ती +क्षत्रिय +ब्राह्मणों +कराता +नौबतपुर +आयन +आइ +प्रवर्तन +लिटिल +स्वत +नासा +तंग +रक्षक +ग्रोवर +शिवपुरी +सीडी +गौर +बतौर +कल्प +साधु +इकाइयाँ +पढ़ +दीक्षा +घंटों +करेगी +उदहारण +लीवर +सती +बियर +हार्वर्ड +सहारे +दक्ष +१९९६ +अभिषेक +तुम्हारी +रेगिस्तान +अभयारण्य +चाचा +प्रशासकीय +टावर +अनुकरण +जें +ऊन +फायर +जैसलमेर +कविताएँ +विक्रमादित्य +लड़के +न्यायिक +आपराधिक +निंदा +सेठ +गत +दुर्योधन +गगनचुम्बी +हीरा +१९९५ +वैन +मिशेल +मालुम +जिमी +रिपब्लिकन +चटर्जी +पेपर +बोस्टन +व्यापारियों +शान +सुप्रसिद्ध +सचिन +हु +राजकुमारी +निवारण +विकृत +त्रिपुरा +लेबनान +परेशानी +१९९७ +देवलथल +प्रत्यय +मरीजों +स्‍थान +फतेहपुर +ह्रदय +अध्यापन +लीड्स +औरंगजेब +वस्तुएँ +निवेशकों +सरोवर +एंडी +दिनांक +कंट्री +लीप +गंध +श्रेणियां +आरक्षित +मारुति +प्रशासक +ज़िन्दगी +जन्मस्थान +वॉल +भाइयों +सहकुंड +शेयरों +कवरेज +धाम +कर्ता +वाल्मीकि +संग +सेल्सियस +सलीम +सूक्ष्मदर्शी +यांत्रिकी +इलाका +रियल +पंकज +विशेषताएँ +मकबरा +प्रहार +अजमेर +अभिगमन +केशव +मयूर +धनी +ऑक्साइड +अरुणाचल +उपलब्धता +नजदीकी +इंजीनियरी +डीन +उपनिषद् +जरूर +प्रखण्ड। +ब्रह्मांड +शीत +पहाड़ों +एक्ट +विण्डोज़ +छठी +कश्यप +वार्नर +उ०व० +बुश +१९६० +सन्त +पारसी +खोजने +कुंजी +रोमानिया +इकट्ठा +लय +शस्त्र +फलन +तुलसीदास +आदित्य +जगदीशपुर +नीम +इयर +सामान्यतया +चार्ली +जानेवाले +एजेंसियों +पाटिल +सिगरेट +बरकरार +पाठ्य +साहनी +जोड़कर +शैल +पाचन +लेट +से। +अनावश्यक +गतिविधियाँ +विषयक +शर्तों +असंख्य +याहू +विक्रय +राष्ट्रमंडल +ऑस्ट्रेलियन +बलिदान +उपेक्षा +पाती +गौरी +संचित +मार्केट +सिकंदर +सीरिया +अभिक्रिया +टक्कर +दहन +हैमिल्टन +घोष +समाजशास्त्र +भाग्य +चट्टानों +साझेदारी +पठन +उत्तेजित +अवशोषण +चिकित्सकीय +अपमान +ओजोन +स्तूप +वयस्कों +ट्यूमर +रॉ +इंटरफेस +टेबल +संज्ञानात्मक +सच्चे +कपड़ा +वक़्त +ऐल्बम +मित्रों +बीहता +उदाहरणों +ऑस्कर +पृथक् +घी +अं +सुई +झलक +विराम +फोर्ट +पुरस्कारों +इज़ +एनबीसी +रखा। +सत्येन्द्र +वर्णक्रम +चांदी +वेगास +नें +वषीश्ठ +श्र +बगैर +पुनर्निर्माण +आदान +हिटलर +क्षतिग्रस्त +ज्यों +प्रसंस्करण +सुरंग +शाकाहारी +धनुष +वैचारिक +मधुर +गायिका +प्रोफाइल +प्रतिरोधी +उपज +संवर्धन +चेहरा +बाँध +कोर्स +स्पेनी +परिप्रेक्ष्य +प्रतापगढ़ +महानगर +सुनाई +गद्दी +वास्तु +निर्देशांक +आँखें +व्यतीत +उन्नीसवीं +गिरने +भावों +सांख्यिकीय +आशय +भगवती +साधारणतया +भोज +मुराद +रवी +प्लेस +परंपराओं +हिप +डार्क +चुन +साजन +परिदृश्य +रज़ा +ताइवान +सवारी +देखिये +त्रिकोण +कपड़ों +पद्धतियों +अपनाने +स्त्रोत +खिज़िरसराय +समर +जड़ी +वेदव्यास +१९६५ +चलन +जिव् +सौंप +औपनिवेशिक +चिकित्सीय +ट्रेड +स्वच्छ +बुरे +डैनियल +मंगलवार +पूर्वज +उष्मा +चिकित्सकों +रूपांतरित +जंतुओं +नारद +पैकेज +नागरी +पल +बहुविकल्पी +तथाकथित +कार्यक्षेत्र +पंख +अवॉर्ड +मसौढी +तम्बाकू +लहर +बीमारियों +निरूपण +साइकिल +थीम +क्रान्तिकारी +इंग्लैण्ड +सर्वत्र +जॉर्जिया +शेट्टी +छाप +मलिक +हैमबर्ग +स्वदेशी +सूचक +१९६२ +धारचुला +चर्चिल +रिलायंस +ईस +ती +संकर +विजुअल +उदार +उद्गम +पंचमी +मंजूरी +अनन्त +प्रायोजित +नेट +मालवा +लाई +बगल +धर्मेन्द्र +नाश +फीफा +नगरपालिका +टेप +खुर्द +मार्गों +धमकी +शिवलिंग +प्रासंगिक +धरहरा +मारिया +विवादित +मेक्सिकन +१९८६ +उपायों +दरअसल +सम्पादक +वृत्तचित्र +सिंगल +लुई +विद्यार्थियों +मुद्दा +फैसले +आए। +अलगाव +मिशिगन +धान +भयानक +पिट +दिखाए +ान +चाप +पहनने +विशेषज्ञता +पैट्रिक +इनमे +चर +कुत्ता +निर्वाण +दण्ड +नागरिकता +दुकानों +वर्चुअल +लंका +शॉन +ब्लड +जैक्सन +जलीय +अमास +कड़ियों +अनुसूचित +रेत +गारंटी +दिशाओं +स्टैनफोर्ड +मूलत +डेनियल +परि +सेवक +अमृता +शताब्दियों +जायेगी +दिलचस्पी +नाईट +मॉडलों +हान +स्वायत्त +ज्वर +जवाहरलाल +आगामी +कूद +बुधवार +राक्षस +आयेगा। +इंटर +वांछित +धमनी +सुलभ +बाण +वाई +पुरातात्विक +गौड़ +सामवेद +नाभिक +अध्यापक +समाजवाद +उद्भव +डैनी +चक्रवात +फैलाव +एंटीबायोटिक +चर्चित +जितेन्द्र +उपनिवेश +लास्ट +१९७५ +डाई +गुणा +सूट +इलेक्ट्रॉनिक्स +स्क्वायर +डाले +दुःख +कुंड +सांचे +चंपारण +प्रवास +दुख +अधिवेशन +भरोसा +तप +महामारी +सेब +जेरी +हसन +ऑर्डर +घोड़ा +पासवर्ड +खारिज +ख़ुद +इन्होने +डेविस +सरन +प्लाज्मा +खुलासा +स्कॉटिश +टोरंटो +बेकर +प्रतीक्षा +कराते +क्षमताओं +पांडे +हॉप +कांच +मणि +ऐतरेय +णी +न्यूज +संतुलित +सीला +विरूद्ध +द्वितीयक +ट्रक +भेदभाव +निराला +नजदीक +भाष्य +आयेगा +सहन +उस्ताद +नॉर्वे +बैठा +संस्कारों +घने +गोपनीयता +स्तम्भ +वैमानिक +पंत +भक्तों +सम्भावना +श्वास +ओवेन +जगत् +फायदा +तस्वीरें +रुक +निषेध +नेटवर्किंग +आयरन +मॉडलिंग +१९८४ +चंद +शिमला +कोल +मनोज +बैल +झा +केन्द्रों +केप +एकाधिक +कुरुक्षेत्र +डिएगो +कराना +फिल्मी +ठहराया +जिल्ला +अमीरात +ज़िला +प्रतिस्थापन +मूर्तियों +कूट +साहस +बेबी +हाइब्रिड +पेशी +तिरुपति +सोलह +इयान +डिक्शनरी +ताज +बहुमूल्य +सुगंधित +पैनल +वाटर +नकली +टैक्सी +अस्त्र +बुखार +जानना +उत्परिवर्तन +निमित्त +द्वारका +फिलिप्स +कांगो +आइलैंड +दाढ़ीकेश +आक्साइड +मिल्वौकी +पर्वतों +१९८५ +ढाल +ईस्टर +वर्षो +उधर +बिल्डिंग +ज़ोर +निर्भरता +सिन्धु +अनौपचारिक +यम +योर +नवजात +नियंत्रक +अनुभवों +विज्ञानी +लगाये +वर्णों +स्वतन्त्र +अलौकिक +हीं +बदलता +डालते +चौड़ी +आशीर्वाद +गोद +उपाध्याय +जिनको +स्टर्लिंग +क्यू +सिपाही +मासने +अनुभवी +अपभ्रंश +सलमान +दर्जे +आईसीसी +मेँ +किलोग्राम +इंजनों +खुश +किंग्स +व्यर्थ +प्राप्तकर्ता +सल्तनत +उत +सीख +१००० +अवयवों +जिक्र +दीप +ज्ञानपीठ +कोयले +्र +संदिग्ध +नम +परमाणुओं +मछलियों +मार्टिना +स्कैन +मादक +अधिवर्ष +महान् +लेखांकन +आजीवन +बेला +बाली +दाहिने +उठ +भूरा +कोस्ट +यंत्रों +दलित +पर्याय +प्रस्थान +रेखाओं +ईस्वी +पालतू +गिरा +बरौनी +१९९४ +प्लग +दोहरी +एडम्स +अजीत +सावधानी +थ्री +आशंका +सिल्वर +न्यूयार्क +रोमांस +डॉट +कॉपी +बाप +ईंट +गर्भवती +लाला +घूर्णन +जया +यशवंतपुर +पागल +जागरूकता +कंठ +आईटी +पत्तों +समर्थकों +टूल +राउंड +अन्‍य +ग्रिड +दंत +हिंसक +तार्किक +विशुद्ध +बैठने +मुद्रण +सकती। +पहुंचाने +कंधे +परिश्रम +खोलने +वृत्तांत +सिस्टम्स +धरातल +सांचा +संवेदनशीलता +जिंदगी +पूर्णतः +पुरस्कृत +सराहना +अन्न +मीठा +संतों +डीसी +एंड्रयू +़ +बृहदारण्यक +टुकड़ों +रिजर्व +खंडन +उपभोक्ताओं +टिम +नागार्जुन +श्रवण +प्रविष्टियों +कीटों +रेसलिंग +मैदानों +अभिनव +एनिमेटेड +दीन +बारिश +मॉल +डेथ +क्रान्ति +छोड़ा +पुण्य +प्रतियोगिताओं +देह +माइक्रोफोन +मनाने +किम +हेल्थ +अभिव्यक्त +दस्तावेजों +बेरी +अपहरण +टोपी +बाजारों +संग्रहित +देखो +बहने +भली +चतुर्वेदी +विघटन +रियासत +भवनों +जायेगा। +छठे +अपर्याप्त +वस्तुतः +कार्बोहाइड्रेट +इंजेक्शन +नायर +विद्रोही +बैटमैन +गोल्फ +प्रतिज्ञा +जरा +पीस +बदलती +खरीदा +इंटरनैशनल +झुकाव +लाना +उत्थान +सुसज्जित +अर्चना +ओं +लोड +कमांडर +१९८२ +विद्यालयों +व्याप्त +आतंक +अनियमित +विंग +चंद्रशेखर +जाहिर +त्र +काटकर +गिल +इवान +एंटी +जाता। +प्रदीप +वकालत +परजीवी +प्रणालियां +अहम +केले +चन्द्रगुप्त +इक्विटी +दोस्तों +विद्यापीठ +समर्पण +जिल +तोड़ने +फिलाडेल्फिया +पंचायत +चिड़ियाघर +नर्मदा +विनियमन +परम्परागत +लॉजिक +बधाई +टेक्नोलॉजी +थाई +मापने +सोशल +७५ +फॉण्ट +चित्रकूट +प्राइवेट +मराठा +तुम्हारा +जमशेदपुर +१९६१ +सावली +भूमिकाओं +चयापचय +अभिन्न +किन +खंडों +एलिजाबेथ +ग्रहणाधिकार +ताजा +निक +उदा +प्रयोजनों +पश्चात्‌ +लेखो +गन +नमस्ते +जोनाथन +गोविंद +ऑटोमोबाइल +गोलाकार +गंभीरता +फिनलैंड +प्रबन्धन +पूर्णविराम +एलेक्स +मनोहर +सौदा +स्टाइल +२०१२ +पीट +सामरिक +रेड्डी +दया +प्रा +वॉल्ट +वादा +दरों +उपन्यासकार +तरंगों +स्पैनिश +बरेली +दोस्ती +विकारों +पंक्तियों +दिखायी +ड्रैगन +चाँदी +यश +विकृति +बेसिक +कामयाब +हल्की +अंडा +वास +आर्मी +कार्तिक +श्रे +ब्रह्मचारी +अर्द्ध +ग्रेड +फिल्मांकन +पूर्वानुमान +साइटों +मैत्री +इज +कलाओं +मुद्रित +मिलर +सुंदरता +युवाओं +विंबलडन +मीले +पाणिनि +सहारनपुर +पिशाच +केंडीबार +मृ +डिवीजन +निकलकर +निभाया +मनी +वक्ता +सिग्नल +कैलाश +वाक्यांश +तुर्क +विशेषण +निशाना +अग्रसर +रैंक +१९५० +खाद +ङ +सीटों +कनेक्शन +पेट्रोल +तु +ग्राफ +रण +कंट्रोल +रत +जुड़वां +पूर्वक +बर्बरता +पेरू +एहसास +व्याख्यान +गिल्ड +न्यूज़ीलैंड +कमान +पुत्रों +फ्रांसिस +पुजारी +भरतपुर +कुवैत +मापा +खाई +थकान +रिक्त +अनुमोदन +लेडी +बाएँ +शोथ +अभिप्राय +युवक +स्टेम +नीलम +पीरपैंती +प्रतियां +बहाव +बहार +उत् +अरविन्द +आराधना +मंगोलिया +ध्वन्यात्मक +फ़ेडरर +एयरपोर्ट +बाबर +टेरियर +क्रमिक +विषम +१९९३ +चालित +स्थाई +शीतल +सज़ा +अनुपस्थिति +बफ़ेलो +होस्ट +क्लान +जाएंगे +ऊर्ध्वाधर +द्रौपदी +सूप +रुपया +१९४८ +मीना +शेक्सपियर +बेकार +टैगोर +किताबें +प्रविष्ट +सौंपा +चा +हिंदुओं +ऑब्जेक्ट +अवशोषित +सातवीं +पिन +अयस्क +हाइकु +संस्थाएं +निकासी +भीषण +सल्फेट +बीघा +निपटने +नाते +बाला +रिक +समलैंगिक +आपातकालीन +उष्ण +ईस्टवुड +रचनाएं +बरसात +अमित +यजुर्वेद +प्रशा +संपदा +व्यंजनों +रॉकेट +चट्टान +जार्ज +यहूदियों +विजयनगर +अल्फा +उत्तेजना +प्रायोगिक +अर्थों +गेज +दस्तावेज़ +मानकीकरण +१९७७ +पैक +टेरी +उल्लिखित +काच +परास्त +स्वीकार्य +रचनाकार +अलंकृत +शपथ +अंगूर +अग्रिम +वंचित +कपास +पाण्डवों +दानापुर +घोर +कामना +बह +धोखा +नं +प्रतियोगी +१९६७ +ज़्यादातर +जला +अनुशासन +मसाला +अंडरटेकर +दूरस्थ +सेठी +उसमे +दिलाने +मुक्केबाजी +संस्कृतनिष्ठ +ग्रा +कोकेन +जेरिको +ठंडे +प्रोडक्शन +गर्ल +विराट +गेंदबाजी +पैन +जज +कराची +महानगरीय +स्टाफ +मजदूरों +एनीमेशन +शाखाएँ +वाइन +१९५६ +एंव +वीर्य +सकते। +तलाई +परिपक्व +डेल +अवस्थाओं +सर्प +उन्मुख +भूभाग +युद्धों +रूढ़िवादी +नाथनगर +नामके +लॉस्ट +कॉट +नियामक +वहन +कलम +सम्राट् +परिपूर्ण +इश्क +ड्रीम +कब्र +मोम +अल्बर्ट +दूरबीन +उदर +कानूनों +जवान +इन्हे +सौदे +गान +दामोदर +बेलारूस +श्रेण +दिख +दही +विजयी +घोल +चालीस +मध्ययुगीन +पेंगुइन +समायोजित +मिनी +पीसी +फ़्रांसीसी +सीईओ +भजन +आदत +लिखकर +१९६८ +परमेश्वर +एरिया +कमर +रेशम +मिसाइल +जेन +मोटर्स +उग्र +शैव +डालता +यूनिवर्सल +पिनांग +फ्लैश +विजेताओं +१९८८ +स्वरों +बैंगनी +स्विच +फेफड़ों +सच्चाई +चरित +निकटवर्ती +इंद्र +निवेशक +सिकंदराबाद +पूंछ +समाहित +चित्त +फिट +खुसरो +सार्वभौमिक +खाया +स्थानिक +चिट्ठा +लग्गा +समझे +उपसर्ग +भोग +साइन +क्रीम +पाकर +बोलियों +सका। +१९७३ +सिद्धि +गुलज़ार +आलोचनात्मक +मिलाया +शोभा +ऐनी +दायरे +गईं। +जाएगी। +वाल्व +वैली +रामचंद्र +संध्या +क्रय +सम्बद्ध +जमाने +सहस्रनामन +ध्वस्त +किरणों +कै +आएगा +एस्टन +सोचना +अनुयायियों +जवाहर +मॅट +निभाने +का। +क्रोएशिया +कीर्ति +कल्चर +चालु +ईथेन +इरादा +न्यास +वृंदावन +हिम +गेट्स +ज़ी +वृद्धी +परीचय +डेबिट +कार्निवल +सकी +नालंदा +यो +परेश +कालांतर +मुखिया +डेड +डब्लू +सांख्य +फ्रैंकफर्ट +अजीब +वृत्ति +एफ़ +अबतक +रूट +हिस्सेदारी +आवेश +रू +अंतरण +वॉकर +भवानी +पत्ती +धवन +लाभकारी +मैगज़ीन +ओपेरा +निकलते +परिधि +विलक्षण +बताती +शिक्षित +१९५४ +विद +लेफ्टिनेंट +उल्लेखनीयता +जोली +रतन +डालर +उड़िया +अनुपालन +क्रिस्टोफर +केदारनाथ +डायोड +तराई +गुरारू +प्रतिपादित +धुरी +प्रतिबिंबित +अंग्रेज़ +स्टेज +खलनायक +सुप्रीम +राष्ट्रवादी +स्विस +कैथरीन +अपोल्लोन +हिल्स +प्रवर्तक +रबर +जोड़ों +बॉम्बे +विवादों +वेस्टर्न +मध्यवर्ती +मालिश +दीवाना +गुरुवार +दर्शाती +गतिविधियां +मुख्यधारा +ऋषियों +खिलाडी +औसतन +फ्रेडरिक +पंचम +सूखी +चौड़ा +विधियाँ +१९८७ +बेंजामिन +गली +हफ्ते +डीप +नलिका +पिंक +आईपी +साउंडट्रैक +दिनकर +एमटीवी +अंकन +क्रूज़ +कैफीन +बल्लेबाजी +देसाई +ऑप्टिकल +विद्वान् +हेड +लेंगे। +शिवा +बॉण्ड +कुशलता +क्वांटम +अनिश्चित +कन्नड +विचित्र +रग्बी +रिव्यू +प्रपत्र +निष्पक्षता +आर्कटिक +समस्याएँ +प्रयोगात्मक +जुडना +वाल +ज़िम्बाब्वे +तलाक +व्योम +बिक्रम +अमीनो +प्रतिस्पर्धी +श्रीश +विश्वव्यापी +ग्राउंड +पॉवर +्ड +बहुतायत +मौसमी +उतर +तैनात +चित्रकारी +इंटरफ़ेस +खगोलशास्त्र +गुहा +अपराधों +पाउडर +नॉन +टिप्पणियां +डू +राजन +मेघालय +समृद्धि +सीमेंट +कथाकार +गौराडीह +कतिपय +डगलस +असमिया +आदिम +हज़ारों +मीर +हड़ताल +ज्ञानसे +पोर्टलैंड +्रेणी +संकाय +दर्शाने +अल्लाह +बिल्ली +श्रमिकों +अल्पसंख्यक +मेजबानी +चाइना +ह्रास +फ़ाइलें +गल्फ +राख +औषधियों +१८५७ +आश्चर्यजनक +हाउ +खेतों +विनंत्ती +बढ़े +ग्रीवा +ऋषिकेश +पुनपुन +जटिलता +राज्‍य +लक्ष्यों +डमी +किताबों +जोश +लड़कों +कॉमिक +कैमरून +पूर +हमे +१९८१ +स्पर्धा +दिखाता +कार्यकर्ताओं +वरदान +कराई +अनुकूलित +आचार +गार्ड +सुर +मोर्चा +१९७४ +प्रदत्त +प्रेत +डेवलपमेंट +कार्यात्मक +बालू +पहचानने +आश्रित +रॉबिन +आकस्मिक +कस्बा +मालिकों +उपाध्यक्ष +सिलिकॉन +करेगा। +दूत +संग्रहण +ड्रग +गिरजाघर +मोहब्बत +घूम +चैन +आर्यों +महासचिव +फिलहाल +मेजबान +बसने +१९८३ +पोत +एप्पल +रेणी +मल्होत्रा +चैप्लिन +जीवाणुओं +१९७६ +छाती +ट्विटर +सिकन्दर +बोझ +बैठकर +ऐसें +विस्फोटक +अद्वैत +जीवनकाल +विचलन +कैपिटल +नाटककार +उपवास +बसें +बांटा +मदर +डेस्कटॉप +उन्मूलन +देनी +इच्छुक +नेटस्केप +बैरी +ढाका +ति +तह +एचटीएम +खुफिया +कामों +आतंरिक +सोनिया +स्वम् +ईमान +सार्थक +मेडिसिन +काण्ड +कॉमन्स +अफ़ग़ानिस्तान +शिशुओं +शतरंज +१२४ +गाजियाबाद +सर्दी +स्क्रिप्ट +बैकअप +छद्म +केली +मकर +साधक +मूर्तियां +शिया +सूरी +छाल +अब्राहम +फूड +ञ +पालि +मीमांसा +मीरा +मान्यताओं +कैसा +विनय +जाय। +लेम्बोर्गिनी +इज़रायल +जीनोम +मैक्सिको +एलिज़ाबेथ +नॉट +कंक्रीट +बाधित +यूनिक्स +पाण्डव +स्तनधारी +सिवाय +शारदा +सत्याग्रह +पूर्णत +कठ +बताई +लीड +उत्सर्जित +सुधारों +एंडरसन +उत्कर्षराज +कमला +मैनेजर +डीजल +डेक +शेखर +साईट +संयम +बढ़ाकर +तैत्तिरीय +चमत्कार +कवच +तिल +सप्रू +४०० +सिंधु +सब्जी +पाइप +मैथ्यू +लेग +वादी +काय +नेचर +कागज़ +मंजिल +बेल्ट +प्रोफ़ाइल +गाथा +सीमांत +कीमतों +अंतर्निहित +मुद्राओं +जग +ममता +स्टीवन +शास्त्रों +फोरम +लिए। +विचारक +प्रबंधकोंने +हिंदुस्तान +सिखों +महत्ता +गोदावरी +खुदाबंदपुर +दुबे +सबका +फिक्शन +व्यवसायिक +मरे +चमड़े +कालोनी +सितारों +दुरउपयोग +आयुक्त +नसीरुद्दीन +दाँत +सुलतानगंज +राष्ट्रिय +फतुहा +संग्रामपुर +सोर्स +करेंगे। +सहयोगियों +क्लैप्टन +बीजगणित +प्रांतों +आभासी +दीवान +मानो +गौण +लगाता +डेनिस +सुदृढ़ +एडम +आभास +सदस्योंके +उठता +ल्योन +बंगला +टुन +लिट्टे +नक्काशी +बिंदुओं +हेपेटाइटिस +वामन +जिलाधिकारी +्व +आठवीं +फी +जिन्ना +क्वार्टर +अनवर +विंडोज़ +देखरेख +ऑयल +समजकर +साहित्यकारों +बालकाण्ड +कौटिल्य +जामनगर +अंचल +बिकने +ज्ञानकोषकी +अंगूठी +खींच +एफबीआई +पेस्ट +विडियो +मिलना +लाइनों +भूटान +ट्रेडमार्क +तने +बापकी +अत्याचार +मॉरिसन +मलय +उतने +एंटीबॉडी +मिठाई +१९७९ +कोलेस्ट्रॉल +ेणी +संतुष्ट +बेगम +समझता +पोलिश +फ़ुटबॉल +मीटाकर +तारापुर +धनबाद +एयरलाइन +लाकर +अप्रत्यक्ष +इंकार +लौटे +मानसून +रॉबर्ट्स +फोर्स +चलाते +प्रिंट +ठ +यूनेस्को +धुन +स्टॉप +हर्ष +ऊ +सावित्री +सलाम +फेडरल +जनित +कु +अन्तरिक्ष +विक्टर +इथियोपिया +दुरुपयोग +भारद्वाज +नमः +दांते +शव +सचमुच +मुनिता +चौथाई +सालाना +कब्जे +ओड़िशा +अंतत +संगमरमर +पारिस्थितिक +आरम्भिक +राघव +मैसाचुसेट्स +वीकीपीडीयांके +पुनर्जागरण +मिलक्त +बमबारी +अस्थिर +प्रतीकों +उच्चतर +पतले +अधिकांशतः +चरित्रों +सौन्दर्य +पुरातन +डिज्नी +ड्यूक +कार्यालयों +कमज़ोर +मेट +शेफ़ील्ड +आरएनए +उत्प्रेरक +सेक्शन +संभोग +बास +वापिस +राष्ट्रभाषा +सस्ते +मैदानी +लग्न +भोजपुर +कुण्ड +सघन +फ़ॉर +१९६४ +संस्मरण +फॉर्म +वैद्युत +पाम +परदे +अचल +ग़लती +मंद +बरियारपुर +शुद्धता +परवेज़ +बॉय +जीभ +रोलिंग +बदलना +स्टब +भुवनेश्वर +कोइ +हस्तांतरण +मुकदमे +फैलने +पैरिस +प्रत्यारोपण +अफ़्ग़ानिस्तान +दयाल +कवक +मेमोरियल +एयरबस +इंटेल +फिल्मफेयर +बरोबर +पहुँचे +सावरकर +कुरान +माली +दिखाते +किनारों +निचली +कराती +किस्मों +रहेंगे +रीढ़ +खजुराहो +शियर्र +घात +स्वयंसेवक +मेगावाट +झरने +बाढ +ग्रीष्म +हराकर +ठंडी +गेहूं +ओबेरॉय +फ्रेंकलिन +केंद्रों +शुक्राणु +रूपये +इकाइयां +हटाकर +प्रचारक +रैंकिंग +नीली +क्लाउड +निजामुद्दीन +फर्क +ग्लास +उपजाऊ +गैरी +घुटने +सत्यजित +न्यून +कमजोरी +जोएल +हरीश +जन्मदिन +क्योकि +शिवराज +ख़़ुदा +सिक्कों +पंचांग +मिथिला +१९३० +पेशे +राष्‍ट्रीय +पहना +कॅरियर +प्रतिष्ठान +मालदीव +कलाम +गेहूँ +हुयी +दुष्ट +रांची +टुकड़ा +डाकू +प्रक्रियाएं +सहाय +फ्रंट +निकास +लहसुन +हेलन +डाइऑक्साइड +श्रद्धांजलि +चिप +रोमांटिक +बॉडी +शोक +सितारा +लेनी +आयुर्विज्ञान +फेम +हरित +हीमोग्लोबिन +ब्रायंट +गोला +मानद +कब्ज़ा +व्यू +प्रदर्शनों +डेमोक्रेटिक +फेंक +आंत +समुच्चय +मातृभाषा +महाराणा +रिटर्न +१९५७ +छपाई +उपग्रहों +गोले +जीवंत +रियो +ैं +दृढ़ता +धीमा +गज +यादृच्छिक +विपक्ष +विमानन +कथाएं +चेष्टा +गतिशीलता +लालकुआँ +१५० +दिलचस्प +बैक्टीरिया +पवार +ढांचा +पंप +नूतन +आमन्त्रित +पुस्तिका +चौदह +फोर +सऊदी +सरसों +कैलिफ़ोर्निया +नेल्सन +रकम +६५ +कहा। +नायिका +आभार +अनजाने +एस्टर +एलेन +प्रेरक +जरुरी +वाइल्ड +विशेषाधिकार +नरसिंह +ब्रदर +अधिकता +बर्मी +धाराओं +सिंघल +समीक्षकों +राजदूत +समारोहों +ढेर +सूखा +अर्जेन्टीना +प्लेटो +१९६३ +१९६६ +स्थलाकृति +इरादे +कर्मों +जानेवाली +क्षीण +मरुस्थल +प्रांतीय +स्काई +ऍ +विशिष्टता +एमी +अरबों +इंसुलिन +युवावस्था +कैमरे +नमूनों +जावेद +नक्शे +सु +१९६९ +संकुचन +किय +समीक्षाएं +स्पिन +हवाला +कारावास +शिक्षकों +नाहीं +सर्जन +दाने +उठाते +वरन् +६०० +उठाना +भट्टाचार्य +्ता +डोनाल्ड +संतृप्त +हड्डियों +मिलाने +करनेवाला +निकोबार +दे। +सॉसेज +चेतन +त्रिवेंद्रम +ऐन +करीबी +मासको +पहेली +देशभर +इमेज +मोटाई +सिगार +ऑक्सीकरण +मैनुअल +सूअर +चलना +पड़े। +पर। +पराजय +मंगेशकर +नर्तकी +यज्ञोपवीत +देखिए +द्योतक +आतां +मीठे +भागने +रूपी +परिणत +श्रृंगार +शक्तिपीठ +कुरु +बीजिंग +मुगलों +घटा +सच्चा +वान +पैकेट +चौथान +मॉर्गन +सिवा +इन्टरनेट +वैधानिक +मास्को +भेड़ +रोहिणी +मैरीलैंड +भेजी +मिर्ज़ा +परिशिष्ट +निर्माणाधीन +असे +रॉन +डायरी +द् +संदूक +नक्शा +विराजमान +विकल्पों +प्रधानता +लिपियों +काउण्टी +याचिका +वरीयता +विजू +त्रुटियों +निर्देशिका +चूर्ण +समूचे +प्लस +टाइपिंग +लिखें +दोहरे +प्रथाओं +निर्मल +रस्सी +बेखम +ण्ड +बजाया +मुलायम +हमीरपुर +बंधक +प्रतिरक्षी +आपरेशन +निसान +नरम +वॉल्यूम +ख्याल +क्रैमलिन +इट्स +थ्योरी +शेयरधारकों +सुमीत +अंदरूनी +लवी +माधुरी +खातों +गाड़ियों +सजावट +निपटान +खोलकर +जन्मा +पीएच +अभिनेताओं +चावला +प्रेमिका +स्विट्जरलैंड +ब्राउजर +मोदी +शेरशाह +नमी +चालुक्य +सूफी +उचाई +कोलम्बिया +सू +उठाकर +ग़ज़ल +क्षरण +ग़लत +खरीदारी +दुल्हन +शम्मी +निष्ठा +प्रविष्टि +साम्यवादी +रहेगी +अनोखा +स्तुति +उपलब्धियों +परियोजनाएं +गद्यकार +स्विफ्ट +इंडीज +लौकिक +कोशों +प्रिया +शिष्यों +निकली +बाँटने +टकराव +मौजूदगी +निरन्तर +आकाशवाणी +उल +चीफ +सुविधाजनक +यादगार +समाचारपत्र +म्युज़िक +सूचनाओं +जमालपुर +रोकता +लक्षित +दौलत +स्पेंसर +लालू +पिच +आसवन +ज्वार +पाषाण +संयोजित +अरे +ईथरनेट +मय +आखिरकार +एथेंस +लड़का +धूम +निर्देशों +आहे +प्रयोगकर्ता +झीलों +ज्वाला +नागालैंड +आपत्ति +कांस्य +ख़राब +करनेवाली +विगत +ार्ता +फेडरेशन +वैसी +युनुस +वस्त्रों +श्रद्धालु +अदृश्य +सामर्थ्य +६३ +हार्दिक +मानदंड +बौना +सुनवाई +शॉपिंग +बराबरी +सि +पलायन +लाइसेंसिंग +अञ्चल +जगदीप +गोत्र +देहांत +कार्टर +प्रतिबन्ध +शैतान +फांसी +रीड +बोतल +गोविन्दा +सामंजस्य +फर्श +फिल +यूएसए +गाते +उपक्षेत्र +एंग्लो +तुमने +बुगु +निर्वाह +बताए +दूरदर्शी +धोखाधड़ी +संचालक +तकरीबन +आमिर +स्टारबक्स +जड़ें +रूम +टेल +घोड़ों +नरसंहार +प्रीति +अश्लील +कलश +कैलगरी +८५ +घूमते +प्रवक्ता +वूल्वरिन +अप्रत्याशित +आंकड़ा +ग्रीनहाउस +फेस्टिवल +अनूदित +सर्वे +चेन +छवियों +अधिकाधिक +मिटा +पिरामिड +अग्र +चाणक्य +प्रक्षेपास्त्र +१९७८ +विक +टंडन +मैनहटन +कैच +मौन +टमाटर +सांद्रता +इस्तीफा +करवाने +समीक्षक +फारस +वज़न +प्रवृत्तियों +लुइस +उत्तीर्ण +राँची +वनस्पतियों +अल्फ़ा +रीडर +गेंदबाज +नकद +क्रिश्चियन +राजेंद्र +ऐल्कोहॉल +कच्चा +असोसिएशन +लैंग्वेज +मसाले +ज़रूर +मंडी +सुमन +सनी +कर्मियों +साइबेरिया +कंपन +आवर्त +रुधिर +गढ़ी +चिकन +स्नेह +दत्ता +धर्मग्रन्थ +जौनपुर +मुरादाबाद +पर्वतमाला +लौटा +लाये +गोपी +दाएं +पुनर्जीवित +आगम +प्रतिक्रियाओं +हीरे +तीर +भ्रष्ट +गर्भाधान +परेड +टेलीग्राफ +ऐक्शन +वीरता +आर्क +इफ़्तेख़ार +टार्ज़न +प्रतिलिपि +डेढ़ +सम्पत्ति +गर्व +मदुगु +माघ +मूर्तियाँ +छन्द +कठिनाइयों +अभियानों +तया +चांद +कौषीतकि +वास्तुकार +पडता +मज़बूत +कार्यान्वित +क्लाइंट +पूरब +साइमन +क्षतिपूर्ति +माध्यमों +स्केल +उत्तरदायित्व +पतला +पीटर्सबर्ग +नौका +पटल +समझाने +मिसौरी +आण्विक +एस्पिरिन +म०ब० +जोन +कुक +बाईं +ध्येय +ब्लेड +कृत्य +गार्सिया +तीर्थंकर +सम्मुख +चाहीये +मार्केटिंग +रोमांचक +सहानुभूति +वायरलेस +घृणा +महाद्वीपीय +उर्मिला +बसंत +दवाएं +पकाने +नन्दा +अलवर +निराशा +छिपा +तपेदिक +आदिवासियों +अनुवादित +सातवें +सिक्का +संवत् +सावन +कार्पोरेशन +उर्वरक +राही +ओलिवर +पांचवें +झीलें +डेविल +खां +अन्तरराष्ट्रीय +ब्राह्मी +कांड +जू +गाँवों +भैरव +वीकली +टुडे +बेसिन +बाघों +निरूपित +शाप +मन्त्री +कुंडली +अथ +राष्ट्रगान +आणविक +दांतों +वैश्वीकरण +कहें +शैवाल +सिलसिला +कैरी +१९५५ +काबुल +मोटरसाइकिल +विवश +फ़ूड +अरोड़ा +गिरोह +पते +झरना +अनुमोदित +मांडूक्य +कडियां +मजाक +जरी +विकीपीडिया +होत +जमैका +स्पष्टीकरण +पाद +जरूरतों +एम्पायर +हस्त +संहिताओं +लड्डू +मध्यकाल +वीकी +देवगन +चित्रआकार +विदिशा +कॉफ़ी +सेंचुरी +होते। +मित्रता +कठोरता +वज़ीर +रूपक +अश्वेत +राज्यसभा +आभूषण +चैम्पियन +उपरान्त +लार्ड +नोबल +प्रविष्टियां +बस्तियों +िए +नानक +बर्ड +पड़ेगा +लिंकन +बहाल +९६ +बंदूक +रेट +अयोध्याकाण्ड +महाप्रभु +ग्राहम +नल +डार्विन +ग्रेटर +कारखानों +वाट +सोचने +हिम्मत +बढाने +लेबर +गिना +पूर्वजों +बेचे +हरिवंश +श्वेताश्वतर +माइक्रो +सीनेट +पु +दिए। +नकदी +ब्रॉडबैंड +फ्रेमवर्क +दाग +ँ +ग्लूकोज +आश्वासन +दरगाह +बीवी +किस्में +अभिकल्पना +इन्दिरा +रामकृष्ण +शेन +वार् +पॉइंट +झांसी +चेल्सी +वाइस +महानतम +विश्वसनीयता +चूना +डिस्प्ले +प्रकोप +सदाबहार +लोहिया +मीनाक्षी +र्ता +हावर्ड +इस्लामिक +कौशिक +भुजा +पहलवान +जादुई +अर्थशास्त्री +मनमौजी +शायर +डिजाइनर +समयावधि +सपनों +मर्यादा +रेकी +दरवाजा +उत्त +बारूद +हे। +कुर्सी +जन्मजात +लूट +नियोजित +नियोजन +तेरह +हिंगू +मैडोना +्म +सोमनाथ +पीपुल्स +मुद्रास्फीति +बजाने +काँच +तैराकी +साबुन +अभ्यारण्य +बढ़ाते +तन +उ०प० +महासभा +अहंकार +मांसपेशी +निर्वात +खतरों +जाओ +हैपलोग्रुप +हैवीवेट +आरोपों +सितारे +विनियमित +सब्जियों +शीतकालीन +पार्टियों +शिला +रसवात्सल्य +पश्च +चॅक +लड़ाकू +तुझे +रॉस +क्लोरीन +विषाक्तता +मानों +वाक्यों +प्रतियों +उल्टी +हैरिस +निकालना +अक्षम +सिंधी +विशेषत +आस्ट्रिया +अवगत +साधारणत +मार्क्स +चीता +व्यवसायों +डालना +क्षितिज +पालिका +उल्टा +कारखाना +सैयद +कमेटी +भला +फेयर +फ्लू +रामभद्राचार्य +स्प्रिंगस्टीन +पिस्टन +संदर्भों +जनसँख्या +आनुवांशिक +उषा +ज़रिए +सीमाएं +घर्षण +प्रौद्योगिकियों +दिखती +मतों +लत +बैले +एक्यूपंक्चर +फोटोग्राफर +क्रिकेटर +अनीता +इण्डिक +आधिपत्य +सतही +गुफाओं +प्रतीकात्मक +नशीली +शुक्ला +शेंगेन +फास्ट +बुल्गारिया +महंगे +सनम +नज़रिया +हेलो +माथुर +सेवाएँ +रिपब्लिक +सेंसर +सर्कल +बिज़नेस +सेकेंड +असत्यापित +कैनेडी +दुर्भाग्य +विनायक +कारगर +प्रस्तावना +अरस्तू +बताये +गृहयुद्ध +तर +शीट +गिरफ्तारी +वार्मिंग +इसीलिये +महासागरीय +खनिजों +पेरी +जटिलताओं +जीती +लॉरेंस +पूर् +साठ +सूडान +एबीसी +संस्थाएँ +सिएटल +आख्यान +बोल्ट +खानों +यीशु +परिलक्षित +अभिमन्यु +दैत्य +पॉलिन +निकाली +राष्ट्रवाद +खोजा +साक्षी +पारदर्शी +७२ +जाएँगे। +फुलवारीशरीफ़ +वैवाहिक +जुलती +सेंटीमीटर +ईश +नाभि +रेशे +संकीर्ण +नेताजी +टीके +एड्रेस +विश्‍व +चार्टर +बीना +मधुबनी +पियानो +हेक्टेयर +मंगलौर +फलत +सीने +संभाल +अलास्का +स्पाइवेयर +सुलोचना +नीलगिरी +तैसें +उभरा +राजकोट +मिलीग्राम +फाइलें +हिब्रू +बैग +आटा +होतीं +शंख +मजबूती +सीना +उनमे +आज़मी +अभिलेखों +रोचेस्टर +पुष्ट +दाहिनी +क़रीब +कार्लोस +जादूगर +मैनें +अवरुद्ध +झ +सस्ता +लैंस +टैक्स +बैड +इशारा +पढ़ना +विलायक +ज्यामितीय +एनी +पत्तियाँ +बहामास +पढ़े +कारें +प्ले +चश्मे +प्रतिकृति +झंडा +उभरते +स्टेनली +डेव +बेनोइट +वीवरण +निकालकर +तदनुसार +बुल +अवशेषों +कच्छ +बताना +एंटरटेनमेंट +राज्यमंत्री +मायने +परख +बराक +मिले। +ढाई +प्रतिफल +क्रियाएँ +स्थूल +बसु +आकलनकर्ता +गुट +अथर्ववेद +संस +केट +टीमें +सैंडविच +लेखिका +कैबिनेट +जुर्माना +मारी +मिटाने +परवरदिगार +अंदाज़ +मूल्यवान +लिखता +संचय +साउंड +युवराज +विकिक्वेट +स्कूली +नशे +प्रयोक्ताओं +पापों +पित्त +बहल +विकलांग +डूब +किंगफिशर +कार्यक्षमता +टेड +वगैरह +डाउनटाउन +अपूर्व +कलन +थाली +साढ़े +पीली +कृष्णन +९९ +प्रोसेसर +एमआईटी +तंतु +राजेन्द्रनाथ +छीन +स्टैंड +मुरलीधरन +कंप्यूटिंग +सॉफ़्टवेयर +चुप +एसी +प्रोटोटाइप +चुनने +राजी +अंडर +सुविधाएँ +शरत +हरेक +मु +विमानसेवा +पड़ी। +मूर्तिकला +जुडी +संविदा +बाय +बढ़ाता +रुख +लोकगीत +समायोजन +अमेरिकियों +कैन +जीप +नक़ल +तेथ +श्रृंखलाओं +ज़माने +मशीनी +एक्सरे +आह्वान +अलाउद्दीन +प्रत्याशी +बिन्दू +रहस्यमय +रेखाएँ +पिया +पत्रकारों +प्रतिभूति +उमर +स्वच्छता +घनश्याम +विषाक्त +दबाने +अध +जोड़ते +वायुमंडलीय +ठंड +बर्फ़ +फीसदी +लेआउट +दरिया +क्लबों +छत्रपति +असुरक्षित +नागरकोविल +कार्यो +सौभाग्य +परवाह +महंगा +युगांडा +नवाचार +रामचन्द्र +जुलता +निष्कासन +गर्भगृह +वेदांत +निराश +शोधकर्ता +पड़ोस +मौके +असफलता +गय +जयसिंह +हैदर +संगीतकारों +दीपावली +मूसा +समाजों +मानवाधिकार +जोड़ना +ट्रम्प +एंजाइम +गांधीजी +चुनी +१९३१ +डिवाइस +समझाया +हजरत +प्रमोद +कुशीनगर +बर्मन +गोलार्ध +मोह +पढ़ते +गवाह +मर्सिडीज +आमन्त्रण +कतर +एकाधिकार +टायसन +ऑपरेटर +बलराम +होंगी +आये। +नानी +अलीगंज +जहा +विद्युतीय +जड़ों +अपराधियों +द्वि +जौ +बंदर +बढ़िया +रेसलमेनिया +इलेक्ट्रान +फिलीपींस +प्राप्‍त +क्यूंकि +विकलांगता +जिल्हा +सींग +बछवारा +हावी +गाए +एकेडमी +वाइरस +सवालों +फोटोग्राफी +हाइड्रोकार्बनों +कोबेन +स्वर्गीय +यार +कोशिकीय +बखरी +उतरने +गैलापागोस +विलास +हंगल +आज़ादी +अंशों +सिलेंडर +केन्या +अप्रयुक्त +धर्मनिरपेक्ष +प्रबंधको +ताजिकिस्तान +पुनर्गठन +स्टडी +समा +ीर्षक +दोषों +आईएसओ +कोला +रेलमार्ग +जहाज़ +बहाने +थोक +जानबूझकर +बेकेट +कमाने +खाल +छावनी +डबल्स +पहनते +आल +मनोरंजक +फ्रैंकलिन +भ्रमित +सुज़ुकी +वॉर्स +वर्जित +अनशन +वुड +अपवाह +श्राफ +एवेन्यू +नाप +पर्पल +हुक्म +भूगोलवेत्ता +दबा +उभर +शंघाई +पैकेजिंग +नॉटिंघम +वर् +भूमिकाएं +जनमत +सीखा +हलसी +ग्रैमी +सकेगा +वार्त +१९४० +डैन +कलंकीत +कारन +नहरें +पडा +२५० +दर्रा +ओड़िया +कांफ्रेंस +तिमाही +फिल्टर +ग्राफिक्स +लाइक +रोज़ेज़ +केक +आंदोलनों +ऑ +७६ +गाँठ +सेन्ट्रल +करों +पोजीशन +ट्रांस +अस्पतालों +प्रचारित +सपोर्ट +समितियों +एस्टेट +संकुचित +दिखते +जलन +उत्तराधिकार +प्राध्यापक +सूक्ष्मजैविकी +मिर्जापुर +रैखिक +नैनोट्यूब +वीजा +गुजरती +मालाबार +निगमों +पोरबंदर +ट्वेंटी +नवरातिलोवा +्त +७७ +जासूस +अभूतपूर्व +नवागन्तुकों +वर्मनने +मिसाल +गरीबों +फूट +फ्रेंड्स +फोकस +शत +तैसा +गे +एनिमेशन +मेवाड़ +स्ट्रीम +१९५८ +प्रमुखता +पेशियों +ऋ +जलाशय +चलाता +क्ष +हेमामालिनी +बैंगलोर +सुनते +लैंगिक +सुदर्शन +रमन +नाइट्राइट +टिहरी +कैदी +कस्टम +खरा +चिप्स +अनगिनत +महाकवि +आवश्यकताएं +कमिश्नर +रचा +श्रेणीबद्ध +रवाना +बूटी +वाँ +खिलौना +गर्ल्स +कमांड +चलाना +संसद् +तस्वीरों +प्रतियोगिताएं +शाखाएं +निरूपा +पावन +रसायनों +औषध +वीणा +साजिश +बुजुर्ग +एनालॉग +मकबरे +परीक्षित +धोनी +नबम्बर +प्रबंधित +सैल्मन +आकारों +सवाई +माईस्पेस +किण्वन +आईबीएम +प्लांट +गुजर +शर्ट +ल०व० +विकिसम्मेलन +पंद्रहवीं +मातृ +ीय +भिक्षु +फ़ोटो +अपडेट +दोहरा +क्रेन +बाइबल +पहुँचाने +दाएँ +निःशुल्क +नाइट्रेट +एरनाकुलम +पहुंची +सक्रियता +लियोन +मंडली +लोकपाल +निकायों +आधुनिकता +वसूली +नारा +राना +गॉर्डन +दांव +चन्द्रशेखर +हार्बर +सलाद +मंत्रिमंडल +रसेल +तब्दील +आशिक +विधायक +बची +१९४९ +जैकी +पनीर +वेशभूषा +वेल्श +पसन्द +चुपके +चि +अतरी +परतों +मधुबाला +सांप +पहुंचता +रोकना +पकड़े +१९२० +पीतल +नास्तिक +नासिर +किस्मत +लाइनें +प्रतिबिंब +माफी +मार्क्सवादी +एथिलीन +कोशीश +जगद्गुरु +जीना +वाह +प्रेसीडेंसी +सीनियर +पूर्णता +फिजी +अत्र +होनेवाली +बिड़ला +रिवाज +उपनगर +ईथर +बद्रीनाथ +शीर +ु +रेखाचित्र +महेन्द्र +त्तराखण्ड +सूत +सीढ़ी +भट्ठी +भण्डार +व्यवसायी +सेवानिवृत्त +गुणांक +जामा +शेखावत +८०० +क्रूर +घिरे +फलक +अम्बेडकर +लगन +बिन्दुओं +मुकुट +वेस्टमिंस्टर +इमाम +बर्नार्ड +मृदा +बायें +शासकीय +ख़िताब +षड्यंत्र +रेखीय +स्पीयर्स +जीमेल +डिस्ट्रिक्ट +अल्बानिया +राशियों +लीन +गवाही +जस्टिस +स्पेलिंग +बाँटा +कुश +मकसद +अटल +मेटा +सर्पिल +रास +पंखों +संवेदना +हलचल +संकल्पना +३००० +मक्खन +जॉर्डन +मिथ्या +समीकरणों +फेफड़े +पैतृक +प्लैटिनम +एंथोनी +वीनस +बदली +७०० +पीढ़ियों +सूरीनाम +स्ट्रॉस +क्रियाशील +विक्रेताओं +मोल +लड़ते +रहो +वक्तव्य +उत्पादकता +मॉनिटर +पुरोहित +मालवीय +समझी +रूपांतर +पनामा +प्रतिरोधक +समस्तीपुर +वेधशाला +पीड़ितों +देवदास +अवधारणाओं +फर्ग्यूसन +ग्लेन +चौड़े +फाँसी +आंत्र +त्रि +फेरारी +पदार्थो +शंकु +दादी +पुनरावर्तन +विवरणों +हलके +दरार +मीन +गिरीश +चुनें +निभाता +१९४५ +स्पीड +यथार्थवादी +तोप +किट +चिन +पुकार +मॉडर्न +कड़े +कावेरी +आई। +तूफ़ान +द्योल +पिकनिक +बायर +गिटारवादक +एकांकी +लगाव +सस्ती +खुदा +बढ़ाना +संयंत्रों +निष्पक्ष +अरविंद +पकड़ा +गिने +शहद +मिथक +मून +दीया। +डेविडसन +ग्राफिक +प्रियस +अनिष्पक्ष +कराटे +सुनहरा +सचिवालय +फ़ॉर्मैटिंग +वाल्टर +स्तंभों +आटे +स्मार्ट +मेक +घाटियों +मेसन +अनोखी +सदाशिव +प्रतिजन +रुझान +प्रवीण +कपिल +विधवा +रुकावट +टर्नर +त्रिभुज +मंत्रियों +तत्पश्चात +चूहे +म्हणे +कॉलेजों +उत्कीर्ण +र्षक +घेर +नेपोलियन +सुलझाने +विभिन्‍न +आइस +भित्ति +गला +वैधता +लुकास +उड़ +स्टैंडर्ड +खिलौने +युगों +लिवरपूल +लिप्यन्तरण +खड़ीबोली +पर्दे +शत्रुघन +अग्निहोत्री +वर्चस्व +बहिष्कार +एडवेंचर +यूटोपिया +ऐसीटिलीन +विचरण +कल्पित +मुख्‍य +अपनाई +गंधक +ेश +किशोरावस्था +लेज़र +कैम्प +टाई +तुरन्त +अर्धचालक +मॉरीशस +साँस +संगठनात्मक +बहुवचन +तले +कभार +पुकारा +चाँदनी +१९५९ +जिनपर +नागराज +मोनिका +्तराखण्ड +६४ +सुखद +आवारा +पानदारक +एशियन +चैत्र +कैश +हथेली +नैनो +झूठा +विस्थापन +प्रमाणीकरण +इसराइल +आठवें +सागरीय +प्रजापति +किसने +सभ्यताओं +अर्ल +स्वराज +१९३६ +चन्द +बसाया +महानदी +वर्ड +रिसाव +चम्मच +प्रशिक्षक +रघुनाथ +एमिनेम +सुधा +पंद्रह +काटा +चादर +जैम +निकटता +उमा +भयभीत +फ़ॉर्मूला +शाहजहाँ +इंजीनियरों +वर्दी +ूर्व +आनुवंशिकी +घेरा +हाथियों +रैली +संलयन +आवर्ती +क्रियान्वित +दशहरा +वृद्ध +विरोधियों +बोवी +भूविज्ञान +पो +होय +ऋणात्मक +लाते +अण्डा +सम्बंध +बोट +इटावा +साहसिक +आपातकाल +टायर +साइप्रस +चूहों +विधियां +षक +जोड़ती +त्रिज्या +मनाते +बांड +प्रतिबद्धता +आइसलैंड +उत्तेजक +पैमाना +बांद्रा +गर्भपात +पब्लिशिंग +अन्यत्र +बम्बई +महीन +पूंजीवाद +क्रियान्वयन +संगीतमय +दैट +दाखिला +आवश्यकतानुसार +मेनन +स्प्रिंग +ख़िलाफ़ +शक्तियां +अंतरजाल +यूक्रेन +अस +वर्जिन +मानती +सद्भावना +आंद्रे +वल्लभ +इजरायल +अध्यायों +मजदूरी +उत्तरोत्तर +प्रभात +श्रोताओं +हलन्त +हीरोज़ +कुँवर +अलेक्जेंडर +कराया। +वोल्टता +एवार्ड +गोल्डेन +पनडुब्बी +स्टेरॉयड +सचदेव +ट्रू +सिरों +मारकर +माउंटबेटन +बार्नस्टार +कोका +मन्दिरों +फ़िल्मी +धाराएं +सांप्रदायिक +आत्मसमर्पण +समांतर +प्रीमियम +विनोबा +बहुराष्ट्रीय +डैविल +धागे +दसवीं +बार्कलेज +बिरला +प्रतिमान +कक्षाओं +हैना +अमूर्त +मंज़िल +निरंतरता +निपुण +ढोल +१९४२ +मनोरोग +डेप +यूनीवर्स +डाला। +क्षार +शूट +बेसबॉल +बीएमडब्लू +शौकिया +प्रागैतिहासिक +ारत +मुझ +गुफाएं +वर्क +अनन्य +सुरुचि +छा +बग +कर्क +उठे +हक +प्रशस्ति +कलाई +जयप्रकाश +महीना +चिंतित +दूषित +नियोक्ता +स्वदेश +यत्र +पूछताछ +विस्थापित +खोजों +लाभान्वित +कांट +पहचाने +बॉर्न +प्रवृति +रेजिमेंट +थिंक +ऐश +स्थगित +सीटी +विशेषतः +बुराई +रुद्रप्रयाग +सुषमा +८४ +बनी। +जनजातियों +रेख +अन्याय +संवाददाता +कच्ची +बोलियाँ +एडी +पेंटिंग +जिन्हे +रति +स्टार्च +अबू +पहुंचते +अम्लीय +सैर +बीबी +इंटरटेनमेंट +वानस्पतिक +बेशक +श्लोकों +आपात +नन्द +मेज +तृतीयक +टॉड +प्रसिद्द +रांगेय +कैप्टन +बीन +चाह +बनीं +पोटेंशिअल +असित +सीरम +कैदियों +चुनरी +ज्येष्ठ +अगासी +जस्ता +थेरेपी +मैथुन +लोकल +सूर +यात्राओं +गेंदों +चढ़ +गाजीपुर +भागीदार +राहु +सजाया +उत्पीड़न +ओमान +बायीं +तुर्कमेनिस्तान +फेस +धड़ +वन्यजीव +चीज़ों +अनमोल +निभाते +जैसें +मुंशी +सुपरमैन +बहारी +विकिस्रोत +दुग्ध +लगीं +गुड्डी +माउस +आग़ा +गोरखा +कसौटी +अल्फ्रेड +पूज्य +वोक्सवैगन +ख़ +तना +ट्रैफिक +खंडित +मो +्षक +नायडू +शबाना +आतंकवादियों +जाली +लिविंग +पुनरावृत्ति +एक्सप्लोरर +फ़ोर्स +श्रोता +राजनयिक +तुल्य +डेज़ +फ्रेड +परोसा +ची +फोर्ब्स +कण्ठ +बर +कीन +प्रतिभागियों +सुरेन्द्र +फाइलों +निद्रा +बंगलोर +संभावनाओं +बॉस्टन +हार्ले +प्रोसेसिंग +नासिक +वाइड +एनर्जी +पकवान +दारा +कम्पनियों +थोडा +नवादा +सप्त +शाहरुख़ +तांबे +नग्न +अंजाम +तुग़लक़ +बचाया +बैनर्जी +बादलों +संप्रेषण +लैरी +९८ +डायमंड +शुभारंभ +अपार +देगा। +खिड़की +जश्न +मैनपुरी +विधाओं +६६ +भ्रामक +तंत्रों +सीरिज़ +लहरों +पुस्तकालयों +विनाशकारी +जैज़ +खतना +बस्तियां +उत्कर्ष +कोशिकाएँ +नेहरु +मेड +लिखा। +धनात्मक +चॉकलेट +मनोरमा +१९५२ +बार्सिलोना +लावा +फैजाबाद +वाटर्स +प्रात +बढ +विद्युत्‌ +मसलन +मसूरी +अचार +सटीकता +कीर्तिमान +ब्रिगेड +प्रकाशीय +कं +उत्साहित +नौकर +वारिस +नामदेव +हेमंत +ईंटों +इंटेलिजेंस +सपाट +गोबर +पर्सनल +कार्यप्रणाली +असीम +कॉलम +झाँसी +प्रबन्ध +करिश्मा +मिसिसिपी +ब्रेकिंग +निभा +खाती +दावों +वोल्ट +आप्रवासी +धड़कन +बिताया +प्रशस्त +बीटल +महलों +निलंबित +एबरडीन +लूथर +बारबरा +खण्डों +यूज़र +बर्बाद +उन्नयन +वेल्लोर +राजबब्बर +समन्वित +लोप +हल्दी +बुद्धिमान +किराए +८८ +अनुसन्धान +जेड +बादाम +पासपोर्ट +खुलता +माकपा +प्रमाणन +वृन्दावन +सड़कें +बम्बोर +पोषित +सिन्दूर +अमोनिया +श्रुति +उठाए +तकनीकें +पदवी +ऑर +गड़बड़ी +आमाशय +नरक +मुहैया +गुजरने +संग्रहीत +जेसन +सीक्रेट +असिमोव +कन्याकुमारी +र्व +झारखण्ड +उत्तराख +परिपक्वता +८१ +कौरव +ज्ञानकोश +रंगोली +गान्धी +ध्वनियों +कनाडाई +छिपे +म्हणोनि +प्रणालियाँ +विखंडन +गुम्बद +किक +बख़्तियारपुर +वश +नैस्टर +शा +बर्गर +फ़ल +हुवा +बिक +अटलांटा +रोधी +बचना +घा +लुटेरे +मेगाडेथ +बीजों +वियना +चिन्तन +अय्यर +सोम +चिन्हित +रेफरी +सहिष्णुता +छोड़ना +मसले +उद्यमी +जुलते +स्लोवाकिया +साख +गोकुल +दरबारी +बढ़ाई +देखा। +खूबसूरती +पैसेंजर +फ्लाइट +हवाओं +पीढी +नौगांव +आगंतुक +लिली +उत्तरकाशी +गुरुत्व +सिखाया +पियरे +शीर् +सिक्स +डब्ल्यूडब्ल्यूएफ +प्री +दशमलव +तेतिहा +क़ानूनी +धृतराष्ट्र +हाजीपुर +आर्यभट्ट +प्रायोजक +सन्दूक +सांसारिक +फलित +नामका +भट्टी +पांव +त् +सम्पादित +शोधन +विश्‍वविद्यालय +कंस +पम्प +चलाई +करतीं +ईपू +मिज़ोरम +हीन्दीवीकीपीडीयाके +दायें +अयोग्य +मृग +आनेवाले +लीबिया +लेसनर +तुमको +मेहमान +मेलबोर्न +स्‍थापना +थर्ड +इमेजिंग +सम्मेलनों +अमज़द +लगेगा +बेड़े +इब्राहिम +पक्का +पलट +मानदंडों +त्रिनिदाद +साम्राज्यवाद +परीक्षक +पड़ाव +पहाडी +जुड़ना +विलोपन +सिलसिले +खींचने +चलाए +जानकर +बेली +विचारकों +पितामह +नॉर्मन +डिपार्टमेंट +स्वादिष्ट +सुगंध +पेस +समता +गोंडा +लेस +फैलाने +सैनी +पिज़्ज़ा +रामधारी +तांत्रिक +साध्य +जन्मभूमि +संभालने +आकृतियों +अख्तर +हेल +तवी +पांडवों +मीलकर +उत्खनन +स्वैच्छिक +दिल्‍ली +श्रीलंकाई +दोहराया +मुखर +टोयोटा +रिपोर्टिंग +निषिद्ध +गंगोत्री +डिक +परमार +बार्न +फ़ैल +इण्डोनेशिया +अकादमिक +ड्राफ्ट +भूकम्प +दिखलाई +धर्मशास्त्र +किये। +क्राई +बकरी +पाया। +न्यूर्क +जौहर +कामयाबी +फौज +सुव्यवस्थित +डॉक्टरों +बढ़त +क्योटो +दर्जन +जुटाने +कलर +हिन +ग् +प्रेरण +एथलेटिक्स +कपाल +जस्टिन +पश्तो +कुंभ +थाइलैंड +बांस +ँव +कनेक्टिकट +जोरदार +बेरोजगारी +सुल्तानपुर +बिस्तर +खींचा +प्रौढ़ +एल्बमों +कड़ा +मानकीकृत +सामंत +वृहत +परबत्ता +दुल्हिनबाजार +सोल +चना +भोसले +सप्ताहांत +विशालकाय +धोने +भस्म +रहनेवाले +टेघरा +अमीन +फ़्रान्सीसी +शल्यक्रिया +ग्रांट +१९२१ +सांकेतिक +फार +मदिरा +पोर्शे +परिधान +यूरेनियम +जिन्होने +बलात्कार +परीक्षाओं +उत्तराखण +ट्रेक +जन्में +पि +पवित्रता +इंतजार +लाता +वादन +महत्‍वपूर्ण +ब् +अल्जीरिया +सीखना +नगण्य +खत्री +चतुर्भुज +बाक़ी +१९०० +टेन +करोड़ों +स्क्रीनिंग +टूटने +प्रजातियाँ +आन्तरिक +कहो +अपघटन +देशो +ब्रेट +पहुँचे। +परिस्थितियां +म् +पुनर्निर्देशित +नतीजा +साइबर +पैदावार +स्याही +नंदा +सैटेलाइट +न्यूट्रॉन +रोनाल्ड +देवेन +चमकदार +जिगर +योजनाएं +प्लेग +अध्यात्म +विदेशियों +सच्ची +चट्टोपाध्याय +दार्शनिकों +परिसंपत्ति +ओक +जाये। +इलाक़े +तुमसे +बिखरे +व्यवहारिक +तराखण्ड +मऊ +प्लूटो +दुखी +ताम्र +इल्म +फैलता +समतुल्य +किरणें +पेव्ड +हुमायूँ +सईद +भाभी +अंडमान +चूक +रणधीर +इब्न +बो +बॉस +उपराष्ट्रपति +वू +स्पीकर +च्वाइस +स्टुअर्ट +प्रदाताओं +कार्गो +डेन्जोंगपा +महज +सीतापुर +लगान +पेंटल +अनुसूची +हस्तियों +बहू +कुलीन +किनारा +कुलकर्णी +धनराशि +छुटकारा +बगीचे +शिरा +देखती +हीन +मद +बीट +वर्धित +संभाला +नीच +बेंज +जम +जप +गियर +एफएम +आरोपित +सोन +ठाकरे +स्टीवर्ट +पाण्डेय +आयकर +स्वार्थ +जन्मतिथि +विज्ञप्ति +न् +रीज़न +म्हणौनि +वत +रणनीतिक +शु +अत्याधिक +खालसा +प्रान्तों +कैलोरी +१२० +विनिर्देश +अमावस्या +गोलियों +जिन्दगी +अशुद्ध +स्मिता +वार्तालाप +दाखिल +काउबॉय +एक्टर्स +टेनेसी +पराबैंगनी +घूमती +खुलने +हिरण +संचारित +लैला +लाभप्रद +प्वाइंट +नर्तक +जासूसी +मानवों +शाहपुर +गुड़िया +अनुग्रह +९५ +विश्लेषक +जहांगीर +ही। +त्रिशूल +मनीश +स्पैरो +कोंकणी +सेक्टर +रिवर +यथासंभव +साम्यवाद +हडसन +सेव +चैंपियंस +बसों +किपलिंग +लड़ +विकिपिडिया +घनिष्ठ +दीवारें +टॉक +क्रमपरिवर्तन +म्यूजियम +प्लान +केसरी +फैमिली +लातिन +आर्द्रता +घाना +अस्मिता +बट +छड़ी +कात्यायन +पुनर्जन्म +ग्लूकोज़ +अज्ञेय +फिटनेस +प्रतिभाशाली +कलाकृतियों +हीलियम +दोहा +अंधेरे +तापीय +मल्टी +टीकू +आर्किटेक्चर +किन्हीं +सत्यापन +बलूचिस्तान +लारा +फिशर +रिहा +देवा +गॉड +सुनाया +वेश +सबौर +प्रशान्त +चिंताओं +तंजानिया +जाएँ। +संयोजी +साँचों +पूछ +श्राद्ध +मात +टैंगो +अमरनाथ +जानकार +कृषक +पेले +गुणसूत्र +पहियों +जिज्ञासा +टिप्पणियों +कहलाने +मोनोक्रोम +हीरालाल +बारीक +देंगे। +चित +छोड़ते +क़ुरान +यमन +आदर्शों +अपन +संघटन +विषयवस्तु +आमदनी +स्क्वैश +दर्शनों +सूरदास +मातृभूमि +फेंकने +१९५३ +दोस्ताना +लैण्ड +योजन +लॉर्ड्स +अभि +यूएफओ +विध्वंस +भूपति +नदाल +प्रतिभूतियों +ट्री +टॉमी +संप्रदायों +६२ +वैयक्तिक +भेजता +मल्टीमीडिया +आयामी +गुड़ +ट्रॉफी +आविष्कारक +हुईं। +लॉयड +चिह्नों +बिशप +साँप +हेवी +पर्यवेक्षण +ाद +चिन्ता +आलम +चौबीस +तलसानिया +ताड़ +दायित्वों +गलतियाँ +रिएक्टर +चंद्रगुप्त +सप्तम +नाइजीरिया +स्थ +गुदा +त्यों +मिटटी +कर्ज़ +बॉन +६७ +तात्कालिक +गार्डनर +अनूठा +ओड़िआ +रीटा +विश्लेषणात्मक +देवरिया +नेवर +्दी +चिकनी +डेटिंग +पोर्टेबल +उगाया +बालकों +स्पोर्ट +१९५१ +द्रोण +आवंटित +गांगुली +नार्वे +यन्त्र +देशपांडे +८२ +प्याज +एसएमएस +तूं +संहार +अलौली +शकीरा +छू +देवकी +गोल्डबर्ग +मशीनें +कर्ज +चढ़ने +हिमानी +बतलाया +बंगलुरु +पढाई +नेम +फ़ैसला +प्रीतम +हिरासत +मुबारक +खा०प० +डिप्लोमा +कॉनकॉर्ड +समझकर +संदर्म +एलर्जी +नितांत +उठने +मेरिल +गोपनीय +सुगम +क़ी +ाखण्ड +युग्म +बढ़ना +अबाउट +वहा +चला। +वतन +बाधाओं +हुबली +हीट +फुल +अनुपस्थित +येल +भावुक +पित्ताशय +टिन +लड़ा +रॉकी +नोल्स +वमन +मारना +ब्लाक +बहोत +कूपर +करो। +प्रमाणपत्र +यूट्यूब +सम्मलेन +रनवे +पूँजी +मंडप +पोटेशियम +उत्तरांचल +ठेठ +ओडिशा +पल्लव +इन्दौर +तर्ज़ +ः +अनूप +आओ +कुख्यात +बांसुरी +अनुपयुक्त +मगरमच्छ +स्पा +सेबी +चाहा +धमनियों +बारें +अश्व +हस्तिनापुर +ईसाइयों +आइपॉड +१०१ +इराकी +रयान +ाल +हिमनद +अमरावती +गिरी +पूछने +प्रेषित +घटाने +डिस्कवरी +पथरी +रायबरेली +नायनमार +बढती +मिलेगी +किशोरों +साड़ी +शिवजी +पुनर्वास +सहरसा +कैरोलिना +आरण्यक +असुर +लौंग +समाविष्ट +ज़ोन +फकीर +बियोवुल्फ़ +राइस +थेफ्ट +लू +ल० +अज़ाब +वेबदुनिया +ल्यूकेमिया +मार्गरेट +संन्यास +रनों +सुनहरे +सबने +विरल +पॉलिसी +रश +कैमरों +एंजेल्स +प्राणायाम +सेलिब्रिटी +कण्डारस्यूं +शाश्वत +जुलूस +विश +जेफ +मतानुसार +उत्पात +मामा +७३ +रहीं। +क्लिंटन +विकिया +आइवी +लिस्ट +आबू +गोमती +पुरुषोत्तम +उत्तराखण् +हेराल्ड +दांता +पद्मश्री +शर्तें +कटिहार +स्विंग +उत्तरार्द्ध +सिंगल्स +केदार +रघु +वासना +पहुँचकर +न्यूकैसल +मांगी +अमल +सल्फर +छोड +अंजना +कंप्यूटरों +ढ +विलिस +सीकर +जुड़ता +प्रसन्नता +प्लेटफॉर्म +गिरि +उछाल +करीना +जहर +मासके +सम्पदा +चौदहवीं +ढाईज्यूली +साओ +कोचीन +श्रावण +अर्पित +मासूम +टीन +स्पार्क +कट्टर +चढ़ा +ट्रिब्यून +होंडा +कीये +एंटोनियो +लैस +किससे +एकजुट +पतंग +१९२७ +टीकाकरण +मूक +असरगंज +सतहों +नाल +आयताकार +चढ़ाव +कार्यशील +दक्षिणपूर्व +माथे +मर्फी +गुजरता +सफ़र +स्लोवेनिया +रिले +कॉमन +जमाव +कुलभूषण +्स +क्रोम +उजाला +मूत्राशय +इस्राइल +नाड़ी +ंवत +परगना +लैंडिंग +रेलगाड़ी +कलाँ +उद्धार +ज़रिये +शॉर्ट +टिक +डिज़नी +फिल्माया +मरते +निष्कर्षों +उलट +भीमसेन +चक्रों +मात्राओं +प्रणाम +सिम्बियन +संस्थागत +बिताने +आंग्ल +बिजनौर +फायदे +खेड़ा +कार्यभार diff --git a/third_party/harfbuzz-ng/src/src/Makefile.am b/third_party/harfbuzz-ng/src/src/Makefile.am index 225444e326c5..56dc32d9a78a 100644 --- a/third_party/harfbuzz-ng/src/src/Makefile.am +++ b/third_party/harfbuzz-ng/src/src/Makefile.am @@ -47,6 +47,9 @@ HBLIBS += $(GLIB_LIBS) HBDEPS += $(GLIB_DEPS) HBSOURCES += $(HB_GLIB_sources) HBHEADERS += $(HB_GLIB_headers) +HB_HAS_GLIB_DEF = define HB_HAS_GLIB 1 +else +HB_HAS_GLIB_DEF = undef HB_HAS_GLIB endif if HAVE_FREETYPE @@ -55,6 +58,9 @@ HBLIBS += $(FREETYPE_LIBS) HBDEPS += $(FREETYPE_DEPS) HBSOURCES += $(HB_FT_sources) HBHEADERS += $(HB_FT_headers) +HB_HAS_FREETYPE_DEF = define HB_HAS_FREETYPE 1 +else +HB_HAS_FREETYPE_DEF = undef HB_HAS_FREETYPE endif if HAVE_GRAPHITE2 @@ -63,6 +69,9 @@ HBLIBS += $(GRAPHITE2_LIBS) HBDEPS += $(GRAPHITE2_DEPS) HBSOURCES += $(HB_GRAPHITE2_sources) HBHEADERS += $(HB_GRAPHITE2_headers) +HB_HAS_GRAPHITE_DEF = define HB_HAS_GRAPHITE 1 +else +HB_HAS_GRAPHITE_DEF = undef HB_HAS_GRAPHITE endif if HAVE_UNISCRIBE @@ -70,6 +79,9 @@ HBCFLAGS += $(UNISCRIBE_CFLAGS) HBNONPCLIBS += $(UNISCRIBE_LIBS) HBSOURCES += $(HB_UNISCRIBE_sources) HBHEADERS += $(HB_UNISCRIBE_headers) +HB_HAS_UNISCRIBE_DEF = define HB_HAS_UNISCRIBE 1 +else +HB_HAS_UNISCRIBE_DEF = undef HB_HAS_UNISCRIBE endif if HAVE_DIRECTWRITE @@ -77,6 +89,9 @@ HBCFLAGS += $(DIRECTWRITE_CXXFLAGS) HBNONPCLIBS += $(DIRECTWRITE_LIBS) HBSOURCES += $(HB_DIRECTWRITE_sources) HBHEADERS += $(HB_DIRECTWRITE_headers) +HB_HAS_DIRECTWRITE_DEF = define HB_HAS_DIRECTWRITE 1 +else +HB_HAS_DIRECTWRITE_DEF = undef HB_HAS_DIRECTWRITE endif if HAVE_GDI @@ -84,6 +99,9 @@ HBCFLAGS += $(GDI_CXXFLAGS) HBNONPCLIBS += $(GDI_LIBS) HBSOURCES += $(HB_GDI_sources) HBHEADERS += $(HB_GDI_headers) +HB_HAS_GDI_DEF = define HB_HAS_GDI 1 +else +HB_HAS_GDI_DEF = undef HB_HAS_GDI endif if HAVE_CORETEXT @@ -91,6 +109,9 @@ HBCFLAGS += $(CORETEXT_CFLAGS) HBNONPCLIBS += $(CORETEXT_LIBS) HBSOURCES += $(HB_CORETEXT_sources) HBHEADERS += $(HB_CORETEXT_headers) +HB_HAS_CORETEXT_DEF = define HB_HAS_CORETEXT 1 +else +HB_HAS_CORETEXT_DEF = undef HB_HAS_CORETEXT endif @@ -114,6 +135,8 @@ export_symbols = -export-symbols harfbuzz.def harfbuzz_def_dependency = harfbuzz.def export_symbols_subset = -export-symbols harfbuzz-subset.def harfbuzz_subset_def_dependency = harfbuzz-subset.def +export_symbols_cairo = -export-symbols harfbuzz-cairo.def +harfbuzz_cairo_def_dependency = harfbuzz-cairo.def export_symbols_icu = -export-symbols harfbuzz-icu.def harfbuzz_icu_def_dependency = harfbuzz-icu.def export_symbols_gobject = -export-symbols harfbuzz-gobject.def @@ -147,7 +170,7 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = harfbuzz.pc cmakedir = $(libdir)/cmake/harfbuzz cmake_DATA = harfbuzz-config.cmake -EXTRA_DIST += hb-version.h.in harfbuzz.pc.in harfbuzz-config.cmake.in +EXTRA_DIST += hb-version.h.in hb-features.h.in harfbuzz.pc.in harfbuzz-config.cmake.in lib_LTLIBRARIES += libharfbuzz-subset.la libharfbuzz_subset_la_LINK = $(chosen_linker) $(libharfbuzz_subset_la_LDFLAGS) @@ -172,12 +195,24 @@ harfbuzz-subset.cc: Makefile.sources || ($(RM) $(srcdir)/harfbuzz-subset.cc; false) BUILT_SOURCES += harfbuzz-subset.cc +lib_LTLIBRARIES += libharfbuzz-cairo.la +libharfbuzz_cairo_la_LINK = $(chosen_linker) $(libharfbuzz_cairo_la_LDFLAGS) +libharfbuzz_cairo_la_SOURCES = $(HB_CAIRO_sources) +libharfbuzz_cairo_la_CPPFLAGS = $(HBCFLAGS) $(CAIRO_CFLAGS) $(CODE_COVERAGE_CFLAGS) +libharfbuzz_cairo_la_LDFLAGS = $(base_link_flags) $(export_symbols_cairo) $(CODE_COVERAGE_LDFLAGS) +libharfbuzz_cairo_la_LIBADD = $(CAIRO_LIBS) libharfbuzz.la +EXTRA_libharfbuzz_cairo_la_DEPENDENCIES = $(harfbuzz_cairo_def_dependency) +pkginclude_HEADERS += $(HB_CAIRO_headers) +pkgconfig_DATA += harfbuzz-cairo.pc +EXTRA_DIST += harfbuzz-cairo.pc.in + if HAVE_ICU if HAVE_ICU_BUILTIN HBCFLAGS += $(ICU_CFLAGS) HBLIBS += $(ICU_LIBS) HBSOURCES += $(HB_ICU_sources) HBHEADERS += $(HB_ICU_headers) +HB_HAS_ICU_DEF = define HB_HAS_ICU 1 else lib_LTLIBRARIES += libharfbuzz-icu.la libharfbuzz_icu_la_SOURCES = $(HB_ICU_sources) @@ -187,6 +222,7 @@ libharfbuzz_icu_la_LIBADD = $(ICU_LIBS) libharfbuzz.la EXTRA_libharfbuzz_icu_la_DEPENDENCIES = $(harfbuzz_icu_def_dependency) pkginclude_HEADERS += $(HB_ICU_headers) pkgconfig_DATA += harfbuzz-icu.pc +HB_HAS_ICU_DEF = undef HB_HAS_ICU endif endif EXTRA_DIST += harfbuzz-icu.pc.in @@ -218,6 +254,9 @@ hb-gobject-enums.%: hb-gobject-enums.%.tmpl $(HBHEADERS) --template $^ | \ sed 's/_t_get_type/_get_type/g; s/_T (/ (/g' > "$@" \ || ($(RM) "$@"; false) +HB_HAS_GOBJECT_DEF = define HB_HAS_GOBJECT 1 +else +HB_HAS_GOBJECT_DEF = undef HB_HAS_GOBJECT endif EXTRA_DIST += \ harfbuzz-gobject.pc.in \ @@ -226,6 +265,27 @@ EXTRA_DIST += \ $(NULL) +BUILT_SOURCES += \ + hb-features.h +DISTCLEANFILES += \ + hb-features.h + +hb-features.h: hb-features.h.in $(top_builddir)/config.status + $(AM_V_GEN) $(SED) \ + -e 's/mesondefine HB_HAS_CAIRO/$(HB_HAS_CAIRO_DEF)/' \ + -e 's/mesondefine HB_HAS_FREETYPE/$(HB_HAS_FREETYPE_DEF)/' \ + -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \ + -e 's/mesondefine HB_HAS_GDI/$(HB_HAS_GDI_DEF)/' \ + -e 's/mesondefine HB_HAS_GRAPHITE/$(HB_HAS_GRAPHITE_DEF)/' \ + -e 's/mesondefine HB_HAS_GLIB/$(HB_HAS_GLIB_DEF)/' \ + -e 's/mesondefine HB_HAS_GOBJECT/$(HB_HAS_GOBJECT_DEF)/' \ + -e 's/mesondefine HB_HAS_UNISCRIBE/$(HB_HAS_UNISCRIBE_DEF)/' \ + -e 's/mesondefine HB_HAS_DIRECTWRITE/$(HB_HAS_DIRECTWRITE_DEF)/' \ + -e 's/mesondefine HB_HAS_CORETEXT/$(HB_HAS_CORETEXT_DEF)/' \ + -e 's/mesondefine HB_HAS_ICU/$(HB_HAS_ICU_DEF)/' \ + "$<" > "$@" || ($(RM) "$@"; false) + + %.pc: %.pc.in $(top_builddir)/config.status $(AM_V_GEN) \ $(SED) -e 's@%prefix%@$(prefix)@g' \ @@ -252,6 +312,8 @@ harfbuzz.def: $(HBHEADERS) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-subset.def: $(HB_SUBSET_headers) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ +harfbuzz-cairo.def: $(HB_CAIRO_headers) + $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-icu.def: $(HB_ICU_headers) $(AM_V_GEN) $(srcdir)/gen-def.py "$@" $^ harfbuzz-gobject.def: $(HB_GOBJECT_headers) @@ -320,6 +382,7 @@ noinst_PROGRAMS = \ test-ot-name \ test-ot-glyphname \ test-gpos-size-params \ + test-gsub-get-alternates \ test-gsub-would-substitute \ test-use-table \ $(NULL) @@ -357,6 +420,10 @@ test_gpos_size_params_SOURCES = test-gpos-size-params.cc test_gpos_size_params_CPPFLAGS = $(HBCFLAGS) test_gpos_size_params_LDADD = libharfbuzz.la $(HBLIBS) +test_gsub_get_alternates_SOURCES = test-gsub-get-alternates.cc +test_gsub_get_alternates_CPPFLAGS = $(HBCFLAGS) +test_gsub_get_alternates_LDADD = libharfbuzz.la $(HBLIBS) + test_gsub_would_substitute_SOURCES = test-gsub-would-substitute.cc test_gsub_would_substitute_CPPFLAGS = $(HBCFLAGS) $(FREETYPE_CFLAGS) test_gsub_would_substitute_LDADD = libharfbuzz.la $(HBLIBS) $(FREETYPE_LIBS) @@ -368,6 +435,7 @@ COMPILED_TESTS = \ test-iter \ test-machinery \ test-map \ + test-multimap \ test-number \ test-ot-tag \ test-priority-queue \ @@ -407,6 +475,10 @@ test_map_SOURCES = test-map.cc hb-static.cc test_map_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_map_LDADD = $(COMPILED_TESTS_LDADD) +test_multimap_SOURCES = test-multimap.cc hb-static.cc +test_multimap_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) +test_multimap_LDADD = $(COMPILED_TESTS_LDADD) + test_number_SOURCES = test-number.cc hb-number.cc test_number_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS) test_number_LDADD = $(COMPILED_TESTS_LDADD) diff --git a/third_party/harfbuzz-ng/src/src/Makefile.sources b/third_party/harfbuzz-ng/src/src/Makefile.sources index 6c891eac577e..fd7c3b55ef25 100644 --- a/third_party/harfbuzz-ng/src/src/Makefile.sources +++ b/third_party/harfbuzz-ng/src/src/Makefile.sources @@ -42,16 +42,19 @@ HB_BASE_sources = \ hb-draw.hh \ hb-face.cc \ hb-face.hh \ + hb-face-builder.cc \ hb-fallback-shape.cc \ hb-font.cc \ hb-font.hh \ hb-iter.hh \ hb-kern.hh \ + hb-limits.hh \ hb-machinery.hh \ hb-map.cc \ hb-map.hh \ hb-meta.hh \ hb-ms-feature-ranges.hh \ + hb-multimap.hh \ hb-mutex.hh \ hb-null.hh \ hb-number.cc \ @@ -66,11 +69,6 @@ HB_BASE_sources = \ hb-ot-cff2-table.cc \ hb-ot-cff2-table.hh \ hb-ot-cmap-table.hh \ - hb-ot-color-cbdt-table.hh \ - hb-ot-color-colr-table.hh \ - hb-ot-color-cpal-table.hh \ - hb-ot-color-sbix-table.hh \ - hb-ot-color-svg-table.hh \ hb-ot-color.cc \ hb-ot-face-table-list.hh \ hb-ot-face.cc \ @@ -87,7 +85,18 @@ HB_BASE_sources = \ hb-ot-layout-common.hh \ hb-ot-layout-gdef-table.hh \ hb-ot-layout-gpos-table.hh \ + hb-outline.hh \ + hb-outline.cc \ + hb-paint.cc \ + hb-paint.hh \ + hb-paint-extents.cc \ + hb-paint-extents.hh \ hb-ot-layout-gsub-table.hh \ + OT/Color/CBDT/CBDT.hh \ + OT/Color/COLR/COLR.hh \ + OT/Color/CPAL/CPAL.hh \ + OT/Color/sbix/sbix.hh \ + OT/Color/svg/svg.hh \ OT/glyf/glyf.hh \ OT/glyf/glyf-helpers.hh \ OT/glyf/loca.hh \ @@ -95,13 +104,17 @@ HB_BASE_sources = \ OT/glyf/Glyph.hh \ OT/glyf/GlyphHeader.hh \ OT/glyf/SimpleGlyph.hh \ + OT/glyf/coord-setter.hh \ + OT/glyf/composite-iter.hh \ OT/glyf/CompositeGlyph.hh \ + OT/glyf/VarCompositeGlyph.hh \ OT/glyf/SubsetGlyph.hh \ OT/Layout/types.hh \ OT/Layout/Common/Coverage.hh \ OT/Layout/Common/CoverageFormat1.hh \ OT/Layout/Common/CoverageFormat2.hh \ OT/Layout/Common/RangeRecord.hh \ + OT/Layout/GDEF/GDEF.hh \ OT/Layout/GPOS/AnchorFormat1.hh \ OT/Layout/GPOS/AnchorFormat2.hh \ OT/Layout/GPOS/AnchorFormat3.hh \ @@ -156,6 +169,7 @@ HB_BASE_sources = \ OT/Layout/GSUB/SingleSubst.hh \ OT/Layout/GSUB/SubstLookup.hh \ OT/Layout/GSUB/SubstLookupSubTable.hh \ + OT/name/name.hh \ hb-ot-layout-gsubgpos.hh \ hb-ot-layout-jstf-table.hh \ hb-ot-layout.cc \ @@ -211,6 +225,7 @@ HB_BASE_sources = \ hb-ot-tag.cc \ hb-ot-var-avar-table.hh \ hb-ot-var-common.hh \ + hb-ot-var-cvar-table.hh \ hb-ot-var-fvar-table.hh \ hb-ot-var-gvar-table.hh \ hb-ot-var-hvar-table.hh \ @@ -246,7 +261,8 @@ HB_BASE_sources = \ HB_BASE_RAGEL_GENERATED_sources = \ hb-buffer-deserialize-json.hh \ - hb-buffer-deserialize-text.hh \ + hb-buffer-deserialize-text-glyphs.hh \ + hb-buffer-deserialize-text-unicode.hh \ hb-number-parser.hh \ hb-ot-shaper-indic-machine.hh \ hb-ot-shaper-khmer-machine.hh \ @@ -255,7 +271,8 @@ HB_BASE_RAGEL_GENERATED_sources = \ $(NULL) HB_BASE_RAGEL_sources = \ hb-buffer-deserialize-json.rl \ - hb-buffer-deserialize-text.rl \ + hb-buffer-deserialize-text-glyphs.rl \ + hb-buffer-deserialize-text-unicode.rl \ hb-number-parser.rl \ hb-ot-shaper-indic-machine.rl \ hb-ot-shaper-khmer-machine.rl \ @@ -286,6 +303,7 @@ HB_BASE_headers = \ hb-ot-shape.h \ hb-ot-var.h \ hb-ot.h \ + hb-paint.h \ hb-set.h \ hb-shape-plan.h \ hb-shape.h \ @@ -297,7 +315,7 @@ HB_BASE_headers = \ # Optional Sources and Headers with external deps -HB_FT_sources = hb-ft.cc +HB_FT_sources = hb-ft.cc hb-ft-colr.hh HB_FT_headers = hb-ft.h HB_GLIB_sources = hb-glib.cc @@ -330,7 +348,6 @@ HB_SUBSET_sources = \ hb-number.hh \ hb-ot-cff1-table.cc \ hb-ot-cff2-table.cc \ - hb-ot-color-colrv1-closure.hh \ hb-ot-post-table-v2subset.hh \ hb-static.cc \ hb-subset-cff-common.cc \ @@ -341,6 +358,7 @@ HB_SUBSET_sources = \ hb-subset-cff2.hh \ hb-subset-input.cc \ hb-subset-input.hh \ + hb-subset-instancer-solver.cc \ hb-subset-accelerator.hh \ hb-subset-plan.cc \ hb-subset-plan.hh \ @@ -358,6 +376,7 @@ HB_SUBSET_sources = \ graph/markbasepos-graph.hh \ graph/split-helpers.hh \ graph/serialize.hh \ + OT/Color/COLR/colrv1-closure.hh \ $(NULL) HB_SUBSET_headers = \ @@ -365,6 +384,16 @@ HB_SUBSET_headers = \ hb-subset-repacker.h \ $(NULL) +HB_CAIRO_sources = \ + hb-cairo.cc \ + hb-cairo-utils.cc \ + hb-cairo-utils.hh \ + hb-static.cc \ + $(NULL) +HB_CAIRO_headers = \ + hb-cairo.h \ + $(NULL) + HB_GOBJECT_DIST_sources = hb-gobject-structs.cc HB_GOBJECT_DIST_headers = hb-gobject.h hb-gobject-structs.h HB_GOBJECT_ENUM_sources = hb-gobject-enums.cc diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color-cbdt-table.hh b/third_party/harfbuzz-ng/src/src/OT/Color/CBDT/CBDT.hh similarity index 93% rename from third_party/harfbuzz-ng/src/src/hb-ot-color-cbdt-table.hh rename to third_party/harfbuzz-ng/src/src/OT/Color/CBDT/CBDT.hh index 23fa56c4f6f5..b125052344f9 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color-cbdt-table.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Color/CBDT/CBDT.hh @@ -24,10 +24,11 @@ * Google Author(s): Seigo Nonaka, Calder Kitagawa */ -#ifndef HB_OT_COLOR_CBDT_TABLE_HH -#define HB_OT_COLOR_CBDT_TABLE_HH +#ifndef OT_COLOR_CBDT_CBDT_HH +#define OT_COLOR_CBDT_CBDT_HH -#include "hb-open-type.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-paint.hh" /* * CBLC -- Color Bitmap Location @@ -67,7 +68,7 @@ _copy_data_to_cbdt (hb_vector_t *cbdt_prime, { unsigned int new_len = cbdt_prime->length + length; if (unlikely (!cbdt_prime->alloc (new_len))) return false; - memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); + hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); cbdt_prime->length = new_len; return true; } @@ -80,12 +81,15 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const { - extents->x_bearing = font->em_scale_x (bearingX); - extents->y_bearing = font->em_scale_y (bearingY); - extents->width = font->em_scale_x (width); - extents->height = font->em_scale_y (-static_cast(height)); + extents->x_bearing = bearingX; + extents->y_bearing = bearingY; + extents->width = width; + extents->height = -static_cast (height); + + if (scale) + font->scale_glyph_extents (extents); } HBUINT8 height; @@ -307,7 +311,7 @@ struct IndexSubtable } } - bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const + bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const { switch (u.header.indexFormat) { @@ -468,13 +472,13 @@ struct IndexSubtableRecord if (unlikely (!c->serializer->check_success (records->resize (records->length + 1)))) return_trace (false); - (*records)[records->length - 1].firstGlyphIndex = 1; - (*records)[records->length - 1].lastGlyphIndex = 0; + records->tail ().firstGlyphIndex = 1; + records->tail ().lastGlyphIndex = 0; bitmap_size_context->size += IndexSubtableRecord::min_size; c->serializer->push (); - if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start))) + if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start))) { c->serializer->pop_discard (); c->serializer->revert (snap); @@ -504,8 +508,8 @@ struct IndexSubtableRecord return num_missing; } - bool get_extents (hb_glyph_extents_t *extents, const void *base) const - { return (base+offsetToSubtable).get_extents (extents); } + bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const + { return (base+offsetToSubtable).get_extents (extents, scale); } bool get_image_data (unsigned int gid, const void *base, @@ -833,7 +837,7 @@ struct CBDT } bool - get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -841,7 +845,7 @@ struct CBDT if (!subtable_record || !strike.ppemX || !strike.ppemY) return false; - if (subtable_record->get_extents (extents, base)) + if (subtable_record->get_extents (extents, base, scale)) return true; unsigned int image_offset = 0, image_length = 0, image_format = 0; @@ -858,26 +862,29 @@ struct CBDT if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return false; auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (font, extents); + glyphFormat17.glyphMetrics.get_extents (font, extents, scale); break; } case 18: { if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) return false; auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (font, extents); + glyphFormat18.glyphMetrics.get_extents (font, extents, scale); break; } default: return false; /* TODO: Support other image formats. */ } /* Convert to font units. */ - float x_scale = upem / (float) strike.ppemX; - float y_scale = upem / (float) strike.ppemY; - extents->x_bearing = roundf (extents->x_bearing * x_scale); - extents->y_bearing = roundf (extents->y_bearing * y_scale); - extents->width = roundf (extents->width * x_scale); - extents->height = roundf (extents->height * y_scale); + if (scale) + { + float x_scale = upem / (float) strike.ppemX; + float y_scale = upem / (float) strike.ppemY; + extents->x_bearing = roundf (extents->x_bearing * x_scale); + extents->y_bearing = roundf (extents->y_bearing * y_scale); + extents->width = roundf (extents->width * x_scale); + extents->height = roundf (extents->height * y_scale); + } return true; } @@ -934,6 +941,32 @@ struct CBDT bool has_data () const { return cbdt.get_length (); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + hb_glyph_extents_t extents; + hb_glyph_extents_t pixel_extents; + hb_blob_t *blob = reference_png (font, glyph); + + if (unlikely (blob == hb_blob_get_empty ())) + return false; + + if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents))) + return false; + + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + return false; + + bool ret = funcs->image (data, + blob, + pixel_extents.width, -pixel_extents.height, + HB_PAINT_IMAGE_FORMAT_PNG, + font->slant_xy, + &extents); + + hb_blob_destroy (blob); + return ret; + } + private: hb_blob_ptr_t cblc; hb_blob_ptr_t cbdt; @@ -994,4 +1027,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_CBDT_TABLE_HH */ +#endif /* OT_COLOR_CBDT_CBDT_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color-colr-table.hh b/third_party/harfbuzz-ng/src/src/OT/Color/COLR/COLR.hh similarity index 56% rename from third_party/harfbuzz-ng/src/src/hb-ot-color-colr-table.hh rename to third_party/harfbuzz-ng/src/src/OT/Color/COLR/COLR.hh index 908bf550f0d0..191812f48eeb 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color-colr-table.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Color/COLR/COLR.hh @@ -25,12 +25,14 @@ * Google Author(s): Calder Kitagawa */ -#ifndef HB_OT_COLOR_COLR_TABLE_HH -#define HB_OT_COLOR_COLR_TABLE_HH +#ifndef OT_COLOR_COLR_COLR_HH +#define OT_COLOR_COLR_COLR_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-var-common.hh" +#include "../../../hb.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-ot-var-common.hh" +#include "../../../hb-paint.hh" +#include "../../../hb-paint-extents.hh" /* * COLR -- Color @@ -38,17 +40,81 @@ */ #define HB_OT_TAG_COLR HB_TAG('C','O','L','R') -#ifndef HB_COLRV1_MAX_NESTING_LEVEL -#define HB_COLRV1_MAX_NESTING_LEVEL 100 -#endif - -#ifndef COLRV1_ENABLE_SUBSETTING -#define COLRV1_ENABLE_SUBSETTING 1 -#endif +namespace OT { +struct hb_paint_context_t; +} namespace OT { struct COLR; + +struct Paint; + +struct hb_paint_context_t : + hb_dispatch_context_t +{ + template + return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + const COLR* get_colr_table () const + { return reinterpret_cast (base); } + +public: + const void *base; + hb_paint_funcs_t *funcs; + void *data; + hb_font_t *font; + unsigned int palette_index; + hb_color_t foreground; + VarStoreInstancer &instancer; + int depth_left = HB_MAX_NESTING_LEVEL; + int edge_count = HB_COLRV1_MAX_EDGE_COUNT; + + hb_paint_context_t (const void *base_, + hb_paint_funcs_t *funcs_, + void *data_, + hb_font_t *font_, + unsigned int palette_, + hb_color_t foreground_, + VarStoreInstancer &instancer_) : + base (base_), + funcs (funcs_), + data (data_), + font (font_), + palette_index (palette_), + foreground (foreground_), + instancer (instancer_) + { } + + hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground) + { + hb_color_t color = foreground; + + *is_foreground = true; + + if (color_index != 0xffff) + { + if (!funcs->custom_palette_color (data, color_index, &color)) + { + unsigned int clen = 1; + hb_face_t *face = hb_font_get_face (font); + + hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color); + } + + *is_foreground = false; + } + + return HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + hb_color_get_alpha (color) * alpha); + } + + inline void recurse (const Paint &paint); +}; + struct hb_colrv1_closure_context_t : hb_dispatch_context_t { @@ -102,7 +168,7 @@ struct hb_colrv1_closure_context_t : hb_set_t *glyphs_, hb_set_t *layer_indices_, hb_set_t *palette_indices_, - unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : + unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) : base (base_), glyphs (glyphs_), layer_indices (layer_indices_), @@ -164,6 +230,8 @@ struct BaseGlyphRecord template struct Variable { + static constexpr bool is_variable = true; + Variable* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); @@ -173,10 +241,15 @@ struct Variable void closurev1 (hb_colrv1_closure_context_t* c) const { value.closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); - if (!value.subset (c)) return_trace (false); + if (!value.subset (c, instancer, varIdxBase)) return_trace (false); + if (c->plan->all_axes_pinned) + return_trace (true); + + //TODO: update varIdxBase for partial-instancing return_trace (c->serializer->embed (varIdxBase)); } @@ -186,8 +259,26 @@ struct Variable return_trace (c->check_struct (this) && value.sanitize (c)); } + void paint_glyph (hb_paint_context_t *c) const + { + value.paint_glyph (c, varIdxBase); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *stop, + const VarStoreInstancer &instancer) const + { + value.get_color_stop (c, stop, varIdxBase, instancer); + } + + hb_paint_extend_t get_extend () const + { + return value.get_extend (); + } + protected: T value; + public: VarIdx varIdxBase; public: DEFINE_SIZE_STATIC (4 + T::static_size); @@ -196,6 +287,10 @@ struct Variable template struct NoVariable { + static constexpr bool is_variable = false; + + static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION; + NoVariable* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); @@ -205,10 +300,11 @@ struct NoVariable void closurev1 (hb_colrv1_closure_context_t* c) const { value.closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); - return_trace (value.subset (c)); + return_trace (value.subset (c, instancer, varIdxBase)); } bool sanitize (hb_sanitize_context_t *c) const @@ -217,6 +313,23 @@ struct NoVariable return_trace (c->check_struct (this) && value.sanitize (c)); } + void paint_glyph (hb_paint_context_t *c) const + { + value.paint_glyph (c, varIdxBase); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *stop, + const VarStoreInstancer &instancer) const + { + value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer); + } + + hb_paint_extend_t get_extend () const + { + return value.get_extend (); + } + T value; public: DEFINE_SIZE_STATIC (T::static_size); @@ -229,12 +342,21 @@ struct ColorStop void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (paletteIndex); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->stopOffset.set_float (stopOffset.to_float(instancer (varIdxBase, 0))); + out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 1))); + } + + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -244,6 +366,17 @@ struct ColorStop return_trace (c->check_struct (this)); } + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *out, + uint32_t varIdx, + const VarStoreInstancer &instancer) const + { + out->offset = stopOffset.to_float(instancer (varIdx, 0)); + out->color = c->get_color (paletteIndex, + alpha.to_float (instancer (varIdx, 1)), + &out->is_foreground); + } + F2DOT14 stopOffset; HBUINT16 paletteIndex; F2DOT14 alpha; @@ -271,7 +404,8 @@ struct ColorLine stop.closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); @@ -283,7 +417,7 @@ struct ColorLine for (const auto& stop : stops.iter ()) { - if (!stop.subset (c)) return_trace (false); + if (!stop.subset (c, instancer)) return_trace (false); } return_trace (true); } @@ -295,6 +429,52 @@ struct ColorLine stops.sanitize (c)); } + /* get up to count stops from start */ + unsigned int + get_color_stops (hb_paint_context_t *c, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + const VarStoreInstancer &instancer) const + { + unsigned int len = stops.len; + + if (count && color_stops) + { + unsigned int i; + for (i = 0; i < *count && start + i < len; i++) + stops[start + i].get_color_stop (c, &color_stops[i], instancer); + *count = i; + } + + return len; + } + + HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line, + void *color_line_data, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + void *user_data) + { + const ColorLine *thiz = (const ColorLine *) color_line_data; + hb_paint_context_t *c = (hb_paint_context_t *) user_data; + return thiz->get_color_stops (c, start, count, color_stops, c->instancer); + } + + hb_paint_extend_t get_extend () const + { + return (hb_paint_extend_t) (unsigned int) extend; + } + + HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line, + void *color_line_data, + void *user_data) + { + const ColorLine *thiz = (const ColorLine *) color_line_data; + return thiz->get_extend (); + } + Extend extend; Array16Of> stops; public: @@ -358,6 +538,36 @@ struct Affine2x3 return_trace (c->check_struct (this)); } + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xx.set_float (xx.to_float(instancer (varIdxBase, 0))); + out->yx.set_float (yx.to_float(instancer (varIdxBase, 1))); + out->xy.set_float (xy.to_float(instancer (varIdxBase, 2))); + out->yy.set_float (yy.to_float(instancer (varIdxBase, 3))); + out->dx.set_float (dx.to_float(instancer (varIdxBase, 4))); + out->dy.set_float (dy.to_float(instancer (varIdxBase, 5))); + } + return_trace (true); + } + + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + c->funcs->push_transform (c->data, + xx.to_float (c->instancer (varIdxBase, 0)), + yx.to_float (c->instancer (varIdxBase, 1)), + xy.to_float (c->instancer (varIdxBase, 2)), + yy.to_float (c->instancer (varIdxBase, 3)), + dx.to_float (c->instancer (varIdxBase, 4)), + dy.to_float (c->instancer (varIdxBase, 5))); + } + F16DOT16 xx; F16DOT16 yx; F16DOT16 xy; @@ -372,12 +582,13 @@ struct PaintColrLayers { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer HB_UNUSED) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex), + return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); return_trace (true); @@ -389,6 +600,8 @@ struct PaintColrLayers return_trace (c->check_struct (this)); } + inline void paint_glyph (hb_paint_context_t *c) const; + HBUINT8 format; /* format = 1 */ HBUINT8 numLayers; HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ @@ -401,12 +614,21 @@ struct PaintSolid void closurev1 (hb_colrv1_closure_context_t* c) const { c->add_palette_index (paletteIndex); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->alpha.set_float (alpha.to_float (instancer (varIdxBase, 0))); + + if (format == 3 && c->plan->all_axes_pinned) + out->format = 2; + + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -416,6 +638,17 @@ struct PaintSolid return_trace (c->check_struct (this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_bool_t is_foreground; + hb_color_t color; + + color = c->get_color (paletteIndex, + alpha.to_float (c->instancer (varIdxBase, 0)), + &is_foreground); + c->funcs->color (c->data, is_foreground, color); + } + HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ HBUINT16 paletteIndex; F2DOT14 alpha; @@ -429,13 +662,28 @@ struct PaintLinearGradient void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); + out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); + out->x1 = x1 + (int) roundf (instancer (varIdxBase, 2)); + out->y1 = y1 + (int) roundf (instancer (varIdxBase, 3)); + out->x2 = x2 + (int) roundf (instancer (varIdxBase, 4)); + out->y2 = y2 + (int) roundf (instancer (varIdxBase, 5)); + } + + if (format == 5 && c->plan->all_axes_pinned) + out->format = 4; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -444,6 +692,23 @@ struct PaintLinearGradient return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->linear_gradient (c->data, &cl, + x0 + c->instancer (varIdxBase, 0), + y0 + c->instancer (varIdxBase, 1), + x1 + c->instancer (varIdxBase, 2), + y1 + c->instancer (varIdxBase, 3), + x2 + c->instancer (varIdxBase, 4), + y2 + c->instancer (varIdxBase, 5)); + } + HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ Offset24To> colorLine; /* Offset (from beginning of PaintLinearGradient * table) to ColorLine subtable. */ @@ -463,13 +728,28 @@ struct PaintRadialGradient void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->x0 = x0 + (int) roundf (instancer (varIdxBase, 0)); + out->y0 = y0 + (int) roundf (instancer (varIdxBase, 1)); + out->radius0 = radius0 + (unsigned) roundf (instancer (varIdxBase, 2)); + out->x1 = x1 + (int) roundf (instancer (varIdxBase, 3)); + out->y1 = y1 + (int) roundf (instancer (varIdxBase, 4)); + out->radius1 = radius1 + (unsigned) roundf (instancer (varIdxBase, 5)); + } + + if (format == 7 && c->plan->all_axes_pinned) + out->format = 6; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -478,6 +758,23 @@ struct PaintRadialGradient return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->radial_gradient (c->data, &cl, + x0 + c->instancer (varIdxBase, 0), + y0 + c->instancer (varIdxBase, 1), + radius0 + c->instancer (varIdxBase, 2), + x1 + c->instancer (varIdxBase, 3), + y1 + c->instancer (varIdxBase, 4), + radius1 + c->instancer (varIdxBase, 5)); + } + HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ Offset24To> colorLine; /* Offset (from beginning of PaintRadialGradient * table) to ColorLine subtable. */ @@ -497,13 +794,26 @@ struct PaintSweepGradient void closurev1 (hb_colrv1_closure_context_t* c) const { (this+colorLine).closurev1 (c); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->colorLine.serialize_subset (c, colorLine, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 0)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 1)); + out->startAngle.set_float (startAngle.to_float (instancer (varIdxBase, 2))); + out->endAngle.set_float (endAngle.to_float (instancer (varIdxBase, 3))); + } + + if (format == 9 && c->plan->all_axes_pinned) + out->format = 8; + + return_trace (out->colorLine.serialize_subset (c, colorLine, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -512,6 +822,21 @@ struct PaintSweepGradient return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->sweep_gradient (c->data, &cl, + centerX + c->instancer (varIdxBase, 0), + centerY + c->instancer (varIdxBase, 1), + (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * HB_PI, + (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * HB_PI); + } + HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ Offset24To> colorLine; /* Offset (from beginning of PaintSweepGradient * table) to ColorLine subtable. */ @@ -523,14 +848,13 @@ struct PaintSweepGradient DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); }; -struct Paint; - // Paint a non-COLR glyph, filled as indicated by paint. struct PaintGlyph { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -540,7 +864,7 @@ struct PaintGlyph HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - return_trace (out->paint.serialize_subset (c, paint, this)); + return_trace (out->paint.serialize_subset (c, paint, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -549,6 +873,17 @@ struct PaintGlyph return_trace (c->check_struct (this) && paint.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c) const + { + c->funcs->push_inverse_root_transform (c->data, c->font); + c->funcs->push_clip_glyph (c->data, gid, c->font); + c->funcs->push_root_transform (c->data, c->font); + c->recurse (this+paint); + c->funcs->pop_transform (c->data); + c->funcs->pop_clip (c->data); + c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 10 */ Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ HBUINT16 gid; @@ -560,7 +895,8 @@ struct PaintColrGlyph { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer HB_UNUSED) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); @@ -576,6 +912,8 @@ struct PaintColrGlyph return_trace (c->check_struct (this)); } + inline void paint_glyph (hb_paint_context_t *c) const; + HBUINT8 format; /* format = 11 */ HBUINT16 gid; public: @@ -587,13 +925,16 @@ struct PaintTransform { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - if (!out->transform.serialize_copy (c->serializer, transform, this)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (!out->transform.serialize_subset (c, transform, this, instancer)) return_trace (false); + if (format == 13 && c->plan->all_axes_pinned) + out->format = 12; + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -604,6 +945,13 @@ struct PaintTransform transform.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c) const + { + (this+transform).paint_glyph (c); + c->recurse (this+src); + c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ Offset24To src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ Offset24To> transform; @@ -615,13 +963,24 @@ struct PaintTranslate { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->dx = dx + (int) roundf (instancer (varIdxBase, 0)); + out->dy = dy + (int) roundf (instancer (varIdxBase, 1)); + } + + if (format == 15 && c->plan->all_axes_pinned) + out->format = 14; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -630,6 +989,16 @@ struct PaintTranslate return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float ddx = dx + c->instancer (varIdxBase, 0); + float ddy = dy + c->instancer (varIdxBase, 1); + + bool p1 = c->funcs->push_translate (c->data, ddx, ddy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ Offset24To src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ FWORD dx; @@ -642,13 +1011,24 @@ struct PaintScale { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); + out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + } + + if (format == 17 && c->plan->all_axes_pinned) + out->format = 16; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -657,6 +1037,16 @@ struct PaintScale return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); + float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); + + bool p1 = c->funcs->push_scale (c->data, sx, sy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ Offset24To src; /* Offset (from beginning of PaintScale table) to Paint subtable. */ F2DOT14 scaleX; @@ -669,13 +1059,26 @@ struct PaintScaleAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scaleX.set_float (scaleX.to_float (instancer (varIdxBase, 0))); + out->scaleY.set_float (scaleY.to_float (instancer (varIdxBase, 1))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 19 && c->plan->all_axes_pinned) + out->format = 18; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -684,6 +1087,22 @@ struct PaintScaleAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); + float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); + float tCenterX = centerX + c->instancer (varIdxBase, 2); + float tCenterY = centerY + c->instancer (varIdxBase, 3); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_scale (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ Offset24To src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */ F2DOT14 scaleX; @@ -698,13 +1117,21 @@ struct PaintScaleUniform { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + + if (format == 21 && c->plan->all_axes_pinned) + out->format = 20; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -713,6 +1140,15 @@ struct PaintScaleUniform return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float s = scale.to_float (c->instancer (varIdxBase, 0)); + + bool p1 = c->funcs->push_scale (c->data, s, s); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ Offset24To src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */ F2DOT14 scale; @@ -724,13 +1160,25 @@ struct PaintScaleUniformAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->scale.set_float (scale.to_float (instancer (varIdxBase, 0))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + } + + if (format == 23 && c->plan->all_axes_pinned) + out->format = 22; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -739,6 +1187,21 @@ struct PaintScaleUniformAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float s = scale.to_float (c->instancer (varIdxBase, 0)); + float tCenterX = centerX + c->instancer (varIdxBase, 1); + float tCenterY = centerY + c->instancer (varIdxBase, 2); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_scale (c->data, s, s); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ Offset24To src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */ F2DOT14 scale; @@ -752,13 +1215,21 @@ struct PaintRotate { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + + if (format == 25 && c->plan->all_axes_pinned) + out->format = 24; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -767,6 +1238,15 @@ struct PaintRotate return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float a = angle.to_float (c->instancer (varIdxBase, 0)); + + bool p1 = c->funcs->push_rotate (c->data, a); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ Offset24To src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ F2DOT14 angle; @@ -778,13 +1258,25 @@ struct PaintRotateAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->angle.set_float (angle.to_float (instancer (varIdxBase, 0))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 1)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 2)); + } + + if (format ==27 && c->plan->all_axes_pinned) + out->format = 26; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -793,6 +1285,21 @@ struct PaintRotateAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float a = angle.to_float (c->instancer (varIdxBase, 0)); + float tCenterX = centerX + c->instancer (varIdxBase, 1); + float tCenterY = centerY + c->instancer (varIdxBase, 2); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_rotate (c->data, a); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ Offset24To src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */ F2DOT14 angle; @@ -806,13 +1313,24 @@ struct PaintSkew { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); + out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + } + + if (format == 29 && c->plan->all_axes_pinned) + out->format = 28; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -821,6 +1339,16 @@ struct PaintSkew return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); + float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); + + bool p1 = c->funcs->push_skew (c->data, sx, sy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ Offset24To src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ F2DOT14 xSkewAngle; @@ -833,13 +1361,26 @@ struct PaintSkewAroundCenter { HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (out->src.serialize_subset (c, src, this)); + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xSkewAngle.set_float (xSkewAngle.to_float (instancer (varIdxBase, 0))); + out->ySkewAngle.set_float (ySkewAngle.to_float (instancer (varIdxBase, 1))); + out->centerX = centerX + (int) roundf (instancer (varIdxBase, 2)); + out->centerY = centerY + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 31 && c->plan->all_axes_pinned) + out->format = 30; + + return_trace (out->src.serialize_subset (c, src, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -848,6 +1389,22 @@ struct PaintSkewAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); + float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); + float tCenterX = centerX + c->instancer (varIdxBase, 2); + float tCenterY = centerY + c->instancer (varIdxBase, 3); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_skew (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ Offset24To src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */ F2DOT14 xSkewAngle; @@ -862,14 +1419,15 @@ struct PaintComposite { void closurev1 (hb_colrv1_closure_context_t* c) const; - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - if (!out->src.serialize_subset (c, src, this)) return_trace (false); - return_trace (out->backdrop.serialize_subset (c, backdrop, this)); + if (!out->src.serialize_subset (c, src, this, instancer)) return_trace (false); + return_trace (out->backdrop.serialize_subset (c, backdrop, this, instancer)); } bool sanitize (hb_sanitize_context_t *c) const @@ -880,6 +1438,14 @@ struct PaintComposite backdrop.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c) const + { + c->recurse (this+backdrop); + c->funcs->push_group (c->data); + c->recurse (this+src); + c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode); + } + HBUINT8 format; /* format = 32 */ Offset24To src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ @@ -888,6 +1454,11 @@ struct PaintComposite DEFINE_SIZE_STATIC (8); }; +struct ClipBoxData +{ + int xMin, yMin, xMax, yMax; +}; + struct ClipBoxFormat1 { bool sanitize (hb_sanitize_context_t *c) const @@ -896,6 +1467,36 @@ struct ClipBoxFormat1 return_trace (c->check_struct (this)); } + void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const + { + clip_box.xMin = xMin; + clip_box.yMin = yMin; + clip_box.xMax = xMax; + clip_box.yMax = yMax; + } + + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer, + uint32_t varIdxBase) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + if (instancer && !c->plan->pinned_at_default && varIdxBase != VarIdx::NO_VARIATION) + { + out->xMin = xMin + (int) roundf (instancer (varIdxBase, 0)); + out->yMin = yMin + (int) roundf (instancer (varIdxBase, 1)); + out->xMax = xMax + (int) roundf (instancer (varIdxBase, 2)); + out->yMax = yMax + (int) roundf (instancer (varIdxBase, 3)); + } + + if (format == 2 && c->plan->all_axes_pinned) + out->format = 1; + + return_trace (true); + } + public: HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ FWORD xMin; @@ -906,25 +1507,39 @@ struct ClipBoxFormat1 DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size); }; -struct ClipBoxFormat2 : Variable {}; +struct ClipBoxFormat2 : Variable +{ + void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const + { + value.get_clip_box(clip_box, instancer); + if (instancer) + { + clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0)); + clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1)); + clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2)); + clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3)); + } + } +}; struct ClipBox { - ClipBox* copy (hb_serialize_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { - TRACE_SERIALIZE (this); + TRACE_SUBSET (this); switch (u.format) { - case 1: return_trace (reinterpret_cast (c->embed (u.format1))); - case 2: return_trace (reinterpret_cast (c->embed (u.format2))); - default:return_trace (nullptr); + case 1: return_trace (u.format1.subset (c, instancer, VarIdx::NO_VARIATION)); + case 2: return_trace (u.format2.subset (c, instancer)); + default:return_trace (c->default_return_value ()); } } template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -932,6 +1547,28 @@ struct ClipBox } } + bool get_extents (hb_glyph_extents_t *extents, + const VarStoreInstancer &instancer) const + { + ClipBoxData clip_box; + switch (u.format) { + case 1: + u.format1.get_clip_box (clip_box, instancer); + break; + case 2: + u.format2.get_clip_box (clip_box, instancer); + break; + default: + return false; + } + + extents->x_bearing = clip_box.xMin; + extents->y_bearing = clip_box.yMax; + extents->width = clip_box.xMax - clip_box.xMin; + extents->height = clip_box.yMin - clip_box.yMax; + return true; + } + protected: union { HBUINT8 format; /* Format identifier */ @@ -942,13 +1579,18 @@ struct ClipBox struct ClipRecord { - ClipRecord* copy (hb_serialize_context_t *c, const void *base) const + int cmp (hb_codepoint_t g) const + { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } + + bool subset (hb_subset_context_t *c, + const void *base, + const VarStoreInstancer &instancer) const { - TRACE_SERIALIZE (this); - auto *out = c->embed (this); - if (unlikely (!out)) return_trace (nullptr); - if (!out->clipBox.serialize_copy (c, clipBox, base)) return_trace (nullptr); - return_trace (out); + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->clipBox.serialize_subset (c, clipBox, base, instancer)); } bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -957,6 +1599,13 @@ struct ClipRecord return_trace (c->check_struct (this) && clipBox.sanitize (c, base)); } + bool get_extents (hb_glyph_extents_t *extents, + const void *base, + const VarStoreInstancer &instancer) const + { + return (base+clipBox).get_extents (extents, instancer); + } + public: HBUINT16 startGlyphID; // first gid clip applies to HBUINT16 endGlyphID; // last gid clip applies to, inclusive @@ -964,10 +1613,12 @@ struct ClipRecord public: DEFINE_SIZE_STATIC (7); }; +DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord); struct ClipList { - unsigned serialize_clip_records (hb_serialize_context_t *c, + unsigned serialize_clip_records (hb_subset_context_t *c, + const VarStoreInstancer &instancer, const hb_set_t& gids, const hb_map_t& gid_offset_map) const { @@ -999,7 +1650,7 @@ struct ClipList record.endGlyphID = prev_gid; record.clipBox = prev_offset; - if (!c->copy (record, this)) return_trace (0); + if (!record.subset (c, this, instancer)) return_trace (0); count++; start_gid = _; @@ -1013,20 +1664,21 @@ struct ClipList record.startGlyphID = start_gid; record.endGlyphID = prev_gid; record.clipBox = prev_offset; - if (!c->copy (record, this)) return_trace (0); + if (!record.subset (c, this, instancer)) return_trace (0); count++; } return_trace (count); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (*this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - const hb_set_t& glyphset = *c->plan->_glyphset_colred; + const hb_set_t& glyphset = c->plan->_glyphset_colred; const hb_map_t &glyph_map = *c->plan->glyph_map; hb_map_t new_gid_offset_map; @@ -1044,7 +1696,7 @@ struct ClipList } } - unsigned count = serialize_clip_records (c->serializer, new_gids, new_gid_offset_map); + unsigned count = serialize_clip_records (c, instancer, new_gids, new_gid_offset_map); if (!count) return_trace (false); return_trace (c->serializer->check_assign (out->clips.len, count, HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -1052,11 +1704,26 @@ struct ClipList bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + // TODO Make a formatted struct! return_trace (c->check_struct (this) && clips.sanitize (c, this)); } + bool + get_extents (hb_codepoint_t gid, + hb_glyph_extents_t *extents, + const VarStoreInstancer &instancer) const + { + auto *rec = clips.as_array ().bsearch (gid); + if (rec) + { + rec->get_extents (extents, this, instancer); + return true; + } + return false; + } + HBUINT8 format; // Set to 1. - Array32Of clips; // Clip records, sorted by startGlyphID + SortedArray32Of clips; // Clip records, sorted by startGlyphID public: DEFINE_SIZE_ARRAY_SIZED (5, clips); }; @@ -1069,7 +1736,7 @@ struct Paint { TRACE_SANITIZE (this); - if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) + if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL))) return_trace (c->no_dispatch_return_value ()); return_trace (c->end_recursion (this->dispatch (c, std::forward (ds)...))); @@ -1078,8 +1745,8 @@ struct Paint template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); @@ -1121,35 +1788,35 @@ struct Paint union { HBUINT8 format; PaintColrLayers paintformat1; - PaintSolid paintformat2; + NoVariable paintformat2; Variable paintformat3; - PaintLinearGradient paintformat4; + NoVariable> paintformat4; Variable> paintformat5; - PaintRadialGradient paintformat6; + NoVariable> paintformat6; Variable> paintformat7; - PaintSweepGradient paintformat8; + NoVariable> paintformat8; Variable> paintformat9; PaintGlyph paintformat10; PaintColrGlyph paintformat11; PaintTransform paintformat12; PaintTransform paintformat13; - PaintTranslate paintformat14; + NoVariable paintformat14; Variable paintformat15; - PaintScale paintformat16; + NoVariable paintformat16; Variable paintformat17; - PaintScaleAroundCenter paintformat18; + NoVariable paintformat18; Variable paintformat19; - PaintScaleUniform paintformat20; + NoVariable paintformat20; Variable paintformat21; - PaintScaleUniformAroundCenter paintformat22; + NoVariable paintformat22; Variable paintformat23; - PaintRotate paintformat24; + NoVariable paintformat24; Variable paintformat25; - PaintRotateAroundCenter paintformat26; + NoVariable paintformat26; Variable paintformat27; - PaintSkew paintformat28; + NoVariable paintformat28; Variable paintformat29; - PaintSkewAroundCenter paintformat30; + NoVariable paintformat30; Variable paintformat31; PaintComposite paintformat32; } u; @@ -1163,7 +1830,8 @@ struct BaseGlyphPaintRecord { return g < glyphId ? -1 : g > glyphId ? 1 : 0; } bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map, - const void* src_base, hb_subset_context_t *c) const + const void* src_base, hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SERIALIZE (this); auto *out = s->embed (this); @@ -1172,7 +1840,7 @@ struct BaseGlyphPaintRecord HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - return_trace (out->paint.serialize_subset (c, paint, src_base)); + return_trace (out->paint.serialize_subset (c, paint, src_base, instancer)); } bool sanitize (hb_sanitize_context_t *c, const void *base) const @@ -1191,19 +1859,20 @@ struct BaseGlyphPaintRecord struct BaseGlyphList : SortedArray32Of { - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - const hb_set_t* glyphset = c->plan->_glyphset_colred; + const hb_set_t* glyphset = &c->plan->_glyphset_colred; for (const auto& _ : as_array ()) { unsigned gid = _.glyphId; if (!glyphset->has (gid)) continue; - if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++; + if (_.serialize (c->serializer, c->plan->glyph_map, this, c, instancer)) out->len++; else return_trace (false); } @@ -1222,7 +1891,8 @@ struct LayerList : Array32OfOffset32To const Paint& get_paint (unsigned i) const { return this+(*this)[i]; } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + const VarStoreInstancer &instancer) const { TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); @@ -1233,7 +1903,7 @@ struct LayerList : Array32OfOffset32To { auto *o = out->serialize_append (c->serializer); - if (unlikely (!o) || !o->serialize_subset (c, _.second, this)) + if (unlikely (!o) || !o->serialize_subset (c, _.second, this, instancer)) return_trace (false); } return_trace (true); @@ -1250,7 +1920,14 @@ struct COLR { static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; - bool has_data () const { return numBaseGlyphs; } + bool has_v0_data () const { return numBaseGlyphs; } + bool has_v1_data () const + { + if (version == 1) + return (this+baseGlyphList).len > 0; + + return false; + } unsigned int get_glyph_layers (hb_codepoint_t glyph, unsigned int start_offset, @@ -1359,7 +2036,7 @@ struct COLR (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && (this+layersZ).sanitize (c, numLayers) && (version == 0 || - (COLRV1_ENABLE_SUBSETTING && version == 1 && + (version == 1 && baseGlyphList.sanitize (c, this) && layerList.sanitize (c, this) && clipList.sanitize (c, this) && @@ -1428,9 +2105,8 @@ struct COLR bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; - const hb_set_t& glyphset = *c->plan->_glyphset_colred; + const hb_set_t& glyphset = c->plan->_glyphset_colred; auto base_it = + hb_range (c->plan->num_output_glyphs ()) @@ -1479,7 +2155,7 @@ struct COLR if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) return hb_pair_t> (false, out_layers); out_layers[i].glyphId = new_gid; - out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); + out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx); } return hb_pair_t> (true, out_layers); @@ -1499,7 +2175,12 @@ struct COLR auto snap = c->serializer->snapshot (); if (!c->serializer->allocate_size (5 * HBUINT32::static_size)) return_trace (false); - if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this)) + + VarStoreInstancer instancer (varStore ? &(this+varStore) : nullptr, + varIdxMap ? &(this+varIdxMap) : nullptr, + c->plan->normalized_coords.as_array ()); + + if (!colr_prime->baseGlyphList.serialize_subset (c, baseGlyphList, this, instancer)) { if (c->serializer->in_error ()) return_trace (false); //no more COLRv1 glyphs: downgrade to version 0 @@ -1509,13 +2190,181 @@ struct COLR if (!colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it)) return_trace (false); - colr_prime->layerList.serialize_subset (c, layerList, this); - colr_prime->clipList.serialize_subset (c, clipList, this); + colr_prime->layerList.serialize_subset (c, layerList, this, instancer); + colr_prime->clipList.serialize_subset (c, clipList, this, instancer); + if (!varStore || c->plan->all_axes_pinned) + return_trace (true); + colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); - //TODO: subset varStore once it's implemented in fonttools + colr_prime->varStore.serialize_copy (c->serializer, varStore, this); return_trace (true); } + const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const + { + const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; + const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph); + if (record) + { + const Paint &paint = &baseglyph_paintrecords+record->paint; + return &paint; + } + else + return nullptr; + } + +#ifndef HB_NO_PAINT + bool + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + { + if (version != 1) + return false; + + VarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), + hb_array (font->coords, font->num_coords)); + + if (get_clip (glyph, extents, instancer)) + { + font->scale_glyph_extents (extents); + return true; + } + + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0)); + + hb_extents_t e = extents_data.get_extents (); + if (e.is_void ()) + { + extents->x_bearing = 0; + extents->y_bearing = 0; + extents->width = 0; + extents->height = 0; + } + else + { + extents->x_bearing = e.xmin; + extents->y_bearing = e.ymax; + extents->width = e.xmax - e.xmin; + extents->height = e.ymin - e.ymax; + } + + return ret; + } +#endif + + bool + has_paint_for_glyph (hb_codepoint_t glyph) const + { + if (version == 1) + { + const Paint *paint = get_base_glyph_paint (glyph); + + return paint != nullptr; + } + + return false; + } + + bool get_clip (hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + const VarStoreInstancer instancer) const + { + return (this+clipList).get_extents (glyph, + extents, + instancer); + } + +#ifndef HB_NO_PAINT + bool + paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const + { + VarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), + hb_array (font->coords, font->num_coords)); + hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); + + if (version == 1) + { + const Paint *paint = get_base_glyph_paint (glyph); + if (paint) + { + // COLRv1 glyph + + VarStoreInstancer instancer (&(this+varStore), + &(this+varIdxMap), + hb_array (font->coords, font->num_coords)); + + bool is_bounded = true; + if (clip) + { + hb_glyph_extents_t extents; + if (get_clip (glyph, &extents, instancer)) + { + font->scale_glyph_extents (&extents); + c.funcs->push_clip_rectangle (c.data, + extents.x_bearing, + extents.y_bearing + extents.height, + extents.x_bearing + extents.width, + extents.y_bearing); + } + else + { + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + + paint_glyph (font, glyph, + extents_funcs, &extents_data, + palette_index, foreground, + false); + + hb_extents_t extents = extents_data.get_extents (); + is_bounded = extents_data.is_bounded (); + + c.funcs->push_clip_rectangle (c.data, + extents.xmin, + extents.ymin, + extents.xmax, + extents.ymax); + } + } + + c.funcs->push_root_transform (c.data, font); + + if (is_bounded) + c.recurse (*paint); + + c.funcs->pop_transform (c.data); + + if (clip) + c.funcs->pop_clip (c.data); + + return true; + } + } + + const BaseGlyphRecord *record = get_base_glyph_record (glyph); + if (record && ((hb_codepoint_t) record->glyphId == glyph)) + { + // COLRv0 glyph + for (const auto &r : (this+layersZ).as_array (numLayers) + .sub_array (record->firstLayerIdx, record->numLayers)) + { + hb_bool_t is_foreground; + hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground); + c.funcs->push_clip_glyph (c.data, r.glyphId, c.font); + c.funcs->color (c.data, is_foreground, color); + c.funcs->pop_clip (c.data); + } + + return true; + } + + return false; + } +#endif + protected: HBUINT16 version; /* Table version number (starts at 0). */ HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ @@ -1538,7 +2387,50 @@ struct COLR_accelerator_t : COLR::accelerator_t { COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} }; -} /* namespace OT */ +void +hb_paint_context_t::recurse (const Paint &paint) +{ + if (unlikely (depth_left <= 0 || edge_count <= 0)) return; + depth_left--; + edge_count--; + paint.dispatch (this); + depth_left++; +} + +void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const +{ + const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); + for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) + { + const Paint &paint = paint_offset_lists.get_paint (i); + c->funcs->push_group (c->data); + c->recurse (paint); + c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); + } +} + +void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const +{ + const COLR *colr_table = c->get_colr_table (); + const Paint *paint = colr_table->get_base_glyph_paint (gid); + hb_glyph_extents_t extents = {0}; + bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer); + + if (has_clip_box) + c->funcs->push_clip_rectangle (c->data, + extents.x_bearing, + extents.y_bearing + extents.height, + extents.x_bearing + extents.width, + extents.y_bearing); + + if (paint) + c->recurse (*paint); + + if (has_clip_box) + c->funcs->pop_clip (c->data); +} + +} /* namespace OT */ -#endif /* HB_OT_COLOR_COLR_TABLE_HH */ +#endif /* OT_COLOR_COLR_COLR_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color-colrv1-closure.hh b/third_party/harfbuzz-ng/src/src/OT/Color/COLR/colrv1-closure.hh similarity index 94% rename from third_party/harfbuzz-ng/src/src/hb-ot-color-colrv1-closure.hh rename to third_party/harfbuzz-ng/src/src/OT/Color/COLR/colrv1-closure.hh index fbaf2ec26b6b..705863d4ade5 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color-colrv1-closure.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Color/COLR/colrv1-closure.hh @@ -24,12 +24,11 @@ * */ -#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH -#define HB_OT_COLR_COLRV1_CLOSURE_HH +#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH +#define OT_COLOR_COLR_COLRV1_CLOSURE_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-color-colr-table.hh" +#include "../../../hb-open-type.hh" +#include "COLR.hh" /* * COLR -- Color @@ -105,4 +104,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons } /* namespace OT */ -#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */ +#endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color-cpal-table.hh b/third_party/harfbuzz-ng/src/src/OT/Color/CPAL/CPAL.hh similarity index 88% rename from third_party/harfbuzz-ng/src/src/hb-ot-color-cpal-table.hh rename to third_party/harfbuzz-ng/src/src/OT/Color/CPAL/CPAL.hh index bcab77f79dc7..c07716c1c987 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color-cpal-table.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Color/CPAL/CPAL.hh @@ -25,12 +25,12 @@ * Google Author(s): Sascha Brawer */ -#ifndef HB_OT_COLOR_CPAL_TABLE_HH -#define HB_OT_COLOR_CPAL_TABLE_HH +#ifndef OT_COLOR_CPAL_CPAL_HH +#define OT_COLOR_CPAL_CPAL_HH -#include "hb-open-type.hh" -#include "hb-ot-color.h" -#include "hb-ot-name.h" +#include "../../../hb-open-type.hh" +#include "../../../hb-ot-color.h" +#include "../../../hb-ot-name.h" /* @@ -73,6 +73,30 @@ struct CPALV1Tail } public: + void collect_name_ids (const void *base, + unsigned palette_count, + unsigned color_count, + const hb_map_t *color_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + if (paletteLabelsZ) + { + + (base+paletteLabelsZ).as_array (palette_count) + | hb_sink (nameids_to_retain) + ; + } + + if (colorLabelsZ) + { + const hb_array_t colorLabels = (base+colorLabelsZ).as_array (color_count); + for (unsigned i = 0; i < color_count; i++) + { + if (!color_index_map->has (i)) continue; + nameids_to_retain->add (colorLabels[i]); + } + } + } + bool serialize (hb_serialize_context_t *c, unsigned palette_count, unsigned color_count, @@ -95,13 +119,10 @@ struct CPALV1Tail if (colorLabelsZ) { c->push (); - for (const auto _ : colorLabels) + for (unsigned i = 0; i < color_count; i++) { - const hb_codepoint_t *v; - if (!color_index_map->has (_, &v)) continue; - NameID new_color_idx; - new_color_idx = *v; - if (!c->copy (new_color_idx)) + if (!color_index_map->has (i)) continue; + if (!c->copy (colorLabels[i])) { c->pop_discard (); return_trace (false); @@ -189,6 +210,13 @@ struct CPAL return numColors; } + void collect_name_ids (const hb_map_t *color_index_map, + hb_set_t *nameids_to_retain /* OUT */) const + { + if (version == 1) + v1 ().collect_name_ids (this, numPalettes, numColors, color_index_map, nameids_to_retain); + } + private: const CPALV1Tail& v1 () const { @@ -239,7 +267,7 @@ struct CPAL TRACE_SUBSET (this); if (!numPalettes) return_trace (false); - const hb_map_t *color_index_map = c->plan->colr_palettes; + const hb_map_t *color_index_map = &c->plan->colr_palettes; if (color_index_map->is_empty ()) return_trace (false); hb_set_t retained_color_indices; @@ -319,4 +347,4 @@ struct CPAL } /* namespace OT */ -#endif /* HB_OT_COLOR_CPAL_TABLE_HH */ +#endif /* OT_COLOR_CPAL_CPAL_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color-sbix-table.hh b/third_party/harfbuzz-ng/src/src/OT/Color/sbix/sbix.hh similarity index 88% rename from third_party/harfbuzz-ng/src/src/hb-ot-color-sbix-table.hh rename to third_party/harfbuzz-ng/src/src/OT/Color/sbix/sbix.hh index d0e2235fb2f0..46ad3fd58e10 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color-sbix-table.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Color/sbix/sbix.hh @@ -25,11 +25,11 @@ * Google Author(s): Calder Kitagawa */ -#ifndef HB_OT_COLOR_SBIX_TABLE_HH -#define HB_OT_COLOR_SBIX_TABLE_HH +#ifndef OT_COLOR_SBIX_SBIX_HH +#define OT_COLOR_SBIX_SBIX_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-paint.hh" /* * sbix -- Standard Bitmap Graphics @@ -213,10 +213,11 @@ struct sbix bool get_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + hb_glyph_extents_t *extents, + bool scale = true) const { /* We only support PNG right now, and following function checks type. */ - return get_png_extents (font, glyph, extents); + return get_png_extents (font, glyph, extents, scale); } hb_blob_t *reference_png (hb_font_t *font, @@ -231,6 +232,37 @@ struct sbix num_glyphs, available_ppem); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + if (!has_data ()) + return false; + + int x_offset = 0, y_offset = 0; + unsigned int strike_ppem = 0; + hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); + hb_glyph_extents_t extents; + hb_glyph_extents_t pixel_extents; + + if (blob == hb_blob_get_empty ()) + return false; + + if (!hb_font_get_glyph_extents (font, glyph, &extents)) + return false; + + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + return false; + + bool ret = funcs->image (data, + blob, + pixel_extents.width, -pixel_extents.height, + HB_PAINT_IMAGE_FORMAT_PNG, + font->slant_xy, + &extents); + + hb_blob_destroy (blob); + return ret; + } + private: const SBIXStrike &choose_strike (hb_font_t *font) const @@ -285,7 +317,8 @@ struct sbix bool get_png_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + hb_glyph_extents_t *extents, + bool scale = true) const { /* Following code is safe to call even without data. * But faster to short-circuit. */ @@ -310,22 +343,18 @@ struct sbix extents->height = -1 * png.IHDR.height; /* Convert to font units. */ - if (strike_ppem) + if (strike_ppem && scale) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); - extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); - extents->width = font->em_scalef_x (extents->width * scale); - extents->height = font->em_scalef_y (extents->height * scale); - } - else - { - extents->x_bearing = font->em_scale_x (extents->x_bearing); - extents->y_bearing = font->em_scale_y (extents->y_bearing); - extents->width = font->em_scale_x (extents->width); - extents->height = font->em_scale_y (extents->height); + extents->x_bearing = roundf (extents->x_bearing * scale); + extents->y_bearing = roundf (extents->y_bearing * scale); + extents->width = roundf (extents->width * scale); + extents->height = roundf (extents->height * scale); } + if (scale) + font->scale_glyph_extents (extents); + hb_blob_destroy (blob); return strike_ppem; @@ -420,4 +449,4 @@ struct sbix_accelerator_t : sbix::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_SBIX_TABLE_HH */ +#endif /* OT_COLOR_SBIX_SBIX_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color-svg-table.hh b/third_party/harfbuzz-ng/src/src/OT/Color/svg/svg.hh similarity index 83% rename from third_party/harfbuzz-ng/src/src/hb-ot-color-svg-table.hh rename to third_party/harfbuzz-ng/src/src/OT/Color/svg/svg.hh index fc649f1006d3..c7d91b88ee0e 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color-svg-table.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Color/svg/svg.hh @@ -22,10 +22,12 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#ifndef HB_OT_COLOR_SVG_TABLE_HH -#define HB_OT_COLOR_SVG_TABLE_HH +#ifndef OT_COLOR_SVG_SVG_HH +#define OT_COLOR_SVG_SVG_HH -#include "hb-open-type.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-blob.hh" +#include "../../../hb-paint.hh" /* * SVG -- SVG (Scalable Vector Graphics) @@ -91,8 +93,31 @@ struct SVG bool has_data () const { return table->has_data (); } + bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + if (!has_data ()) + return false; + + hb_blob_t *blob = reference_blob_for_glyph (glyph); + + if (blob == hb_blob_get_empty ()) + return false; + + funcs->image (data, + blob, + 0, 0, + HB_PAINT_IMAGE_FORMAT_SVG, + font->slant_xy, + nullptr); + + hb_blob_destroy (blob); + return true; + } + private: hb_blob_ptr_t table; + public: + DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t)); }; const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const @@ -123,4 +148,4 @@ struct SVG_accelerator_t : SVG::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_SVG_TABLE_HH */ +#endif /* OT_COLOR_SVG_SVG_HH */ diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/Common/Coverage.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/Common/Coverage.hh index a7befd61cd94..d35654e24573 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/Common/Coverage.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/Common/Coverage.hh @@ -74,10 +74,8 @@ struct Coverage } /* Has interface. */ - static constexpr unsigned SENTINEL = NOT_COVERED; - typedef unsigned int value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + unsigned operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } @@ -149,6 +147,7 @@ struct Coverage TRACE_SUBSET (this); auto it = + iter () + | hb_take (c->plan->source->get_num_glyphs ()) | hb_filter (c->plan->glyph_map_gsub) | hb_map_retains_sorting (c->plan->glyph_map_gsub) ; @@ -225,7 +224,7 @@ struct Coverage static constexpr bool is_sorted_iterator = true; iter_t (const Coverage &c_ = Null (Coverage)) { - memset (this, 0, sizeof (*this)); + hb_memset (this, 0, sizeof (*this)); format = c_.u.format; switch (format) { diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat1.hh index 82fd48dc50d5..5d68e3d15e7e 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat1.hh @@ -77,7 +77,14 @@ struct CoverageFormat1_3 bool intersects (const hb_set_t *glyphs) const { - /* TODO Speed up, using hb_set_next() and bsearch()? */ + if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + if (get_coverage (g) != NOT_COVERED) + return true; + return false; + } + for (const auto& g : glyphArray.as_array ()) if (glyphs->has (g)) return true; diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat2.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat2.hh index 974d094633a2..d7fcc3520283 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat2.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/Common/CoverageFormat2.hh @@ -80,8 +80,6 @@ struct CoverageFormat2_4 TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); - /* TODO(iter) Write more efficiently? */ - unsigned num_ranges = 0; hb_codepoint_t last = (hb_codepoint_t) -2; for (auto g: glyphs) @@ -115,26 +113,22 @@ struct CoverageFormat2_4 bool intersects (const hb_set_t *glyphs) const { + if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + if (get_coverage (g) != NOT_COVERED) + return true; + return false; + } + return hb_any (+ hb_iter (rangeRecord) | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (*glyphs); })); } bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const { - auto cmp = [] (const void *pk, const void *pr) -> int - { - unsigned index = * (const unsigned *) pk; - const RangeRecord &range = * (const RangeRecord *) pr; - if (index < range.value) return -1; - if (index > (unsigned int) range.value + (range.last - range.first)) return +1; - return 0; - }; - - auto arr = rangeRecord.as_array (); - unsigned idx; - if (hb_bsearch_impl (&idx, index, - arr.arrayZ, arr.length, sizeof (arr[0]), - (int (*)(const void *_key, const void *_item)) cmp)) - return arr.arrayZ[idx].intersects (*glyphs); + auto *range = rangeRecord.as_array ().bsearch (index); + if (range) + return range->intersects (*glyphs); return false; } @@ -142,9 +136,14 @@ struct CoverageFormat2_4 hb_requires (hb_is_sink_of (IterableOut, hb_codepoint_t))> void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const { + /* Break out of loop for overlapping, broken, tables, + * to avoid fuzzer timouts. */ + hb_codepoint_t last = 0; for (const auto& range : rangeRecord) { - hb_codepoint_t last = range.last; + if (unlikely (range.first < last)) + break; + last = range.last; for (hb_codepoint_t g = range.first - 1; glyphs.next (&g) && g <= last;) intersect_glyphs << g; diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GDEF/GDEF.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GDEF/GDEF.hh new file mode 100644 index 000000000000..0551fcf812a3 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GDEF/GDEF.hh @@ -0,0 +1,918 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef OT_LAYOUT_GDEF_GDEF_HH +#define OT_LAYOUT_GDEF_GDEF_HH + +#include "../../../hb-ot-layout-common.hh" + +#include "../../../hb-font.hh" + + +namespace OT { + + +/* + * Attachment List Table + */ + +/* Array of contour point indices--in increasing numerical order */ +struct AttachPoint : Array16Of +{ + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->serialize (c->serializer, + iter ())); + } +}; + +struct AttachList +{ + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (index == NOT_COVERED) + { + if (point_count) + *point_count = 0; + return 0; + } + + const AttachPoint &points = this+attachPoint[index]; + + if (point_count) + { + + points.as_array ().sub_array (start_offset, point_count) + | hb_sink (hb_array (point_array, *point_count)) + ; + } + + return points.len; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, attachPoint) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); + } + + protected: + Offset16To + coverage; /* Offset to Coverage table -- from + * beginning of AttachList table */ + Array16OfOffset16To + attachPoint; /* Array of AttachPoint tables + * in Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (4, attachPoint); +}; + +/* + * Ligature Caret Table + */ + +struct CaretValueFormat1 +{ + friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + + private: + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ + FWORD coordinate; /* X or Y value, in design units */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CaretValueFormat2 +{ + friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + + private: + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const + { + hb_position_t x, y; + font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); + return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ + HBUINT16 caretValuePoint; /* Contour point index on glyph */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CaretValueFormat3 +{ + friend struct CaretValue; + + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, + const VariationStore &var_store) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? + font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : + font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + if (!c->serializer->embed (caretValueFormat)) return_trace (false); + if (!c->serializer->embed (coordinate)) return_trace (false); + + unsigned varidx = (this+deviceTable).get_variation_index (); + if (c->plan->layout_variation_idx_delta_map.has (varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } + + if (c->plan->all_axes_pinned) + return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + + if (!c->serializer->embed (deviceTable)) + return_trace (false); + + return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), + hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { (this+deviceTable).collect_variation_indices (c); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ + FWORD coordinate; /* X or Y value, in design units */ + Offset16To + deviceTable; /* Offset to Device table for X or Y + * value--from beginning of CaretValue + * table */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct CaretValue +{ + hb_position_t get_caret_value (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store) const + { + switch (u.format) { + case 1: return u.format1.get_caret_value (font, direction); + case 2: return u.format2.get_caret_value (font, direction, glyph_id); + case 3: return u.format3.get_caret_value (font, direction, var_store); + default:return 0; + } + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + switch (u.format) { + case 1: + case 2: + return; + case 3: + u.format3.collect_variation_indices (c); + return; + default: return; + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + CaretValueFormat1 format1; + CaretValueFormat2 format2; + CaretValueFormat3 format3; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +struct LigGlyph +{ + unsigned get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned start_offset, + unsigned *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + if (caret_count) + { + + carets.as_array ().sub_array (start_offset, caret_count) + | hb_map (hb_add (this)) + | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); }) + | hb_sink (hb_array (caret_array, *caret_count)) + ; + } + + return carets.len; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (carets) + | hb_apply (subset_offset_array (c, out->carets, this)) + ; + + return_trace (bool (out->carets)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const Offset16To& offset : carets.iter ()) + (this+offset).collect_variation_indices (c); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (carets.sanitize (c, this)); + } + + protected: + Array16OfOffset16To + carets; /* Offset array of CaretValue tables + * --from beginning of LigGlyph table + * --in increasing coordinate order */ + public: + DEFINE_SIZE_ARRAY (2, carets); +}; + +struct LigCaretList +{ + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (index == NOT_COVERED) + { + if (caret_count) + *caret_count = 0; + return 0; + } + const LigGlyph &lig_glyph = this+ligGlyph[index]; + return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ligGlyph) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, ligGlyph) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) + ; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); + } + + protected: + Offset16To + coverage; /* Offset to Coverage table--from + * beginning of LigCaretList table */ + Array16OfOffset16To + ligGlyph; /* Array of LigGlyph tables + * in Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (4, ligGlyph); +}; + + +struct MarkGlyphSetsFormat1 +{ + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + bool ret = true; + for (const Offset32To& offset : coverage.iter ()) + { + auto *o = out->coverage.serialize_append (c->serializer); + if (unlikely (!o)) + { + ret = false; + break; + } + + //not using o->serialize_subset (c, offset, this, out) here because + //OTS doesn't allow null offset. + //See issue: https://github.com/khaledhosny/ots/issues/172 + c->serializer->push (); + c->dispatch (this+offset); + c->serializer->add_link (*o, c->serializer->pop_pack ()); + } + + return_trace (ret && out->coverage.len); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Array16Of> + coverage; /* Array of long offsets to mark set + * coverage tables */ + public: + DEFINE_SIZE_ARRAY (4, coverage); +}; + +struct MarkGlyphSets +{ + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.covers (set_index, glyph_id); + default:return false; + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c)); + default:return_trace (false); + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + MarkGlyphSetsFormat1 format1; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + + +/* + * GDEF -- Glyph Definition + * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef + */ + + +template +struct GDEFVersion1_2 +{ + friend struct GDEF; + + protected: + FixedVersion<>version; /* Version of the GDEF table--currently + * 0x00010003u */ + typename Types::template OffsetTo + glyphClassDef; /* Offset to class definition table + * for glyph type--from beginning of + * GDEF header (may be Null) */ + typename Types::template OffsetTo + attachList; /* Offset to list of glyphs with + * attachment points--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + ligCaretList; /* Offset to list of positioning points + * for ligature carets--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + markAttachClassDef; /* Offset to class definition table for + * mark attachment type--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + markGlyphSetsDef; /* Offset to the table of mark set + * definitions--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010002. */ + Offset32To + varStore; /* Offset to the table of Item Variation + * Store--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010003. */ + public: + DEFINE_SIZE_MIN (4 + 4 * Types::size); + + unsigned int get_size () const + { + return min_size + + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + + (version.to_int () >= 0x00010003u ? varStore.static_size : 0); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && + (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); + bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); + bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); + bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); + + bool subset_markglyphsetsdef = false; + if (version.to_int () >= 0x00010002u) + { + subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); + } + + bool subset_varstore = false; + if (version.to_int () >= 0x00010003u) + { + if (c->plan->all_axes_pinned) + out->varStore = 0; + else + subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); + } + + if (subset_varstore) + { + out->version.minor = 3; + } else if (subset_markglyphsetsdef) { + out->version.minor = 2; + } else { + out->version.minor = 0; + } + + return_trace (subset_glyphclassdef || subset_attachlist || + subset_ligcaretlist || subset_markattachclassdef || + (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || + (out->version.to_int () >= 0x00010003u && subset_varstore)); + } +}; + +struct GDEF +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; + + enum GlyphClasses { + UnclassifiedGlyph = 0, + BaseGlyph = 1, + LigatureGlyph = 2, + MarkGlyph = 3, + ComponentGlyph = 4 + }; + + unsigned int get_size () const + { + switch (u.version.major) { + case 1: return u.version1.get_size (); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.get_size (); +#endif + default: return u.version.static_size; + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.version.sanitize (c))) return_trace (false); + switch (u.version.major) { + case 1: return_trace (u.version1.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (u.version2.sanitize (c)); +#endif + default: return_trace (true); + } + } + + bool subset (hb_subset_context_t *c) const + { + switch (u.version.major) { + case 1: return u.version1.subset (c); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.subset (c); +#endif + default: return false; + } + } + + bool has_glyph_classes () const + { + switch (u.version.major) { + case 1: return u.version1.glyphClassDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.glyphClassDef != 0; +#endif + default: return false; + } + } + const ClassDef &get_glyph_class_def () const + { + switch (u.version.major) { + case 1: return this+u.version1.glyphClassDef; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.glyphClassDef; +#endif + default: return Null(ClassDef); + } + } + bool has_attach_list () const + { + switch (u.version.major) { + case 1: return u.version1.attachList != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.attachList != 0; +#endif + default: return false; + } + } + const AttachList &get_attach_list () const + { + switch (u.version.major) { + case 1: return this+u.version1.attachList; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.attachList; +#endif + default: return Null(AttachList); + } + } + bool has_lig_carets () const + { + switch (u.version.major) { + case 1: return u.version1.ligCaretList != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.ligCaretList != 0; +#endif + default: return false; + } + } + const LigCaretList &get_lig_caret_list () const + { + switch (u.version.major) { + case 1: return this+u.version1.ligCaretList; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.ligCaretList; +#endif + default: return Null(LigCaretList); + } + } + bool has_mark_attachment_types () const + { + switch (u.version.major) { + case 1: return u.version1.markAttachClassDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.markAttachClassDef != 0; +#endif + default: return false; + } + } + const ClassDef &get_mark_attach_class_def () const + { + switch (u.version.major) { + case 1: return this+u.version1.markAttachClassDef; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.markAttachClassDef; +#endif + default: return Null(ClassDef); + } + } + bool has_mark_glyph_sets () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.markGlyphSetsDef != 0; +#endif + default: return false; + } + } + const MarkGlyphSets &get_mark_glyph_sets () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets); +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.markGlyphSetsDef; +#endif + default: return Null(MarkGlyphSets); + } + } + bool has_var_store () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.varStore != 0; +#endif + default: return false; + } + } + const VariationStore &get_var_store () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore); +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.varStore; +#endif + default: return Null(VariationStore); + } + } + + + bool has_data () const { return u.version.to_int (); } + unsigned int get_glyph_class (hb_codepoint_t glyph) const + { return get_glyph_class_def ().get_class (glyph); } + void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const + { get_glyph_class_def ().collect_class (glyphs, klass); } + + unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const + { return get_mark_attach_class_def ().get_class (glyph); } + + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); } + + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { return get_lig_caret_list ().get_lig_carets (font, + direction, glyph_id, get_var_store(), + start_offset, caret_count, caret_array); } + + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { return get_mark_glyph_sets ().covers (set_index, glyph_id); } + + /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing + * glyph class and other bits, and high 8-bit the mark attachment type (if any). + * Not to be confused with lookup_props which is very similar. */ + unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned int klass = get_glyph_class (glyph); + + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); + + switch (klass) { + default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; + case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; + case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; + case MarkGlyph: + klass = get_mark_attachment_type (glyph); + return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); + } + } + + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + table = hb_sanitize_context_t ().reference_table (face); + if (unlikely (table->is_blocklisted (table.get_blob (), face))) + { + hb_blob_destroy (table.get_blob ()); + table = hb_blob_get_empty (); + } + } + ~accelerator_t () { table.destroy (); } + + hb_blob_ptr_t table; + }; + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { get_lig_caret_list ().collect_variation_indices (c); } + + void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, + hb_hashmap_t> *layout_variation_idx_delta_map /* OUT */) const + { + if (!has_var_store ()) return; + if (layout_variation_indices->is_empty ()) return; + + unsigned new_major = 0, new_minor = 0; + unsigned last_major = (layout_variation_indices->get_min ()) >> 16; + for (unsigned idx : layout_variation_indices->iter ()) + { + uint16_t major = idx >> 16; + if (major >= get_var_store ().get_sub_table_count ()) break; + if (major != last_major) + { + new_minor = 0; + ++new_major; + } + + unsigned new_idx = (new_major << 16) + new_minor; + if (!layout_variation_idx_delta_map->has (idx)) + continue; + int delta = hb_second (layout_variation_idx_delta_map->get (idx)); + + layout_variation_idx_delta_map->set (idx, hb_pair_t (new_idx, delta)); + ++new_minor; + last_major = major; + } + } + + protected: + union { + FixedVersion<> version; /* Version identifier */ + GDEFVersion1_2 version1; +#ifndef HB_NO_BEYOND_64K + GDEFVersion1_2 version2; +#endif + } u; + public: + DEFINE_SIZE_MIN (4); +}; + +struct GDEF_accelerator_t : GDEF::accelerator_t { + GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} +}; + +} /* namespace OT */ + + +#endif /* OT_LAYOUT_GDEF_GDEF_HH */ diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/AnchorFormat3.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/AnchorFormat3.hh index 2e30ab33c361..e7e3c5c6d1ea 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/AnchorFormat3.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/AnchorFormat3.hh @@ -51,9 +51,9 @@ struct AnchorFormat3 if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - if (c->plan->layout_variation_idx_delta_map->has (x_varidx)) + if (c->plan->layout_variation_idx_delta_map.has (x_varidx)) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx)); + int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx)); if (delta != 0) { if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, @@ -63,9 +63,9 @@ struct AnchorFormat3 } unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; - if (c->plan->layout_variation_idx_delta_map->has (y_varidx)) + if (c->plan->layout_variation_idx_delta_map.has (y_varidx)) { - int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx)); + int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx)); if (delta != 0) { if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, @@ -80,8 +80,8 @@ struct AnchorFormat3 if (!c->serializer->embed (xDeviceTable)) return_trace (false); if (!c->serializer->embed (yDeviceTable)) return_trace (false); - out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); - out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map); + out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); + out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); return_trace (out); } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePos.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePos.hh index c105cfb09165..0105a9b85427 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePos.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePos.hh @@ -19,8 +19,8 @@ struct CursivePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePosFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePosFormat1.hh index 7f58fac8b8ed..ff255e090a28 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/CursivePosFormat1.hh @@ -143,7 +143,7 @@ struct CursivePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "cursive attaching glyph at %d to glyph at %d", + "cursive attaching glyph at %u to glyph at %u", i, j); } @@ -241,7 +241,7 @@ struct CursivePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "cursive attached glyph at %d to glyph at %d", + "cursive attached glyph at %u to glyph at %u", i, j); } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkArray.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkArray.hh index cb5e8b26896e..ff43ffb8c571 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkArray.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkArray.hh @@ -42,7 +42,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "attaching mark glyph at %d to glyph at %d", + "attaching mark glyph at %u to glyph at %u", c->buffer->idx, glyph_pos); } @@ -56,7 +56,7 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "attached mark glyph at %d to glyph at %d", + "attached mark glyph at %u to glyph at %u", c->buffer->idx, glyph_pos); } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePos.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePos.hh index edf7099c072b..cd2fc7ccfdd2 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePos.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePos.hh @@ -22,8 +22,8 @@ struct MarkBasePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh index ebb8c31c679c..eb4712049b16 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -90,6 +90,25 @@ struct MarkBasePosFormat1_2 const Coverage &get_coverage () const { return this+markCoverage; } + static inline bool accept (hb_buffer_t *buffer, unsigned idx) + { + /* We only want to attach to the first of a MultipleSubst sequence. + * https://github.com/harfbuzz/harfbuzz/issues/740 + * Reject others... + * ...but stop if we find a mark in the MultipleSubst sequence: + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ + return !_hb_glyph_info_multiplied (&buffer->info[idx]) || + 0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) || + (idx == 0 || + _hb_glyph_info_is_mark (&buffer->info[idx - 1]) || + !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) || + _hb_glyph_info_get_lig_id (&buffer->info[idx]) != + _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) || + _hb_glyph_info_get_lig_comp (&buffer->info[idx]) != + _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1 + ); + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -97,48 +116,54 @@ struct MarkBasePosFormat1_2 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); if (likely (mark_index == NOT_COVERED)) return_trace (false); - /* Now we search backwards for a non-mark glyph */ + /* Now we search backwards for a non-mark glyph. + * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - do { - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + + if (c->last_base_until > buffer->idx) + { + c->last_base_until = 0; + c->last_base = -1; + } + unsigned j; + for (j = buffer->idx; j > c->last_base_until; j--) + { + auto match = skippy_iter.match (buffer->info[j - 1]); + if (match == skippy_iter.MATCH) + { + // https://github.com/harfbuzz/harfbuzz/issues/4124 + if (!accept (buffer, j - 1) && + NOT_COVERED == (this+baseCoverage).get_coverage (buffer->info[j - 1].codepoint)) + match = skippy_iter.SKIP; + } + if (match == skippy_iter.MATCH) { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); + c->last_base = (signed) j - 1; + break; } + } + c->last_base_until = buffer->idx; + if (c->last_base == -1) + { + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); + return_trace (false); + } - /* We only want to attach to the first of a MultipleSubst sequence. - * https://github.com/harfbuzz/harfbuzz/issues/740 - * Reject others... - * ...but stop if we find a mark in the MultipleSubst sequence: - * https://github.com/harfbuzz/harfbuzz/issues/1020 */ - if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || - 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || - (skippy_iter.idx == 0 || - _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || - !_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1 - )) - break; - skippy_iter.reject (); - } while (true); + unsigned idx = (unsigned) c->last_base; /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } + //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); } - unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); + unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint); if (base_index == NOT_COVERED) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } - return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); + return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx)); } bool subset (hb_subset_context_t *c) const diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPos.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPos.hh index 09152fd876e2..739c325411cc 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPos.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPos.hh @@ -22,8 +22,8 @@ struct MarkLigPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh index 1a8021237e2b..92e83a0e9948 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -100,24 +100,41 @@ struct MarkLigPosFormat1_2 if (likely (mark_index == NOT_COVERED)) return_trace (false); /* Now we search backwards for a non-mark glyph */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + + if (c->last_base_until > buffer->idx) { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + c->last_base_until = 0; + c->last_base = -1; + } + unsigned j; + for (j = buffer->idx; j > c->last_base_until; j--) + { + auto match = skippy_iter.match (buffer->info[j - 1]); + if (match == skippy_iter.MATCH) + { + c->last_base = (signed) j - 1; + break; + } + } + c->last_base_until = buffer->idx; + if (c->last_base == -1) + { + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); return_trace (false); } + unsigned idx = (unsigned) c->last_base; + /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } + //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); } - unsigned int j = skippy_iter.idx; - unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); + unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[idx].codepoint); if (lig_index == NOT_COVERED) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } @@ -128,7 +145,7 @@ struct MarkLigPosFormat1_2 unsigned int comp_count = lig_attach.rows; if (unlikely (!comp_count)) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } @@ -137,7 +154,7 @@ struct MarkLigPosFormat1_2 * can directly use the component index. If not, we attach the mark * glyph to the last component of the ligature. */ unsigned int comp_index; - unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]); + unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]); unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (lig_id && lig_id == mark_id && mark_comp > 0) @@ -145,7 +162,7 @@ struct MarkLigPosFormat1_2 else comp_index = comp_count - 1; - return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j)); + return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx)); } bool subset (hb_subset_context_t *c) const diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkMarkPos.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkMarkPos.hh index 4118fc304ffc..cddd2a3d5077 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkMarkPos.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/MarkMarkPos.hh @@ -22,8 +22,8 @@ struct MarkMarkPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPos.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPos.hh index 9823768cbc19..c13d4f48941c 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPos.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPos.hh @@ -25,8 +25,8 @@ struct PairPos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat1.hh index ddf7313f94ba..4dada1c83011 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat1.hh @@ -43,7 +43,7 @@ struct PairPosFormat1_3 { valueFormat, len1, - 1 + len1 + len2 + PairSet::get_size (len1, len2) }; return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); @@ -51,8 +51,21 @@ struct PairPosFormat1_3 bool intersects (const hb_set_t *glyphs) const { + auto &cov = this+coverage; + + if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) + { + for (hb_codepoint_t g : glyphs->iter()) + { + unsigned i = cov.get_coverage (g); + if ((this+pairSet[i]).intersects (glyphs, valueFormat)) + return true; + } + return false; + } + return - + hb_zip (this+coverage, pairSet) + + hb_zip (cov, pairSet) | hb_filter (*glyphs, hb_first) | hb_map (hb_second) | hb_map ([glyphs, this] (const typename Types::template OffsetTo &_) @@ -164,19 +177,21 @@ struct PairPosFormat1_3 hb_pair_t compute_effective_value_formats (const hb_set_t& glyphset) const { - unsigned len1 = valueFormat[0].get_len (); - unsigned len2 = valueFormat[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + unsigned record_size = PairSet::get_size (valueFormat); unsigned format1 = 0; unsigned format2 = 0; for (const auto & _ : - + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second)) + + hb_zip (this+coverage, pairSet) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + ) { const PairSet& set = (this + _); const PairValueRecord *record = &set.firstPairValueRecord; - for (unsigned i = 0; i < set.len; i++) + unsigned count = set.len; + for (unsigned i = 0; i < count; i++) { if (record->intersects (glyphset)) { @@ -185,6 +200,9 @@ struct PairPosFormat1_3 } record = &StructAtOffset (record, record_size); } + + if (format1 == valueFormat[0] && format2 == valueFormat[1]) + break; } return hb_pair (format1, format2); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat2.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat2.hh index 83b093b98830..de15a29e3cf5 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat2.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairPosFormat2.hh @@ -49,7 +49,7 @@ struct PairPosFormat2_4 unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); - unsigned int stride = len1 + len2; + unsigned int stride = HBUINT16::static_size * (len1 + len2); unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; return_trace (c->check_range ((const void *) values, @@ -220,17 +220,25 @@ struct PairPosFormat2_4 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerning glyphs at %d,%d", + "try kerning glyphs at %u,%u", c->buffer->idx, skippy_iter.idx); } applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + if (applied_first || applied_second) + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "kerned glyphs at %u,%u", + c->buffer->idx, skippy_iter.idx); + } + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerned glyphs at %d,%d", + "tried kerning glyphs at %u,%u", c->buffer->idx, skippy_iter.idx); } @@ -241,10 +249,15 @@ struct PairPosFormat2_4 boring: buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + if (len2) + { + skippy_iter.idx++; + // https://github.com/harfbuzz/harfbuzz/issues/3824 + // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 + buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + } buffer->idx = skippy_iter.idx; - if (len2) - buffer->idx++; return_trace (true); } @@ -285,8 +298,8 @@ struct PairPosFormat2_4 for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map); - valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_map); + valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map); + valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); } } @@ -309,6 +322,7 @@ struct PairPosFormat2_4 { unsigned len1 = valueFormat1.get_len (); unsigned len2 = valueFormat2.get_len (); + unsigned record_size = len1 + len2; unsigned format1 = 0; unsigned format2 = 0; @@ -317,10 +331,13 @@ struct PairPosFormat2_4 { for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size; format1 = format1 | valueFormat1.get_effective_format (&values[idx]); format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); } + + if (format1 == valueFormat1 && format2 == valueFormat2) + break; } return hb_pair (format1, format2); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairSet.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairSet.hh index aa48d933c398..147b8e00ea63 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairSet.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/PairSet.hh @@ -24,11 +24,22 @@ struct PairSet public: DEFINE_SIZE_MIN (2); + static unsigned get_size (unsigned len1, unsigned len2) + { + return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); + } + static unsigned get_size (const ValueFormat valueFormats[2]) + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + return get_size (len1, len2); + } + struct sanitize_closure_t { const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ - unsigned int stride; /* 1 + len1 + len2 */ + unsigned int stride; /* bytes */ }; bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const @@ -37,7 +48,6 @@ struct PairSet if (!(c->check_struct (this) && c->check_range (&firstPairValueRecord, len, - HBUINT16::static_size, closure->stride))) return_trace (false); unsigned int count = len; @@ -49,9 +59,7 @@ struct PairSet bool intersects (const hb_set_t *glyphs, const ValueFormat *valueFormats) const { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (valueFormats); const PairValueRecord *record = &firstPairValueRecord; unsigned int count = len; @@ -67,9 +75,7 @@ struct PairSet void collect_glyphs (hb_collect_glyphs_context_t *c, const ValueFormat *valueFormats) const { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (valueFormats); const PairValueRecord *record = &firstPairValueRecord; c->input->add_array (&record->secondGlyph, len, record_size); @@ -78,9 +84,7 @@ struct PairSet void collect_variation_indices (hb_collect_variation_indices_context_t *c, const ValueFormat *valueFormats) const { - unsigned len1 = valueFormats[0].get_len (); - unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (valueFormats); const PairValueRecord *record = &firstPairValueRecord; unsigned count = len; @@ -101,7 +105,7 @@ struct PairSet hb_buffer_t *buffer = c->buffer; unsigned int len1 = valueFormats[0].get_len (); unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); + unsigned record_size = get_size (len1, len2); const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, &firstPairValueRecord, @@ -112,24 +116,38 @@ struct PairSet if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerning glyphs at %d,%d", + "try kerning glyphs at %u,%u", c->buffer->idx, pos); } bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + if (applied_first || applied_second) + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "kerned glyphs at %u,%u", + c->buffer->idx, pos); + } + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "kerned glyphs at %d,%d", + "tried kerning glyphs at %u,%u", c->buffer->idx, pos); } if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, pos + 1); + if (len2) - pos++; + { + pos++; + // https://github.com/harfbuzz/harfbuzz/issues/3824 + // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 + buffer->unsafe_to_break (buffer->idx, pos + 1); + } buffer->idx = pos; return_trace (true); @@ -154,7 +172,7 @@ struct PairSet unsigned len1 = valueFormats[0].get_len (); unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + unsigned record_size = get_size (len1, len2); typename PairValueRecord::context_t context = { @@ -163,7 +181,7 @@ struct PairSet newFormats, len1, &glyph_map, - c->plan->layout_variation_idx_delta_map + &c->plan->layout_variation_idx_delta_map }; const PairValueRecord *record = &firstPairValueRecord; diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePos.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePos.hh index 6dce3e634368..3af6c4996594 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePos.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePos.hh @@ -72,8 +72,8 @@ struct SinglePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat1.hh index b4c9fc3db005..623e4e66b20c 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat1.hh @@ -28,7 +28,15 @@ struct SinglePosFormat1 TRACE_SANITIZE (this); return_trace (c->check_struct (this) && coverage.sanitize (c, this) && + /* The coverage table may use a range to represent a set + * of glyphs, which means a small number of bytes can + * generate a large glyph set. Manually modify the + * sanitizer max ops to take this into account. + * + * Note: This check *must* be right after coverage sanitize. */ + c->check_ops ((this + coverage).get_population () >> 1) && valueFormat.sanitize_value (c, this, values)); + } bool intersects (const hb_set_t *glyphs) const @@ -63,7 +71,7 @@ struct SinglePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioning glyph at %d", + "positioning glyph at %u", c->buffer->idx); } @@ -72,7 +80,7 @@ struct SinglePosFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioned glyph at %d", + "positioned glyph at %u", c->buffer->idx); } @@ -144,7 +152,7 @@ struct SinglePosFormat1 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); return_trace (ret); } }; diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat2.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat2.hh index c77951156b98..e8f2d7c2c6e2 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/SinglePosFormat2.hh @@ -73,7 +73,7 @@ struct SinglePosFormat2 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioning glyph at %d", + "positioning glyph at %u", c->buffer->idx); } @@ -84,7 +84,7 @@ struct SinglePosFormat2 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "positioned glyph at %d", + "positioned glyph at %u", c->buffer->idx); } @@ -163,7 +163,7 @@ struct SinglePosFormat2 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); return_trace (ret); } }; diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/ValueFormat.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/ValueFormat.hh index 26a40f01a327..1aa451abcc83 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/ValueFormat.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GPOS/ValueFormat.hh @@ -371,7 +371,7 @@ struct ValueFormat : HBUINT16 for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) return_trace (false); - values += stride; + values = &StructAtOffset (values, stride); } return_trace (true); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSet.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSet.hh index 4a9e9672ebc5..b4466119be0b 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSet.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSet.hh @@ -61,7 +61,7 @@ struct AlternateSet { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (alternate substitution)", + "replacing glyph at %u (alternate substitution)", c->buffer->idx); } @@ -70,8 +70,8 @@ struct AlternateSet if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (alternate substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (alternate substitution)", + c->buffer->idx - 1u); } return_trace (true); @@ -84,7 +84,7 @@ struct AlternateSet { if (alternates.len && alternate_count) { - + alternates.sub_array (start_offset, alternate_count) + + alternates.as_array ().sub_array (start_offset, alternate_count) | hb_sink (hb_array (alternate_glyphs, *alternate_count)) ; } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSubst.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSubst.hh index 9d7cd6fddf15..04a052a7836c 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSubst.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/AlternateSubst.hh @@ -23,8 +23,8 @@ struct AlternateSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Ligature.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Ligature.hh index cdb35f525bef..38057cb60c95 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Ligature.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Ligature.hh @@ -29,6 +29,9 @@ struct Ligature bool intersects (const hb_set_t *glyphs) const { return hb_all (component, glyphs); } + bool intersects_lig_glyph (const hb_set_t *glyphs) const + { return glyphs->has(ligGlyph); } + void closure (hb_closure_context_t *c) const { if (!intersects (c->glyphs)) return; @@ -69,7 +72,7 @@ struct Ligature { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (ligature substitution)", + "replacing glyph at %u (ligature substitution)", c->buffer->idx); } @@ -78,8 +81,8 @@ struct Ligature if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (ligature substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (ligature substitution)", + c->buffer->idx - 1u); } return_trace (true); @@ -138,7 +141,7 @@ struct Ligature { c->buffer->sync_so_far (); c->buffer->message (c->font, - "ligated glyph at %d", + "ligated glyph at %u", pos); } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSet.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSet.hh index 637cec713777..9db25cf567b4 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSet.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSet.hh @@ -34,6 +34,18 @@ struct LigatureSet ; } + bool intersects_lig_glyph (const hb_set_t *glyphs) const + { + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([glyphs] (const Ligature &_) { + return _.intersects_lig_glyph (glyphs) && _.intersects (glyphs); + }) + | hb_any + ; + } + void closure (hb_closure_context_t *c) const { + hb_iter (ligature) diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubst.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubst.hh index 7ba19e844c53..18f6e355816d 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubst.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubst.hh @@ -23,8 +23,8 @@ struct LigatureSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh index 32b642c38ad7..5c7df97d13ae 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -130,7 +130,7 @@ struct LigatureSubstFormat1_2 + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) | hb_filter (glyphset, hb_first) | hb_filter ([&] (const LigatureSet& _) { - return _.intersects (&glyphset); + return _.intersects_lig_glyph (&glyphset); }, hb_second) | hb_map (hb_first) | hb_sink (new_coverage); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/MultipleSubst.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/MultipleSubst.hh index 95710ed2be82..742c8587ee3b 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/MultipleSubst.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/MultipleSubst.hh @@ -24,8 +24,8 @@ struct MultipleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); #ifndef HB_NO_BEYOND_64K diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh index 48e208efb9c6..5ad463fea792 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh @@ -20,8 +20,8 @@ struct ReverseChainSingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index a23e92028ed9..2c2e1aa44fdc 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -135,7 +135,7 @@ struct ReverseChainSingleSubstFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replacing glyph at %d (reverse chaining substitution)", + "replacing glyph at %u (reverse chaining substitution)", c->buffer->idx); } @@ -144,7 +144,7 @@ struct ReverseChainSingleSubstFormat1 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (reverse chaining substitution)", + "replaced glyph at %u (reverse chaining substitution)", c->buffer->idx); } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Sequence.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Sequence.hh index e2190078b808..ae3292f3295b 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Sequence.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/Sequence.hh @@ -44,7 +44,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (multiple substitution)", + "replacing glyph at %u (multiple substitution)", c->buffer->idx); } @@ -53,8 +53,8 @@ struct Sequence if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (multiple subtitution)", - c->buffer->idx - 1); + "replaced glyph at %u (multiple subtitution)", + c->buffer->idx - 1u); } return_trace (true); @@ -67,7 +67,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "deleting glyph at %d (multiple substitution)", + "deleting glyph at %u (multiple substitution)", c->buffer->idx); } @@ -77,7 +77,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "deleted glyph at %d (multiple substitution)", + "deleted glyph at %u (multiple substitution)", c->buffer->idx); } @@ -88,7 +88,7 @@ struct Sequence { c->buffer->sync_so_far (); c->buffer->message (c->font, - "multiplying glyph at %d", + "multiplying glyph at %u", c->buffer->idx); } diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubst.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubst.hh index 7da8103168f7..4529927ba6d7 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubst.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubst.hh @@ -27,8 +27,8 @@ struct SingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat1.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat1.hh index 1be21b98bc41..850be86c0436 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -25,7 +25,15 @@ struct SingleSubstFormat1_3 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); + return_trace (c->check_struct (this) && + coverage.sanitize (c, this) && + /* The coverage table may use a range to represent a set + * of glyphs, which means a small number of bytes can + * generate a large glyph set. Manually modify the + * sanitizer max ops to take this into account. + * + * Note: This check *must* be right after coverage sanitize. */ + c->check_ops ((this + coverage).get_population () >> 1)); } hb_codepoint_t get_mask () const @@ -87,6 +95,34 @@ struct SingleSubstFormat1_3 bool would_apply (hb_would_apply_context_t *c) const { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + unsigned + get_glyph_alternates (hb_codepoint_t glyph_id, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) + { + if (alternate_count) + *alternate_count = 0; + return 0; + } + + if (alternate_count && *alternate_count) + { + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + glyph_id = (glyph_id + d) & mask; + + *alternate_glyphs = glyph_id; + *alternate_count = 1; + } + + return 1; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -103,7 +139,7 @@ struct SingleSubstFormat1_3 { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (single substitution)", + "replacing glyph at %u (single substitution)", c->buffer->idx); } @@ -112,8 +148,8 @@ struct SingleSubstFormat1_3 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (single substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (single substitution)", + c->buffer->idx - 1u); } return_trace (true); diff --git a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat2.hh b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat2.hh index 5416299754c6..9c651abe71d9 100644 --- a/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/third_party/harfbuzz-ng/src/src/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -36,8 +36,24 @@ struct SingleSubstFormat2_4 void closure (hb_closure_context_t *c) const { - + hb_zip (this+coverage, substitute) - | hb_filter (c->parent_active_glyphs (), hb_first) + auto &cov = this+coverage; + auto &glyph_set = c->parent_active_glyphs (); + + if (substitute.len > glyph_set.get_population () * 4) + { + for (auto g : glyph_set) + { + unsigned i = cov.get_coverage (g); + if (i == NOT_COVERED || i >= substitute.len) + continue; + c->output->add (substitute.arrayZ[i]); + } + + return; + } + + + hb_zip (cov, substitute) + | hb_filter (glyph_set, hb_first) | hb_map (hb_second) | hb_sink (c->output) ; @@ -59,6 +75,31 @@ struct SingleSubstFormat2_4 bool would_apply (hb_would_apply_context_t *c) const { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + unsigned + get_glyph_alternates (hb_codepoint_t glyph_id, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (likely (index == NOT_COVERED)) + { + if (alternate_count) + *alternate_count = 0; + return 0; + } + + if (alternate_count && *alternate_count) + { + glyph_id = substitute[index]; + + *alternate_glyphs = glyph_id; + *alternate_count = 1; + } + + return 1; + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -71,7 +112,7 @@ struct SingleSubstFormat2_4 { c->buffer->sync_so_far (); c->buffer->message (c->font, - "replacing glyph at %d (single substitution)", + "replacing glyph at %u (single substitution)", c->buffer->idx); } @@ -80,8 +121,8 @@ struct SingleSubstFormat2_4 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) { c->buffer->message (c->font, - "replaced glyph at %d (single substitution)", - c->buffer->idx - 1); + "replaced glyph at %u (single substitution)", + c->buffer->idx - 1u); } return_trace (true); diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/CompositeGlyph.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/CompositeGlyph.hh index fc8e309bc92c..94e00d3aea32 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/CompositeGlyph.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/CompositeGlyph.hh @@ -3,6 +3,7 @@ #include "../../hb-open-type.hh" +#include "composite-iter.hh" namespace OT { @@ -86,27 +87,34 @@ struct CompositeGlyphRecord } } - void transform_points (contour_point_vector_t &points) const + void transform_points (contour_point_vector_t &points, + const float (&matrix)[4], + const contour_point_t &trans) const { - float matrix[4]; - contour_point_t trans; - if (get_transformation (matrix, trans)) + if (scaled_offsets ()) { - if (scaled_offsets ()) - { - points.translate (trans); - points.transform (matrix); - } - else - { - points.transform (matrix); - points.translate (trans); - } + points.translate (trans); + points.transform (matrix); + } + else + { + points.transform (matrix); + points.translate (trans); } } - unsigned compile_with_deltas (const contour_point_t &p_delta, - char *out) const + bool get_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + get_transformation (matrix, trans); + if (unlikely (!points.resize (points.length + 1))) return false; + points[points.length - 1] = trans; + return true; + } + + unsigned compile_with_point (const contour_point_t &point, + char *out) const { const HBINT8 *p = &StructAfter (flags); #ifndef HB_NO_BEYOND_64K @@ -120,30 +128,29 @@ struct CompositeGlyphRecord unsigned len_before_val = (const char *)p - (const char *)this; if (flags & ARG_1_AND_2_ARE_WORDS) { - // no overflow, copy and update value with deltas - memcpy (out, this, len); + // no overflow, copy value + hb_memcpy (out, this, len); - const HBINT16 *px = reinterpret_cast (p); HBINT16 *o = reinterpret_cast (out + len_before_val); - o[0] = px[0] + roundf (p_delta.x); - o[1] = px[1] + roundf (p_delta.y); + o[0] = roundf (point.x); + o[1] = roundf (point.y); } else { - int new_x = p[0] + roundf (p_delta.x); - int new_y = p[1] + roundf (p_delta.y); + int new_x = roundf (point.x); + int new_y = roundf (point.y); if (new_x <= 127 && new_x >= -128 && new_y <= 127 && new_y >= -128) { - memcpy (out, this, len); + hb_memcpy (out, this, len); HBINT8 *o = reinterpret_cast (out + len_before_val); o[0] = new_x; o[1] = new_y; } else { - // int8 overflows after deltas applied - memcpy (out, this, len_before_val); + // new point value has an int8 overflow + hb_memcpy (out, this, len_before_val); //update flags CompositeGlyphRecord *o = reinterpret_cast (out); @@ -152,14 +159,14 @@ struct CompositeGlyphRecord HBINT16 new_value; new_value = new_x; - memcpy (out, &new_value, HBINT16::static_size); + hb_memcpy (out, &new_value, HBINT16::static_size); out += HBINT16::static_size; new_value = new_y; - memcpy (out, &new_value, HBINT16::static_size); + hb_memcpy (out, &new_value, HBINT16::static_size); out += HBINT16::static_size; - memcpy (out, p+2, len - len_before_val - 2); + hb_memcpy (out, p+2, len - len_before_val - 2); len += 2; } } @@ -170,6 +177,7 @@ struct CompositeGlyphRecord bool scaled_offsets () const { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } + public: bool get_transformation (float (&matrix)[4], contour_point_t &trans) const { matrix[0] = matrix[3] = 1.f; @@ -224,7 +232,6 @@ struct CompositeGlyphRecord return tx || ty; } - public: hb_codepoint_t get_gid () const { #ifndef HB_NO_BEYOND_64K @@ -245,63 +252,36 @@ struct CompositeGlyphRecord StructAfter (flags) = gid; } - protected: - HBUINT16 flags; - HBUINT24 pad; - public: - DEFINE_SIZE_MIN (4); -}; - -struct composite_iter_t : hb_iter_with_fallback_t -{ - typedef const CompositeGlyphRecord *__item_t__; - composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : - glyph (glyph_), current (nullptr), current_size (0) - { - set_current (current_); - } - - composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} - - item_t __item__ () const { return *current; } - bool __more__ () const { return current; } - void __next__ () +#ifndef HB_NO_BEYOND_64K + void lower_gid_24_to_16 () { - if (!current->has_more ()) { current = nullptr; return; } + hb_codepoint_t gid = get_gid (); + if (!(flags & GID_IS_24BIT) || gid > 0xFFFFu) + return; - set_current (&StructAtOffset (current, current_size)); - } - composite_iter_t __end__ () const { return composite_iter_t (); } - bool operator != (const composite_iter_t& o) const - { return current != o.current; } + /* Lower the flag and move the rest of the struct down. */ + unsigned size = get_size (); + char *end = (char *) this + size; + char *p = &StructAfter (flags); + p += HBGlyphID24::static_size; - void set_current (__item_t__ current_) - { - if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) - { - current = nullptr; - current_size = 0; - return; - } - unsigned size = current_->get_size (); - if (!glyph.check_range (current_, size)) - { - current = nullptr; - current_size = 0; - return; - } + flags = flags & ~GID_IS_24BIT; + set_gid (gid); - current = current_; - current_size = size; + memmove (p - HBGlyphID24::static_size + HBGlyphID16::static_size, p, end - p); } +#endif - private: - hb_bytes_t glyph; - __item_t__ current; - unsigned current_size; + protected: + HBUINT16 flags; + HBUINT24 pad; + public: + DEFINE_SIZE_MIN (4); }; +using composite_iter_t = composite_iter_tmpl; + struct CompositeGlyph { const GlyphHeader &header; @@ -351,7 +331,7 @@ struct CompositeGlyph } bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes, - const contour_point_vector_t &deltas, + const contour_point_vector_t &points_with_deltas, hb_bytes_t &dest_bytes /* OUT */) { if (source_bytes.length <= GlyphHeader::static_size || @@ -366,7 +346,7 @@ struct CompositeGlyph /* try to allocate more memories than source glyph bytes * in case that there might be an overflow for int8 value * and we would need to use int16 instead */ - char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char)); + char *o = (char *) hb_calloc (source_len * 2, sizeof (char)); if (unlikely (!o)) return false; const CompositeGlyphRecord *c = reinterpret_cast (source_bytes.arrayZ + GlyphHeader::static_size); @@ -376,18 +356,21 @@ struct CompositeGlyph unsigned i = 0, source_comp_len = 0; for (const auto &component : it) { - /* last 4 points in deltas are phantom points and should not be included */ - if (i >= deltas.length - 4) return false; + /* last 4 points in points_with_deltas are phantom points and should not be included */ + if (i >= points_with_deltas.length - 4) { + free (o); + return false; + } unsigned comp_len = component.get_size (); if (component.is_anchored ()) { - memcpy (p, &component, comp_len); + hb_memcpy (p, &component, comp_len); p += comp_len; } else { - unsigned new_len = component.compile_with_deltas (deltas[i], p); + unsigned new_len = component.compile_with_point (points_with_deltas[i], p); p += new_len; } i++; @@ -398,7 +381,7 @@ struct CompositeGlyph if (source_len > source_comp_len) { unsigned instr_len = source_len - source_comp_len; - memcpy (p, (const char *)c + source_comp_len, instr_len); + hb_memcpy (p, (const char *)c + source_comp_len, instr_len); p += instr_len; } diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/Glyph.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/Glyph.hh index f8366ce3ae9a..9e15a6e6d03b 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/Glyph.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/Glyph.hh @@ -7,6 +7,8 @@ #include "GlyphHeader.hh" #include "SimpleGlyph.hh" #include "CompositeGlyph.hh" +#include "VarCompositeGlyph.hh" +#include "coord-setter.hh" namespace OT { @@ -16,11 +18,6 @@ struct glyf_accelerator_t; namespace glyf_impl { -#ifndef HB_GLYF_MAX_POINTS -#define HB_GLYF_MAX_POINTS 10000 -#endif - - enum phantom_point_index_t { PHANTOM_LEFT = 0, @@ -32,7 +29,14 @@ enum phantom_point_index_t struct Glyph { - enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + enum glyph_type_t { + EMPTY, + SIMPLE, + COMPOSITE, +#ifndef HB_NO_VAR_COMPOSITES + VAR_COMPOSITE, +#endif + }; public: composite_iter_t get_composite_iterator () const @@ -40,12 +44,25 @@ struct Glyph if (type != COMPOSITE) return composite_iter_t (); return CompositeGlyph (*header, bytes).iter (); } + var_composite_iter_t get_var_composite_iterator () const + { +#ifndef HB_NO_VAR_COMPOSITES + if (type != VAR_COMPOSITE) return var_composite_iter_t (); + return VarCompositeGlyph (*header, bytes).iter (); +#else + return var_composite_iter_t (); +#endif + } const hb_bytes_t trim_padding () const { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding (); +#endif case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + case EMPTY: return bytes; default: return bytes; } } @@ -53,53 +70,72 @@ struct Glyph void drop_hints () { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return; // No hinting +#endif case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; - default: return; + case EMPTY: return; } } void set_overlaps_flag () { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return; // No overlaps flag +#endif case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return; case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return; - default: return; + case EMPTY: return; } } void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const { switch (type) { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: return; // No hinting +#endif case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; - default: return; + case EMPTY: return; } } void update_mtx (const hb_subset_plan_t *plan, - int xMin, int yMax, + int xMin, int xMax, + int yMin, int yMax, const contour_point_vector_t &all_points) const { hb_codepoint_t new_gid = 0; if (!plan->new_gid_for_old_gid (gid, &new_gid)) return; + if (type != EMPTY) + { + plan->bounds_width_map.set (new_gid, xMax - xMin); + plan->bounds_height_map.set (new_gid, yMax - yMin); + } + unsigned len = all_points.length; float leftSideX = all_points[len - 4].x; float rightSideX = all_points[len - 3].x; float topSideY = all_points[len - 2].y; float bottomSideY = all_points[len - 1].y; - int hori_aw = roundf (rightSideX - leftSideX); + signed hori_aw = roundf (rightSideX - leftSideX); if (hori_aw < 0) hori_aw = 0; int lsb = roundf (xMin - leftSideX); - plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb)); + plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); + //flag value should be computed using non-empty glyphs + if (type != EMPTY && lsb != xMin) + plan->head_maxp_info.allXMinIsLsb = false; - int vert_aw = roundf (topSideY - bottomSideY); + signed vert_aw = roundf (topSideY - bottomSideY); if (vert_aw < 0) vert_aw = 0; int tsb = roundf (topSideY - yMax); - plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb)); + plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); } bool compile_header_bytes (const hb_subset_plan_t *plan, @@ -107,42 +143,57 @@ struct Glyph hb_bytes_t &dest_bytes /* OUT */) const { GlyphHeader *glyph_header = nullptr; - if (type != EMPTY && all_points.length > 4) + if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4) { glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); if (unlikely (!glyph_header)) return false; } - int xMin = 0, xMax = 0; - int yMin = 0, yMax = 0; + float xMin = 0, xMax = 0; + float yMin = 0, yMax = 0; if (all_points.length > 4) { - xMin = xMax = roundf (all_points[0].x); - yMin = yMax = roundf (all_points[0].y); + xMin = xMax = all_points[0].x; + yMin = yMax = all_points[0].y; } for (unsigned i = 1; i < all_points.length - 4; i++) { - float rounded_x = roundf (all_points[i].x); - float rounded_y = roundf (all_points[i].y); - xMin = hb_min (xMin, rounded_x); - xMax = hb_max (xMax, rounded_x); - yMin = hb_min (yMin, rounded_y); - yMax = hb_max (yMax, rounded_y); + float x = all_points[i].x; + float y = all_points[i].y; + xMin = hb_min (xMin, x); + xMax = hb_max (xMax, x); + yMin = hb_min (yMin, y); + yMax = hb_max (yMax, y); } - update_mtx (plan, xMin, yMax, all_points); + update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points); + + int rounded_xMin = roundf (xMin); + int rounded_xMax = roundf (xMax); + int rounded_yMin = roundf (yMin); + int rounded_yMax = roundf (yMax); + + if (type != EMPTY) + { + plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin); + plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin); + plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax); + plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax); + } - /*for empty glyphs: all_points only include phantom points. - *just update metrics and then return */ + /* when pinned at default, no need to compile glyph header + * and for empty glyphs: all_points only include phantom points. + * just update metrics and then return */ if (!glyph_header) return true; glyph_header->numberOfContours = header->numberOfContours; - glyph_header->xMin = xMin; - glyph_header->yMin = yMin; - glyph_header->xMax = xMax; - glyph_header->yMax = yMax; + + glyph_header->xMin = rounded_xMin; + glyph_header->yMin = rounded_yMin; + glyph_header->xMax = rounded_xMax; + glyph_header->yMax = rounded_yMax; dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); return true; @@ -154,35 +205,64 @@ struct Glyph hb_bytes_t &dest_start, /* IN/OUT */ hb_bytes_t &dest_end /* OUT */) { - contour_point_vector_t all_points, deltas; - if (!get_points (font, glyf, all_points, &deltas, false, false)) + contour_point_vector_t all_points, points_with_deltas; + unsigned composite_contours = 0; + head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; + unsigned *composite_contours_p = &composite_contours; + + // don't compute head/maxp values when glyph has no contours(type is EMPTY) + // also ignore .notdef glyph when --notdef-outline is not enabled + if (type == EMPTY || + (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))) + { + head_maxp_info_p = nullptr; + composite_contours_p = nullptr; + } + + if (!get_points (font, glyf, all_points, &points_with_deltas, head_maxp_info_p, composite_contours_p, false, false)) return false; // .notdef, set type to empty so we only update metrics and don't compile bytes for // it if (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + { type = EMPTY; - - switch (type) { - case COMPOSITE: - if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, - deltas, - dest_end)) - return false; - break; - case SIMPLE: - if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, - plan->flags & HB_SUBSET_FLAGS_NO_HINTING, - dest_end)) - return false; - break; - default: - /* set empty bytes for empty glyph - * do not use source glyph's pointers */ dest_start = hb_bytes_t (); dest_end = hb_bytes_t (); - break; + } + + //dont compile bytes when pinned at default, just recalculate bounds + if (!plan->pinned_at_default) + { + switch (type) + { +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + // TODO + dest_end = hb_bytes_t (); + break; +#endif + + case COMPOSITE: + if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, + points_with_deltas, + dest_end)) + return false; + break; + case SIMPLE: + if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, + plan->flags & HB_SUBSET_FLAGS_NO_HINTING, + dest_end)) + return false; + break; + case EMPTY: + /* set empty bytes for empty glyph + * do not use source glyph's pointers */ + dest_start = hb_bytes_t (); + dest_end = hb_bytes_t (); + break; + } } if (!compile_header_bytes (plan, all_points, dest_start)) @@ -200,40 +280,69 @@ struct Glyph template bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, contour_point_vector_t &all_points /* OUT */, - contour_point_vector_t *deltas = nullptr, /* OUT */ + contour_point_vector_t *points_with_deltas = nullptr, /* OUT */ + head_maxp_info_t * head_maxp_info = nullptr, /* OUT */ + unsigned *composite_contours = nullptr, /* OUT */ bool shift_points_hori = true, bool use_my_metrics = true, bool phantom_only = false, - unsigned int depth = 0) const + hb_array_t coords = hb_array_t (), + unsigned int depth = 0, + unsigned *edge_count = nullptr) const { if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; + unsigned stack_edge_count = 0; + if (!edge_count) edge_count = &stack_edge_count; + if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false; + (*edge_count)++; + + if (head_maxp_info) + { + head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); + } + + if (!coords) + coords = hb_array (font->coords, font->num_coords); + contour_point_vector_t stack_points; bool inplace = type == SIMPLE && all_points.length == 0; /* Load into all_points if it's empty, as an optimization. */ contour_point_vector_t &points = inplace ? all_points : stack_points; switch (type) { + case SIMPLE: + if (depth == 0 && head_maxp_info) + head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); + if (depth > 0 && composite_contours) + *composite_contours += (unsigned) header->numberOfContours; + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) + return false; + break; case COMPOSITE: { - /* pseudo component points for each component in composite glyph */ - unsigned num_points = hb_len (CompositeGlyph (*header, bytes).iter ()); - if (unlikely (!points.resize (num_points))) return false; + for (auto &item : get_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; break; } - case SIMPLE: - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) - return false; +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + { + for (auto &item : get_var_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + } +#endif + case EMPTY: break; } /* Init phantom points */ if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; - hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { int lsb = 0; int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? (int) header->xMin - lsb : 0; - int tsb = 0; + HB_UNUSED int tsb = 0; int v_orig = (int) header->yMax + #ifndef HB_NO_VERTICAL ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) @@ -250,34 +359,29 @@ struct Glyph #endif ; phantoms[PHANTOM_LEFT].x = h_delta; - phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_RIGHT].x = (int) h_adv + h_delta; phantoms[PHANTOM_TOP].y = v_orig; phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } - if (deltas != nullptr && depth == 0 && type == COMPOSITE) - { - if (unlikely (!deltas->resize (points.length))) return false; - deltas->copy_vector (points); - } - #ifndef HB_NO_VAR - glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); + glyf_accelerator.gvar->apply_deltas_to_points (gid, + coords, + points.as_array ()); #endif // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it // with child glyphs' points - if (deltas != nullptr && depth == 0 && type == COMPOSITE) + if (points_with_deltas != nullptr && depth == 0 && type == COMPOSITE) { - for (unsigned i = 0 ; i < points.length; i++) - { - deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x; - deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y; - } + if (unlikely (!points_with_deltas->resize (points.length))) return false; + points_with_deltas->copy_vector (points); } switch (type) { case SIMPLE: + if (depth == 0 && head_maxp_info) + head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4); if (!inplace) all_points.extend (points.as_array ()); break; @@ -289,15 +393,31 @@ struct Glyph { comp_points.reset (); if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) - .get_points (font, glyf_accelerator, comp_points, - deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1))) + .get_points (font, + glyf_accelerator, + comp_points, + points_with_deltas, + head_maxp_info, + composite_contours, + shift_points_hori, + use_my_metrics, + phantom_only, + coords, + depth + 1, + edge_count))) return false; - /* Apply component transformation & translation */ - item.transform_points (comp_points); + /* Copy phantom points from component if USE_MY_METRICS flag set */ + if (use_my_metrics && item.is_use_my_metrics ()) + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; - /* Apply translation from gvar */ - comp_points.translate (points[comp_index]); + float matrix[4]; + contour_point_t default_trans; + item.get_transformation (matrix, default_trans); + + /* Apply component transformation & translation (with deltas applied) */ + item.transform_points (comp_points, matrix, points[comp_index]); if (item.is_anchored ()) { @@ -313,23 +433,78 @@ struct Glyph } } + all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); + + if (all_points.length > HB_GLYF_MAX_POINTS) + return false; + + comp_index++; + } + + if (head_maxp_info && depth == 0) + { + if (composite_contours) + head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours); + head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length); + head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index); + } + all_points.extend (phantoms); + } break; +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + { + contour_point_vector_t comp_points; + hb_array_t points_left = points.as_array (); + for (auto &item : get_var_composite_iterator ()) + { + unsigned item_num_points = item.get_num_points (); + hb_array_t record_points = points_left.sub_array (0, item_num_points); + + comp_points.reset (); + + auto component_coords = coords; + if (item.is_reset_unspecified_axes ()) + component_coords = hb_array (); + + coord_setter_t coord_setter (component_coords); + item.set_variations (coord_setter, record_points); + + if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) + .get_points (font, + glyf_accelerator, + comp_points, + points_with_deltas, + head_maxp_info, + nullptr, + shift_points_hori, + use_my_metrics, + phantom_only, + coord_setter.get_coords (), + depth + 1, + edge_count))) + return false; + + /* Apply component transformation */ + item.transform_points (record_points, comp_points); + /* Copy phantom points from component if USE_MY_METRICS flag set */ if (use_my_metrics && item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); + if (all_points.length > HB_GLYF_MAX_POINTS) return false; - all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); - - comp_index++; + points_left += item_num_points; } - all_points.extend (phantoms); } break; - default: +#endif + case EMPTY: all_points.extend (phantoms); + break; } if (depth == 0 && shift_points_hori) /* Apply at top level */ @@ -353,6 +528,8 @@ struct Glyph } hb_bytes_t get_bytes () const { return bytes; } + glyph_type_t get_type () const { return type; } + const GlyphHeader *get_header () const { return header; } Glyph () : bytes (), header (bytes.as ()), @@ -368,6 +545,9 @@ struct Glyph int num_contours = header->numberOfContours; if (unlikely (num_contours == 0)) type = EMPTY; else if (num_contours > 0) type = SIMPLE; +#ifndef HB_NO_VAR_COMPOSITES + else if (num_contours == -2) type = VAR_COMPOSITE; +#endif else type = COMPOSITE; /* negative numbers */ } @@ -375,7 +555,7 @@ struct Glyph hb_bytes_t bytes; const GlyphHeader *header; hb_codepoint_t gid; - unsigned type; + glyph_type_t type; }; diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/GlyphHeader.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/GlyphHeader.hh index e4a9168b79f0..a43b6691ab49 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/GlyphHeader.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/GlyphHeader.hh @@ -21,10 +21,12 @@ struct GlyphHeader /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ int lsb = hb_min (xMin, xMax); (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); - extents->x_bearing = font->em_scale_x (lsb); - extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); - extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); - extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); + extents->x_bearing = lsb; + extents->y_bearing = hb_max (yMin, yMax); + extents->width = hb_max (xMin, xMax) - hb_min (xMin, xMax); + extents->height = hb_min (yMin, yMax) - hb_max (yMin, yMax); + + font->scale_glyph_extents (extents); return true; } diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/SimpleGlyph.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/SimpleGlyph.hh index d45f4eb35056..b6679b2dae86 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/SimpleGlyph.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/SimpleGlyph.hh @@ -20,7 +20,7 @@ struct SimpleGlyph FLAG_X_SAME = 0x10, FLAG_Y_SAME = 0x20, FLAG_OVERLAP_SIMPLE = 0x40, - FLAG_RESERVED2 = 0x80 + FLAG_CUBIC = 0x80 }; const GlyphHeader &header; @@ -34,6 +34,11 @@ struct SimpleGlyph unsigned int length (unsigned int instruction_len) const { return instruction_len_offset () + 2 + instruction_len; } + bool has_instructions_length () const + { + return instruction_len_offset () + 2 <= bytes.length; + } + unsigned int instructions_length () const { unsigned int instruction_length_offset = instruction_len_offset (); @@ -94,6 +99,7 @@ struct SimpleGlyph /* zero instruction length */ void drop_hints () { + if (!has_instructions_length ()) return; GlyphHeader &glyph_header = const_cast (header); (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; } @@ -132,8 +138,8 @@ struct SimpleGlyph if (unlikely (p + 1 > end)) return false; unsigned int repeat_count = *p++; unsigned stop = hb_min (i + repeat_count, count); - for (; i < stop;) - points_.arrayZ[i++].flag = flag; + for (; i < stop; i++) + points_.arrayZ[i].flag = flag; } } return true; @@ -184,7 +190,7 @@ struct SimpleGlyph if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; - points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy + points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy if (!points_.resize (num_points)) return false; if (phantom_only) return true; @@ -223,33 +229,34 @@ struct SimpleGlyph if (value > 0) flag |= same_flag; else value = -value; - coords.push ((uint8_t)value); + coords.arrayZ[coords.length++] = (uint8_t) value; } else { int16_t val = value; - coords.push (val >> 8); - coords.push (val & 0xff); + coords.arrayZ[coords.length++] = val >> 8; + coords.arrayZ[coords.length++] = val & 0xff; } } static void encode_flag (uint8_t &flag, uint8_t &repeat, - uint8_t &lastflag, + uint8_t lastflag, hb_vector_t &flags /* OUT */) { if (flag == lastflag && repeat != 255) { - repeat = repeat + 1; + repeat++; if (repeat == 1) { - flags.push(flag); + /* We know there's room. */ + flags.arrayZ[flags.length++] = flag; } else { unsigned len = flags.length; - flags[len-2] = flag | FLAG_REPEAT; - flags[len-1] = repeat; + flags.arrayZ[len-2] = flag | FLAG_REPEAT; + flags.arrayZ[len-1] = repeat; } } else @@ -257,7 +264,6 @@ struct SimpleGlyph repeat = 0; flags.push (flag); } - lastflag = flag; } bool compile_bytes_with_deltas (const contour_point_vector_t &all_points, @@ -269,31 +275,30 @@ struct SimpleGlyph dest_bytes = hb_bytes_t (); return true; } - //convert absolute values to relative values unsigned num_points = all_points.length - 4; hb_vector_t flags, x_coords, y_coords; - if (unlikely (!flags.alloc (num_points))) return false; - if (unlikely (!x_coords.alloc (2*num_points))) return false; - if (unlikely (!y_coords.alloc (2*num_points))) return false; + if (unlikely (!flags.alloc (num_points, true))) return false; + if (unlikely (!x_coords.alloc (2*num_points, true))) return false; + if (unlikely (!y_coords.alloc (2*num_points, true))) return false; + + uint8_t lastflag = 255, repeat = 0; + int prev_x = 0, prev_y = 0; - uint8_t lastflag = 0, repeat = 0; - int prev_x = 0.f, prev_y = 0.f; - for (unsigned i = 0; i < num_points; i++) { - uint8_t flag = all_points[i].flag; + uint8_t flag = all_points.arrayZ[i].flag; flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE; - float cur_x = roundf (all_points[i].x); - float cur_y = roundf (all_points[i].y); + int cur_x = roundf (all_points.arrayZ[i].x); + int cur_y = roundf (all_points.arrayZ[i].y); encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); - if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point encode_flag (flag, repeat, lastflag, flags); prev_x = cur_x; prev_y = cur_y; + lastflag = flag; } unsigned len_before_instrs = 2 * header.numberOfContours + 2; @@ -303,29 +308,29 @@ struct SimpleGlyph if (!no_hinting) total_len += len_instrs; - char *p = (char *) hb_calloc (total_len, sizeof (char)); + char *p = (char *) hb_malloc (total_len); if (unlikely (!p)) return false; const char *src = bytes.arrayZ + GlyphHeader::static_size; char *cur = p; - memcpy (p, src, len_before_instrs); + hb_memcpy (p, src, len_before_instrs); cur += len_before_instrs; src += len_before_instrs; if (!no_hinting) { - memcpy (cur, src, len_instrs); + hb_memcpy (cur, src, len_instrs); cur += len_instrs; } - memcpy (cur, flags.arrayZ, flags.length); + hb_memcpy (cur, flags.arrayZ, flags.length); cur += flags.length; - memcpy (cur, x_coords.arrayZ, x_coords.length); + hb_memcpy (cur, x_coords.arrayZ, x_coords.length); cur += x_coords.length; - memcpy (cur, y_coords.arrayZ, y_coords.length); + hb_memcpy (cur, y_coords.arrayZ, y_coords.length); dest_bytes = hb_bytes_t (p, total_len); return true; diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/SubsetGlyph.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/SubsetGlyph.hh index 88fc93c43589..26dc374eab64 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/SubsetGlyph.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/SubsetGlyph.hh @@ -18,17 +18,23 @@ struct SubsetGlyph Glyph source_glyph; hb_bytes_t dest_start; /* region of source_glyph to copy first */ hb_bytes_t dest_end; /* region of source_glyph to copy second */ + bool allocated; bool serialize (hb_serialize_context_t *c, bool use_short_loca, - const hb_subset_plan_t *plan) const + const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); hb_bytes_t dest_glyph = dest_start.copy (c); - dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); + hb_bytes_t end_copy = dest_end.copy (c); + if (!end_copy.arrayZ || !dest_glyph.arrayZ) { + return false; + } + + dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + end_copy.length); unsigned int pad_length = use_short_loca ? padding () : 0; - DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length); HBUINT8 pad; pad = 0; @@ -40,13 +46,68 @@ struct SubsetGlyph if (unlikely (!dest_glyph.length)) return_trace (true); - /* update components gids */ + /* update components gids. */ for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) { hb_codepoint_t new_gid; if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) const_cast (_).set_gid (new_gid); } +#ifndef HB_NO_VAR_COMPOSITES + for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ()) + { + hb_codepoint_t new_gid; + if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) + const_cast (_).set_gid (new_gid); + } +#endif + +#ifndef HB_NO_BEYOND_64K + auto it = Glyph (dest_glyph).get_composite_iterator (); + if (it) + { + /* lower GID24 to GID16 in components if possible. + * + * TODO: VarComposite. Not as critical, since VarComposite supports + * gid24 from the first version. */ + char *p = it ? (char *) &*it : nullptr; + char *q = p; + const char *end = dest_glyph.arrayZ + dest_glyph.length; + while (it) + { + auto &rec = const_cast (*it); + ++it; + + q += rec.get_size (); + + rec.lower_gid_24_to_16 (); + + unsigned size = rec.get_size (); + + memmove (p, &rec, size); + + p += size; + } + memmove (p, q, end - q); + p += end - q; + + /* We want to shorten the glyph, but we can't do that without + * updating the length in the loca table, which is already + * written out :-(. So we just fill the rest of the glyph with + * harmless instructions, since that's what they will be + * interpreted as. + * + * Should move the lowering to _populate_subset_glyphs() to + * fix this issue. */ + + hb_memset (p, 0x7A /* TrueType instruction ROFF; harmless */, end - p); + p += end - p; + dest_glyph = hb_bytes_t (dest_glyph.arrayZ, p - (char *) dest_glyph.arrayZ); + + // TODO: Padding; & trim serialized bytes. + // TODO: Update length in loca. Ugh. + } +#endif if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) Glyph (dest_glyph).drop_hints (); @@ -60,12 +121,18 @@ struct SubsetGlyph bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, hb_font_t *font, const glyf_accelerator_t &glyf) - { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); } + { + allocated = source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); + return allocated; + } void free_compiled_bytes () { - dest_start.fini (); - dest_end.fini (); + if (likely (allocated)) { + allocated = false; + dest_start.fini (); + dest_end.fini (); + } } void drop_hints_bytes () diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/VarCompositeGlyph.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/VarCompositeGlyph.hh new file mode 100644 index 000000000000..309ec473aa29 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/VarCompositeGlyph.hh @@ -0,0 +1,371 @@ +#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH +#define OT_GLYF_VARCOMPOSITEGLYPH_HH + + +#include "../../hb-open-type.hh" +#include "coord-setter.hh" + + +namespace OT { +namespace glyf_impl { + + +struct VarCompositeGlyphRecord +{ + protected: + enum var_composite_glyph_flag_t + { + USE_MY_METRICS = 0x0001, + AXIS_INDICES_ARE_SHORT = 0x0002, + UNIFORM_SCALE = 0x0004, + HAVE_TRANSLATE_X = 0x0008, + HAVE_TRANSLATE_Y = 0x0010, + HAVE_ROTATION = 0x0020, + HAVE_SCALE_X = 0x0040, + HAVE_SCALE_Y = 0x0080, + HAVE_SKEW_X = 0x0100, + HAVE_SKEW_Y = 0x0200, + HAVE_TCENTER_X = 0x0400, + HAVE_TCENTER_Y = 0x0800, + GID_IS_24BIT = 0x1000, + AXES_HAVE_VARIATION = 0x2000, + RESET_UNSPECIFIED_AXES = 0x4000, + }; + + public: + + unsigned int get_size () const + { + unsigned int size = min_size; + + unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3; + size += numAxes * axis_width; + + // gid + size += 2; + if (flags & GID_IS_24BIT) size += 1; + + if (flags & HAVE_TRANSLATE_X) size += 2; + if (flags & HAVE_TRANSLATE_Y) size += 2; + if (flags & HAVE_ROTATION) size += 2; + if (flags & HAVE_SCALE_X) size += 2; + if (flags & HAVE_SCALE_Y) size += 2; + if (flags & HAVE_SKEW_X) size += 2; + if (flags & HAVE_SKEW_Y) size += 2; + if (flags & HAVE_TCENTER_X) size += 2; + if (flags & HAVE_TCENTER_Y) size += 2; + + return size; + } + + bool has_more () const { return true; } + + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; } + + hb_codepoint_t get_gid () const + { + if (flags & GID_IS_24BIT) + return StructAfter (numAxes); + else + return StructAfter (numAxes); + } + + void set_gid (hb_codepoint_t gid) + { + if (flags & GID_IS_24BIT) + StructAfter (numAxes) = gid; + else + StructAfter (numAxes) = gid; + } + + unsigned get_numAxes () const + { + return numAxes; + } + + unsigned get_num_points () const + { + unsigned num = 0; + if (flags & AXES_HAVE_VARIATION) num += numAxes; + if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++; + if (flags & HAVE_ROTATION) num++; + if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++; + if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++; + if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++; + return num; + } + + void transform_points (hb_array_t record_points, + contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + + get_transformation_from_points (record_points, matrix, trans); + + points.transform (matrix); + points.translate (trans); + } + + static inline void transform (float (&matrix)[4], contour_point_t &trans, + float (other)[6]) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268 + float xx1 = other[0]; + float xy1 = other[1]; + float yx1 = other[2]; + float yy1 = other[3]; + float dx1 = other[4]; + float dy1 = other[5]; + float xx2 = matrix[0]; + float xy2 = matrix[1]; + float yx2 = matrix[2]; + float yy2 = matrix[3]; + float dx2 = trans.x; + float dy2 = trans.y; + + matrix[0] = xx1*xx2 + xy1*yx2; + matrix[1] = xx1*xy2 + xy1*yy2; + matrix[2] = yx1*xx2 + yy1*yx2; + matrix[3] = yx1*xy2 + yy1*yy2; + trans.x = xx2*dx1 + yx2*dy1 + dx2; + trans.y = xy2*dx1 + yy2*dy1 + dy2; + } + + static void translate (float (&matrix)[4], contour_point_t &trans, + float translateX, float translateY) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213 + float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY}; + transform (matrix, trans, other); + } + + static void scale (float (&matrix)[4], contour_point_t &trans, + float scaleX, float scaleY) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224 + float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f}; + transform (matrix, trans, other); + } + + static void rotate (float (&matrix)[4], contour_point_t &trans, + float rotation) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 + rotation = rotation * HB_PI; + float c = cosf (rotation); + float s = sinf (rotation); + float other[6] = {c, s, -s, c, 0.f, 0.f}; + transform (matrix, trans, other); + } + + static void skew (float (&matrix)[4], contour_point_t &trans, + float skewX, float skewY) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 + skewX = skewX * HB_PI; + skewY = skewY * HB_PI; + float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f}; + transform (matrix, trans, other); + } + + bool get_points (contour_point_vector_t &points) const + { + float translateX = 0.f; + float translateY = 0.f; + float rotation = 0.f; + float scaleX = 1.f * (1 << 10); + float scaleY = 1.f * (1 << 10); + float skewX = 0.f; + float skewY = 0.f; + float tCenterX = 0.f; + float tCenterY = 0.f; + + unsigned num_points = get_num_points (); + + if (unlikely (!points.resize (points.length + num_points))) return false; + + unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + unsigned axes_size = numAxes * axis_width; + + const F2DOT14 *q = (const F2DOT14 *) (axes_size + + (flags & GID_IS_24BIT ? 3 : 2) + + &StructAfter (numAxes)); + + hb_array_t rec_points = points.as_array ().sub_array (points.length - num_points); + + unsigned count = numAxes; + if (flags & AXES_HAVE_VARIATION) + { + for (unsigned i = 0; i < count; i++) + rec_points[i].x = q++->to_int (); + rec_points += count; + } + else + q += count; + + const HBUINT16 *p = (const HBUINT16 *) q; + + if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++; + if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++; + if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int (); + if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int (); + if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int (); + if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int (); + if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int (); + if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++; + if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++; + + if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y)) + scaleY = scaleX; + + if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) + { + rec_points[0].x = translateX; + rec_points[0].y = translateY; + rec_points++; + } + if (flags & HAVE_ROTATION) + { + rec_points[0].x = rotation; + rec_points++; + } + if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) + { + rec_points[0].x = scaleX; + rec_points[0].y = scaleY; + rec_points++; + } + if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) + { + rec_points[0].x = skewX; + rec_points[0].y = skewY; + rec_points++; + } + if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) + { + rec_points[0].x = tCenterX; + rec_points[0].y = tCenterY; + rec_points++; + } + assert (!rec_points); + + return true; + } + + void get_transformation_from_points (hb_array_t rec_points, + float (&matrix)[4], contour_point_t &trans) const + { + if (flags & AXES_HAVE_VARIATION) + rec_points += numAxes; + + matrix[0] = matrix[3] = 1.f; + matrix[1] = matrix[2] = 0.f; + trans.init (0.f, 0.f); + + float translateX = 0.f; + float translateY = 0.f; + float rotation = 0.f; + float scaleX = 1.f; + float scaleY = 1.f; + float skewX = 0.f; + float skewY = 0.f; + float tCenterX = 0.f; + float tCenterY = 0.f; + + if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) + { + translateX = rec_points[0].x; + translateY = rec_points[0].y; + rec_points++; + } + if (flags & HAVE_ROTATION) + { + rotation = rec_points[0].x / (1 << 12); + rec_points++; + } + if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) + { + scaleX = rec_points[0].x / (1 << 10); + scaleY = rec_points[0].y / (1 << 10); + rec_points++; + } + if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) + { + skewX = rec_points[0].x / (1 << 12); + skewY = rec_points[0].y / (1 << 12); + rec_points++; + } + if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) + { + tCenterX = rec_points[0].x; + tCenterY = rec_points[0].y; + rec_points++; + } + assert (!rec_points); + + translate (matrix, trans, translateX + tCenterX, translateY + tCenterY); + rotate (matrix, trans, rotation); + scale (matrix, trans, scaleX, scaleY); + skew (matrix, trans, -skewX, skewY); + translate (matrix, trans, -tCenterX, -tCenterY); + } + + void set_variations (coord_setter_t &setter, + hb_array_t rec_points) const + { + bool have_variations = flags & AXES_HAVE_VARIATION; + unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + + const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2)); + const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2)); + + const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes))); + + unsigned count = numAxes; + for (unsigned i = 0; i < count; i++) + { + unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++; + + signed v = have_variations ? rec_points[i].x : a++->to_int (); + + v = hb_clamp (v, -(1<<14), (1<<14)); + setter[axis_index] = v; + } + } + + protected: + HBUINT16 flags; + HBUINT8 numAxes; + public: + DEFINE_SIZE_MIN (3); +}; + +using var_composite_iter_t = composite_iter_tmpl; + +struct VarCompositeGlyph +{ + const GlyphHeader &header; + hb_bytes_t bytes; + VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + var_composite_iter_t iter () const + { return var_composite_iter_t (bytes, &StructAfter (header)); } + + const hb_bytes_t trim_padding () const + { + unsigned length = GlyphHeader::static_size; + for (auto &comp : iter ()) + length += comp.get_size (); + return bytes.sub_array (0, length); + } +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */ diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/composite-iter.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/composite-iter.hh new file mode 100644 index 000000000000..d05701f3d1ef --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/composite-iter.hh @@ -0,0 +1,68 @@ +#ifndef OT_GLYF_COMPOSITE_ITER_HH +#define OT_GLYF_COMPOSITE_ITER_HH + + +#include "../../hb.hh" + + +namespace OT { +namespace glyf_impl { + + +template +struct composite_iter_tmpl : hb_iter_with_fallback_t, + const CompositeGlyphRecord &> +{ + typedef const CompositeGlyphRecord *__item_t__; + composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (nullptr), current_size (0) + { + set_current (current_); + } + + composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} + + const CompositeGlyphRecord & __item__ () const { return *current; } + bool __more__ () const { return current; } + void __next__ () + { + if (!current->has_more ()) { current = nullptr; return; } + + set_current (&StructAtOffset (current, current_size)); + } + composite_iter_tmpl __end__ () const { return composite_iter_tmpl (); } + bool operator != (const composite_iter_tmpl& o) const + { return current != o.current; } + + + void set_current (__item_t__ current_) + { + if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) + { + current = nullptr; + current_size = 0; + return; + } + unsigned size = current_->get_size (); + if (!glyph.check_range (current_, size)) + { + current = nullptr; + current_size = 0; + return; + } + + current = current_; + current_size = size; + } + + private: + hb_bytes_t glyph; + __item_t__ current; + unsigned current_size; +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + +#endif /* OT_GLYF_COMPOSITE_ITER_HH */ diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/coord-setter.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/coord-setter.hh new file mode 100644 index 000000000000..df64ed5af7d2 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/coord-setter.hh @@ -0,0 +1,34 @@ +#ifndef OT_GLYF_COORD_SETTER_HH +#define OT_GLYF_COORD_SETTER_HH + + +#include "../../hb.hh" + + +namespace OT { +namespace glyf_impl { + + +struct coord_setter_t +{ + coord_setter_t (hb_array_t coords) : + coords (coords) {} + + int& operator [] (unsigned idx) + { + if (coords.length < idx + 1) + coords.resize (idx + 1); + return coords[idx]; + } + + hb_array_t get_coords () + { return coords.as_array (); } + + hb_vector_t coords; +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + +#endif /* OT_GLYF_COORD_SETTER_HH */ diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/glyf-helpers.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/glyf-helpers.hh index 181c33d06d62..30106b2b98ba 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/glyf-helpers.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/glyf-helpers.hh @@ -25,7 +25,7 @@ _write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest) | hb_map ([=, &offset] (unsigned int padded_size) { offset += padded_size; - DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); + DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset); return offset >> right_shift; }) | hb_sink (dest) @@ -44,6 +44,20 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); head_prime->indexToLocFormat = use_short_loca ? 0 : 1; + if (plan->normalized_coords) + { + head_prime->xMin = plan->head_maxp_info.xMin; + head_prime->xMax = plan->head_maxp_info.xMax; + head_prime->yMin = plan->head_maxp_info.yMin; + head_prime->yMax = plan->head_maxp_info.yMax; + + unsigned orig_flag = head_prime->flags; + if (plan->head_maxp_info.allXMinIsLsb) + orig_flag |= 1 << 1; + else + orig_flag &= ~(1 << 1); + head_prime->flags = orig_flag; + } bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); hb_blob_destroy (head_prime_blob); @@ -61,7 +75,7 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s if (unlikely (!loca_prime_data)) return false; - DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u", entry_size, num_offsets, entry_size * num_offsets); if (use_short_loca) diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/glyf.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/glyf.hh index 5fb32f67f35b..dd08dda6ee19 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/glyf.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/glyf.hh @@ -7,6 +7,7 @@ #include "../../hb-ot-hmtx-table.hh" #include "../../hb-ot-var-gvar-table.hh" #include "../../hb-draw.hh" +#include "../../hb-paint.hh" #include "glyf-helpers.hh" #include "Glyph.hh" @@ -30,6 +31,12 @@ struct glyf static constexpr hb_tag_t tableTag = HB_OT_TAG_glyf; + static bool has_valid_glyf_format(const hb_face_t* face) + { + const OT::head &head = *face->table.head; + return head.indexToLocFormat <= 1 && head.glyphDataFormat <= 1; + } + bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); @@ -45,8 +52,11 @@ struct glyf const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); + unsigned init_len = c->length (); - for (const auto &_ : it) _.serialize (c, use_short_loca, plan); + for (auto &_ : it) + if (unlikely (!_.serialize (c, use_short_loca, plan))) + return false; /* As a special case when all glyph in the font are empty, add a zero byte * to the table, so that OTS doesn’t reject it, and to make the table work @@ -68,56 +78,82 @@ struct glyf { TRACE_SUBSET (this); + if (!has_valid_glyf_format (c->plan->source)) { + // glyf format is unknown don't attempt to subset it. + DEBUG_MSG (SUBSET, nullptr, + "unkown glyf format, dropping from subset."); + return_trace (false); + } + glyf *glyf_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); - hb_vector_t glyphs; - _populate_subset_glyphs (c->plan, glyphs); + hb_font_t *font = nullptr; + if (c->plan->normalized_coords) + { + font = _create_font_for_instancing (c->plan); + if (unlikely (!font)) return false; + } - if (!c->plan->pinned_at_default) + hb_vector_t padded_offsets; + unsigned num_glyphs = c->plan->num_output_glyphs (); + if (unlikely (!padded_offsets.resize (num_glyphs))) { - if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs)) - return_trace (false); + hb_font_destroy (font); + return false; } - auto padded_offsets = - + hb_iter (glyphs) - | hb_map (&glyf_impl::SubsetGlyph::padded_size) - ; + hb_vector_t glyphs; + if (!_populate_subset_glyphs (c->plan, font, glyphs)) + { + hb_font_destroy (font); + return false; + } - unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); - bool use_short_loca = max_offset < 0x1FFFF; + if (font) + hb_font_destroy (font); + + unsigned max_offset = 0; + for (unsigned i = 0; i < num_glyphs; i++) + { + padded_offsets[i] = glyphs[i].padded_size (); + max_offset += padded_offsets[i]; + } + bool use_short_loca = false; + if (likely (!c->plan->force_long_loca)) + use_short_loca = max_offset < 0x1FFFF; - glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); if (!use_short_loca) { - padded_offsets = - + hb_iter (glyphs) - | hb_map (&glyf_impl::SubsetGlyph::length) - ; + for (unsigned i = 0; i < num_glyphs; i++) + padded_offsets[i] = glyphs[i].length (); } + bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan); + if (c->plan->normalized_coords && !c->plan->pinned_at_default) + _free_compiled_subset_glyphs (glyphs); + + if (!result) return false; - if (!c->plan->pinned_at_default) - _free_compiled_subset_glyphs (&glyphs); if (unlikely (c->serializer->in_error ())) return_trace (false); + return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, - padded_offsets, + padded_offsets.iter (), use_short_loca))); } - void + bool _populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_font_t *font, hb_vector_t &glyphs /* OUT */) const; - bool - _compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, - hb_vector_t *glyphs /* OUT */) const; + hb_font_t * + _create_font_for_instancing (const hb_subset_plan_t *plan) const; - void _free_compiled_subset_glyphs (hb_vector_t *glyphs) const + void _free_compiled_subset_glyphs (hb_vector_t &glyphs) const { - for (auto _ : *glyphs) - _.free_compiled_bytes (); + for (unsigned i = 0; i < glyphs.length; i++) + glyphs[i].free_compiled_bytes (); } protected: @@ -145,7 +181,7 @@ struct glyf_accelerator_t vmtx = nullptr; #endif const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) + if (!glyf::has_valid_glyf_format (face)) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; @@ -183,7 +219,7 @@ struct glyf_accelerator_t contour_point_vector_t all_points; bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only))) + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only))) return false; if (consumer.is_consuming_contour_points ()) @@ -205,6 +241,8 @@ struct glyf_accelerator_t return true; } + public: + #ifndef HB_NO_VAR struct points_aggregator_t { @@ -237,19 +275,14 @@ struct glyf_accelerator_t extents->y_bearing = 0; return; } - if (scaled) - { - extents->x_bearing = font->em_scalef_x (min_x); - extents->width = font->em_scalef_x (max_x) - extents->x_bearing; - extents->y_bearing = font->em_scalef_y (max_y); - extents->height = font->em_scalef_y (min_y) - extents->y_bearing; - } - else { extents->x_bearing = roundf (min_x); extents->width = roundf (max_x - extents->x_bearing); extents->y_bearing = roundf (max_y); extents->height = roundf (min_y - extents->y_bearing); + + if (scaled) + font->scale_glyph_extents (extents); } } @@ -273,7 +306,6 @@ struct glyf_accelerator_t contour_point_t *get_phantoms_sink () { return phantoms; } }; - public: unsigned get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { @@ -315,6 +347,15 @@ struct glyf_accelerator_t } #endif + bool get_leading_bearing_without_var_unscaled (hb_codepoint_t gid, bool is_vertical, int *lsb) const + { + if (unlikely (gid >= num_glyphs)) return false; + if (is_vertical) return false; // TODO Humm, what to do here? + + *lsb = glyph_for_gid (gid).get_header ()->xMin; + return true; + } + public: bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const { @@ -327,6 +368,15 @@ struct glyf_accelerator_t return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const + { + funcs->push_clip_glyph (data, gid, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; + } + const glyf_impl::Glyph glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const { @@ -375,13 +425,14 @@ struct glyf_accelerator_t }; -inline void +inline bool glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_font_t *font, hb_vector_t& glyphs /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); unsigned num_glyphs = plan->num_output_glyphs (); - if (!glyphs.resize (num_glyphs)) return; + if (!glyphs.resize (num_glyphs)) return false; for (auto p : plan->glyph_map->iter ()) { @@ -391,31 +442,48 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, if (unlikely (new_gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && - plan->pinned_at_default) + !plan->normalized_coords) subset_glyph.source_glyph = glyf_impl::Glyph (); else - subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); + { + /* If plan has an accelerator, the preprocessing step already trimmed glyphs. + * Don't trim them again! */ + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator); + } if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) subset_glyph.drop_hints_bytes (); else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); + + if (font) + { + if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf))) + { + // when pinned at default, only bounds are updated, thus no need to free + if (!plan->pinned_at_default) + _free_compiled_subset_glyphs (glyphs); + return false; + } + } } + return true; } -inline bool -glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, - hb_vector_t *glyphs /* OUT */) const +inline hb_font_t * +glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const { - OT::glyf_accelerator_t glyf (plan->source); hb_font_t *font = hb_font_create (plan->source); - if (unlikely (!font)) return false; + if (unlikely (font == hb_font_get_empty ())) return nullptr; hb_vector_t vars; - if (unlikely (!vars.alloc (plan->user_axes_location->get_population ()))) - return false; + if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) + { + hb_font_destroy (font); + return nullptr; + } - for (auto _ : *plan->user_axes_location) + for (auto _ : plan->user_axes_location) { hb_variation_t var; var.tag = _.first; @@ -423,18 +491,10 @@ glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan, vars.push (var); } - hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ()); - for (auto& subset_glyph : *glyphs) - { - if (!const_cast (subset_glyph).compile_bytes_with_deltas (plan, font, glyf)) - { - hb_font_destroy (font); - return false; - } - } - - hb_font_destroy (font); - return true; +#ifndef HB_NO_VAR + hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ()); +#endif + return font; } diff --git a/third_party/harfbuzz-ng/src/src/OT/glyf/path-builder.hh b/third_party/harfbuzz-ng/src/src/OT/glyf/path-builder.hh index 9bfc45a1a607..8916241f76e3 100644 --- a/third_party/harfbuzz-ng/src/src/OT/glyf/path-builder.hh +++ b/third_party/harfbuzz-ng/src/src/OT/glyf/path-builder.hh @@ -26,22 +26,29 @@ struct path_builder_t optional_point_t lerp (optional_point_t p, float t) { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } - } first_oncurve, first_offcurve, last_offcurve; + } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2; path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) { font = font_; draw_session = &draw_session_; - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t (); } /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 See also: * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html - * https://stackoverflow.com/a/20772557 */ + * https://stackoverflow.com/a/20772557 + * + * Cubic support added. */ void consume_point (const contour_point_t &point) { bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; +#ifdef HB_NO_CUBIC_GLYF + bool is_cubic = false; +#else + bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); +#endif optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); if (!first_oncurve) { @@ -52,7 +59,12 @@ struct path_builder_t } else { - if (first_offcurve) + if (is_cubic && !first_offcurve2) + { + first_offcurve2 = first_offcurve; + first_offcurve = p; + } + else if (first_offcurve) { optional_point_t mid = first_offcurve.lerp (p, .5f); first_oncurve = mid; @@ -69,16 +81,41 @@ struct path_builder_t { if (is_on_curve) { - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - p.x, p.y); + if (last_offcurve2) + { + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + p.x, p.y); + last_offcurve2 = optional_point_t (); + } + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + p.x, p.y); last_offcurve = optional_point_t (); } else { - optional_point_t mid = last_offcurve.lerp (p, .5f); - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); - last_offcurve = p; + if (is_cubic && !last_offcurve2) + { + last_offcurve2 = last_offcurve; + last_offcurve = p; + } + else + { + optional_point_t mid = last_offcurve.lerp (p, .5f); + + if (is_cubic) + { + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve2 = optional_point_t (); + } + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve = p; + } } } else @@ -94,19 +131,40 @@ struct path_builder_t { if (first_offcurve && last_offcurve) { - optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); + optional_point_t mid = last_offcurve.lerp (first_offcurve2 ? + first_offcurve2 : + first_offcurve, .5f); + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); last_offcurve = optional_point_t (); - /* now check the rest */ } + /* now check the rest */ if (first_offcurve && first_oncurve) - draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, - first_oncurve.x, first_oncurve.y); + { + if (first_offcurve2) + draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y, + first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, + first_oncurve.x, first_oncurve.y); + } else if (last_offcurve && first_oncurve) - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - first_oncurve.x, first_oncurve.y); + { + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + } else if (first_oncurve) draw_session->line_to (first_oncurve.x, first_oncurve.y); else if (first_offcurve) @@ -117,7 +175,7 @@ struct path_builder_t } /* Getting ready for the next contour */ - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); draw_session->close_path (); } } diff --git a/third_party/harfbuzz-ng/src/src/OT/name/name.hh b/third_party/harfbuzz-ng/src/src/OT/name/name.hh new file mode 100644 index 000000000000..c1839f3b683c --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/OT/name/name.hh @@ -0,0 +1,589 @@ +/* + * 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 + */ + +#ifndef OT_NAME_NAME_HH +#define OT_NAME_NAME_HH + +#include "../../hb-open-type.hh" +#include "../../hb-ot-name-language.hh" +#include "../../hb-aat-layout.hh" +#include "../../hb-utf.hh" + + +namespace OT { + +template +inline unsigned int +hb_ot_name_convert_utf (hb_bytes_t bytes, + unsigned int *text_size /* IN/OUT */, + typename out_utf_t::codepoint_t *text /* OUT */) +{ + unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t); + const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ; + const typename in_utf_t::codepoint_t *src_end = src + src_len; + + typename out_utf_t::codepoint_t *dst = text; + + hb_codepoint_t unicode; + const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + + if (text_size && *text_size) + { + (*text_size)--; /* Save room for NUL-termination. */ + const typename out_utf_t::codepoint_t *dst_end = text + *text_size; + + while (src < src_end && dst < dst_end) + { + const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement); + typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode); + if (dst_next == dst) + break; /* Out-of-room. */ + + dst = dst_next; + src = src_next; + } + + *text_size = dst - text; + *dst = 0; /* NUL-terminate. */ + } + + /* Accumulate length of rest. */ + unsigned int dst_len = dst - text; + while (src < src_end) + { + src = in_utf_t::next (src, src_end, &unicode, replacement); + dst_len += out_utf_t::encode_len (unicode); + } + return dst_len; +} + +#define entry_score var.u16[0] +#define entry_index var.u16[1] + + +/* + * name -- Naming + * https://docs.microsoft.com/en-us/typography/opentype/spec/name + */ +#define HB_OT_TAG_name HB_TAG('n','a','m','e') + +#define UNSUPPORTED 42 + +struct NameRecord +{ + hb_language_t language (hb_face_t *face) const + { +#ifndef HB_NO_OT_NAME_LANGUAGE + unsigned int p = platformID; + unsigned int l = languageID; + + if (p == 3) + return _hb_ot_name_language_for_ms_code (l); + + if (p == 1) + return _hb_ot_name_language_for_mac_code (l); + +#ifndef HB_NO_OT_NAME_LANGUAGE_AAT + if (p == 0) + return face->table.ltag->get_language (l); +#endif + +#endif + return HB_LANGUAGE_INVALID; + } + + uint16_t score () const + { + /* Same order as in cmap::find_best_subtable(). */ + unsigned int p = platformID; + unsigned int e = encodingID; + + /* 32-bit. */ + if (p == 3 && e == 10) return 0; + if (p == 0 && e == 6) return 1; + if (p == 0 && e == 4) return 2; + + /* 16-bit. */ + if (p == 3 && e == 1) return 3; + if (p == 0 && e == 3) return 4; + if (p == 0 && e == 2) return 5; + if (p == 0 && e == 1) return 6; + if (p == 0 && e == 0) return 7; + + /* Symbol. */ + if (p == 3 && e == 0) return 8; + + /* We treat all Mac Latin names as ASCII only. */ + if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ + + return UNSUPPORTED; + } + + NameRecord* copy (hb_serialize_context_t *c, const void *base +#ifdef HB_EXPERIMENTAL_API + , const hb_hashmap_t *name_table_overrides +#endif + ) const + { + TRACE_SERIALIZE (this); + HB_UNUSED auto snap = c->snapshot (); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); +#ifdef HB_EXPERIMENTAL_API + hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID); + hb_bytes_t* name_bytes; + + if (name_table_overrides->has (record_ids, &name_bytes)) { + hb_bytes_t encoded_bytes = *name_bytes; + char *name_str_utf16_be = nullptr; + + if (platformID != 1) + { + unsigned text_size = hb_ot_name_convert_utf (*name_bytes, nullptr, nullptr); + + text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf() + unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; + name_str_utf16_be = (char *) hb_calloc (byte_len, 1); + if (!name_str_utf16_be) + { + c->revert (snap); + return_trace (nullptr); + } + hb_ot_name_convert_utf (*name_bytes, &text_size, + (hb_utf16_be_t::codepoint_t *) name_str_utf16_be); + + unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; + if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { + c->revert (snap); + hb_free (name_str_utf16_be); + return_trace (nullptr); + } + + encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len); + } + else + { + // mac platform, copy the UTF-8 string(all ascii characters) as is + if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { + c->revert (snap); + return_trace (nullptr); + } + } + + out->offset = 0; + c->push (); + encoded_bytes.copy (c); + c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0); + hb_free (name_str_utf16_be); + } + else +#endif + { + out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length); + } + return_trace (out); + } + + bool isUnicode () const + { + unsigned int p = platformID; + unsigned int e = encodingID; + + return (p == 0 || + (p == 3 && (e == 0 || e == 1 || e == 10))); + } + + static int cmp (const void *pa, const void *pb) + { + const NameRecord *a = (const NameRecord *)pa; + const NameRecord *b = (const NameRecord *)pb; + + if (a->platformID != b->platformID) + return a->platformID - b->platformID; + + if (a->encodingID != b->encodingID) + return a->encodingID - b->encodingID; + + if (a->languageID != b->languageID) + return a->languageID - b->languageID; + + if (a->nameID != b->nameID) + return a->nameID - b->nameID; + + if (a->length != b->length) + return a->length - b->length; + + return 0; + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && offset.sanitize (c, base, length)); + } + + HBUINT16 platformID; /* Platform ID. */ + HBUINT16 encodingID; /* Platform-specific encoding ID. */ + HBUINT16 languageID; /* Language ID. */ + HBUINT16 nameID; /* Name ID. */ + HBUINT16 length; /* String length (in bytes). */ + NNOffset16To> + offset; /* String offset from start of storage area (in bytes). */ + public: + DEFINE_SIZE_STATIC (12); +}; + +static int +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact) +{ + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + /* Compare by name_id, then language. */ + + if (a->name_id != b->name_id) + return a->name_id - b->name_id; + + if (a->language == b->language) return 0; + if (!a->language) return -1; + if (!b->language) return +1; + + const char *astr = hb_language_to_string (a->language); + const char *bstr = hb_language_to_string (b->language); + + signed c = strcmp (astr, bstr); + + // 'a' is the user request, and 'b' is string in the font. + // If eg. user asks for "en-us" and font has "en", approve. + if (!exact && c && + hb_language_matches (b->language, a->language)) + return 0; + + return c; +} + +static int +_hb_ot_name_entry_cmp (const void *pa, const void *pb) +{ + /* Compare by name_id, then language, then score, then index. */ + + int v = _hb_ot_name_entry_cmp_key (pa, pb, true); + if (v) + return v; + + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + if (a->entry_score != b->entry_score) + return a->entry_score - b->entry_score; + + if (a->entry_index != b->entry_index) + return a->entry_index - b->entry_index; + + return 0; +} + +struct name +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_name; + + unsigned int get_size () const + { return min_size + count * nameRecordZ.item_size; } + + template + bool serialize (hb_serialize_context_t *c, + Iterator it, + const void *src_string_pool +#ifdef HB_EXPERIMENTAL_API + , const hb_vector_t& insert_name_records + , const hb_hashmap_t *name_table_overrides +#endif + ) + { + TRACE_SERIALIZE (this); + + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + unsigned total_count = it.len () +#ifdef HB_EXPERIMENTAL_API + + insert_name_records.length +#endif + ; + this->format = 0; + if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return false; + + NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size); + if (unlikely (!name_records)) return_trace (false); + + hb_array_t records (name_records, total_count); + + for (const NameRecord& record : it) + { + hb_memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } + +#ifdef HB_EXPERIMENTAL_API + for (unsigned i = 0; i < insert_name_records.length; i++) + { + const hb_ot_name_record_ids_t& ids = insert_name_records[i]; + NameRecord record; + record.platformID = ids.platform_id; + record.encodingID = ids.encoding_id; + record.languageID = ids.language_id; + record.nameID = ids.name_id; + record.length = 0; // handled in NameRecord copy() + record.offset = 0; + memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } +#endif + + records.qsort (); + + c->copy_all (records, + src_string_pool +#ifdef HB_EXPERIMENTAL_API + , name_table_overrides +#endif + ); + hb_free (records.arrayZ); + + + if (unlikely (c->ran_out_of_room ())) return_trace (false); + + this->stringOffset = c->length (); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + name *name_prime = c->serializer->start_embed (); + if (unlikely (!name_prime)) return_trace (false); + +#ifdef HB_EXPERIMENTAL_API + const hb_hashmap_t *name_table_overrides = + &c->plan->name_table_overrides; +#endif + + auto it = + + nameRecordZ.as_array (count) + | hb_filter (c->plan->name_ids, &NameRecord::nameID) + | hb_filter (c->plan->name_languages, &NameRecord::languageID) + | hb_filter ([&] (const NameRecord& namerecord) { + return + (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY) + || namerecord.isUnicode (); + }) +#ifdef HB_EXPERIMENTAL_API + | hb_filter ([&] (const NameRecord& namerecord) { + if (name_table_overrides->is_empty ()) + return true; + hb_ot_name_record_ids_t rec_ids (namerecord.platformID, + namerecord.encodingID, + namerecord.languageID, + namerecord.nameID); + + hb_bytes_t *p; + if (name_table_overrides->has (rec_ids, &p) && + (*p).length == 0) + return false; + return true; + }) +#endif + ; + +#ifdef HB_EXPERIMENTAL_API + hb_hashmap_t retained_name_record_ids; + for (const NameRecord& rec : it) + { + hb_ot_name_record_ids_t rec_ids (rec.platformID, + rec.encodingID, + rec.languageID, + rec.nameID); + retained_name_record_ids.set (rec_ids, 1); + } + + hb_vector_t insert_name_records; + if (!name_table_overrides->is_empty ()) + { + if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true))) + return_trace (false); + for (const auto& record_ids : name_table_overrides->keys ()) + { + if (name_table_overrides->get (record_ids).length == 0) + continue; + if (retained_name_record_ids.has (record_ids)) + continue; + insert_name_records.push (record_ids); + } + } +#endif + + return (name_prime->serialize (c->serializer, it, + std::addressof (this + stringOffset) +#ifdef HB_EXPERIMENTAL_API + , insert_name_records + , name_table_overrides +#endif + )); + } + + bool sanitize_records (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + const void *string_pool = (this+stringOffset).arrayZ; + return_trace (nameRecordZ.sanitize (c, count, string_pool)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (format == 0 || format == 1) && + c->check_array (nameRecordZ.arrayZ, count) && + c->check_range (this, stringOffset) && + sanitize_records (c)); + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + this->table = hb_sanitize_context_t ().reference_table (face); + assert (this->table.get_length () >= this->table->stringOffset); + this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); + this->pool_len = this->table.get_length () - this->table->stringOffset; + const hb_array_t all_names (this->table->nameRecordZ.arrayZ, + this->table->count); + + this->names.alloc (all_names.length, true); + + for (unsigned int i = 0; i < all_names.length; i++) + { + hb_ot_name_entry_t *entry = this->names.push (); + + entry->name_id = all_names[i].nameID; + entry->language = all_names[i].language (face); + entry->entry_score = all_names[i].score (); + entry->entry_index = i; + } + + this->names.qsort (_hb_ot_name_entry_cmp); + /* Walk and pick best only for each name_id,language pair, + * while dropping unsupported encodings. */ + unsigned int j = 0; + for (unsigned int i = 0; i < this->names.length; i++) + { + if (this->names[i].entry_score == UNSUPPORTED || + this->names[i].language == HB_LANGUAGE_INVALID) + continue; + if (i && + this->names[i - 1].name_id == this->names[i].name_id && + this->names[i - 1].language == this->names[i].language) + continue; + this->names[j++] = this->names[i]; + } + this->names.resize (j); + } + ~accelerator_t () + { + this->table.destroy (); + } + + int get_index (hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *width=nullptr) const + { + const hb_ot_name_entry_t key = {name_id, {0}, language}; + const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + true); + + if (!entry) + { + entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + false); + } + + if (!entry) + return -1; + + if (width) + *width = entry->entry_score < 10 ? 2 : 1; + + return entry->entry_index; + } + + hb_bytes_t get_name (unsigned int idx) const + { + const hb_array_t all_names (table->nameRecordZ.arrayZ, table->count); + const NameRecord &record = all_names[idx]; + const hb_bytes_t string_pool (pool, pool_len); + return string_pool.sub_array (record.offset, record.length); + } + + private: + const char *pool; + unsigned int pool_len; + public: + hb_blob_ptr_t table; + hb_vector_t names; + }; + + public: + /* We only implement format 0 for now. */ + HBUINT16 format; /* Format selector (=0/1). */ + HBUINT16 count; /* Number of name records. */ + NNOffset16To> + stringOffset; /* Offset to start of string storage (from start of table). */ + UnsizedArrayOf + nameRecordZ; /* The name records where count is the number of records. */ + public: + DEFINE_SIZE_ARRAY (6, nameRecordZ); +}; + +#undef entry_index +#undef entry_score + +struct name_accelerator_t : name::accelerator_t { + name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {} +}; + +} /* namespace OT */ + + +#endif /* OT_NAME_NAME_HH */ diff --git a/third_party/harfbuzz-ng/src/src/check-libstdc++.py b/third_party/harfbuzz-ng/src/src/check-libstdc++.py index 85b7265312f3..e70d5f80b23d 100755 --- a/third_party/harfbuzz-ng/src/src/check-libstdc++.py +++ b/third_party/harfbuzz-ng/src/src/check-libstdc++.py @@ -19,7 +19,7 @@ tested = False # harfbuzz-icu links to libstdc++ because icu does. -for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject']: +for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-gobject', 'harfbuzz-cairo']: for suffix in ['so', 'dylib']: so = os.path.join (libs, 'lib%s.%s' % (soname, suffix)) if not os.path.exists (so): continue diff --git a/third_party/harfbuzz-ng/src/src/check-symbols.py b/third_party/harfbuzz-ng/src/src/check-symbols.py index d0b8bd3c82dd..91bf8b0671a3 100755 --- a/third_party/harfbuzz-ng/src/src/check-symbols.py +++ b/third_party/harfbuzz-ng/src/src/check-symbols.py @@ -22,7 +22,7 @@ tested = False stat = 0 -for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject']: +for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject', 'harfbuzz-cairo']: for suffix in ['so', 'dylib']: so = os.path.join (builddir, libs, 'lib%s.%s' % (soname, suffix)) if not os.path.exists (so): continue diff --git a/third_party/harfbuzz-ng/src/src/gen-def.py b/third_party/harfbuzz-ng/src/src/gen-def.py index e751f524e476..6011817bc546 100755 --- a/third_party/harfbuzz-ng/src/src/gen-def.py +++ b/third_party/harfbuzz-ng/src/src/gen-def.py @@ -19,10 +19,9 @@ if '--experimental-api' not in sys.argv: # Move these to harfbuzz-sections.txt when got stable experimental_symbols = \ -"""hb_subset_repack_or_fail -hb_subset_input_pin_axis_location -hb_subset_input_pin_axis_to_default -hb_subset_preprocess +"""hb_shape_justify +hb_subset_repack_or_fail +hb_subset_input_override_name_table """.splitlines () symbols = [x for x in symbols if x not in experimental_symbols] symbols = "\n".join (symbols) diff --git a/third_party/harfbuzz-ng/src/src/gen-indic-table.py b/third_party/harfbuzz-ng/src/src/gen-indic-table.py index 0ff3ef4ac2fa..4ef970265d12 100755 --- a/third_party/harfbuzz-ng/src/src/gen-indic-table.py +++ b/third_party/harfbuzz-ng/src/src/gen-indic-table.py @@ -95,6 +95,7 @@ 'PLACEHOLDER', 'DOTTEDCIRCLE', 'RS', + 'MPst', 'Repha', 'Ra', 'CM', @@ -168,8 +169,6 @@ 'Vowel' : 'V', 'Vowel_Dependent' : 'M', 'Vowel_Independent' : 'V', - 'Dotted_Circle' : 'DOTTEDCIRCLE', # Ours, not Unicode's - 'Ra' : 'Ra', # Ours, not Unicode's } position_map = { 'Not_Applicable' : 'END', @@ -240,6 +239,9 @@ 0x0953: 'SM', 0x0954: 'SM', + # U+0A40 GURMUKHI VOWEL SIGN II may be preceded by U+0A02 GURMUKHI SIGN BINDI. + 0x0A40: 'MPst', + # The following act like consonants. 0x0A72: 'C', 0x0A73: 'C', @@ -440,7 +442,7 @@ def position_to_category(pos): indic_data[k] = (new_cat, pos, unicode_data[2][k]) # We only expect position for certain types -positioned_categories = ('CM', 'SM', 'RS', 'H', 'M') +positioned_categories = ('CM', 'SM', 'RS', 'H', 'M', 'MPst') for k, (cat, pos, block) in indic_data.items(): if cat not in positioned_categories: pos = 'END' @@ -450,11 +452,12 @@ def position_to_category(pos): # Keep in sync with CONSONANT_FLAGS in the shaper consonant_categories = ('C', 'CS', 'Ra','CM', 'V', 'PLACEHOLDER', 'DOTTEDCIRCLE') +matra_categories = ('M', 'MPst') smvd_categories = ('SM', 'VD', 'A', 'Symbol') for k, (cat, pos, block) in indic_data.items(): if cat in consonant_categories: pos = 'BASE_C' - elif cat == 'M': + elif cat in matra_categories: if block.startswith('Khmer') or block.startswith('Myanmar'): cat = position_to_category(pos) else: @@ -634,7 +637,7 @@ def print_block (block, start, end, data): end = (end-1)//8*8 + 7 if start != last + 1: - if start - last <= 1+16*3: + if start - last <= 1+16*2: print_block (None, last+1, start-1, indic_data) else: if last >= 0: @@ -691,6 +694,6 @@ def print_block (block, start, end, data): print () print ("/* == End of generated table == */") -# Maintain at least 30% occupancy in the table */ -if occupancy < 30: +# Maintain at least 50% occupancy in the table */ +if occupancy < 50: raise Exception ("Table too sparse, please investigate: ", occupancy) diff --git a/third_party/harfbuzz-ng/src/src/gen-ucd-table.py b/third_party/harfbuzz-ng/src/src/gen-ucd-table.py index f4c099f863e6..d85ae4faa892 100755 --- a/third_party/harfbuzz-ng/src/src/gen-ucd-table.py +++ b/third_party/harfbuzz-ng/src/src/gen-ucd-table.py @@ -25,14 +25,28 @@ logging.info('Preparing data tables...') + +# This is how the data is encoded: +# +# General_Category (gc), Canonical_Combining_Class (ccc), +# and Script (sc) are encoded as integers. +# +# Mirroring character (bmg) is encoded as difference from +# the original character. +# +# Composition & Decomposition (dm) are encoded elaborately, +# as discussed below. + gc = [u['gc'] for u in ucd] ccc = [int(u['ccc']) for u in ucd] bmg = [int(v, 16) - int(u) if v else 0 for u,v in enumerate(u['bmg'] for u in ucd)] -#gc_ccc_non0 = set((cat,klass) for cat,klass in zip(gc,ccc) if klass) -#gc_bmg_non0 = set((cat,mirr) for cat,mirr in zip(gc, bmg) if mirr) - sc = [u['sc'] for u in ucd] + +# Prepare Compose / Decompose data +# +# This code is very dense. See hb_ucd_compose() / hb_ucd_decompose() for the logic. + dm = {i:tuple(int(v, 16) for v in u['dm'].split()) for i,u in enumerate(ucd) if u['dm'] != '#' and u['dt'] == 'can' and not (0xAC00 <= i < 0xAC00+11172)} ce = {i for i,u in enumerate(ucd) if u['Comp_Ex'] == 'Y'} @@ -63,6 +77,9 @@ dm_order.update(dm1_order) dm_order.update(dm2_order) + +# Prepare General_Category / Script mapping arrays + gc_order = dict() for i,v in enumerate(('Cc', 'Cf', 'Cn', 'Co', 'Cs', 'Ll', 'Lm', 'Lo', 'Lt', 'Lu', 'Mc', 'Me', 'Mn', 'Nd', 'Nl', 'No', 'Pc', 'Pd', 'Pe', 'Pf', @@ -83,10 +100,18 @@ sc_order[i] = tag sc_array.append(name) -DEFAULT = 3 -COMPACT = 5 -SLOPPY = 9 +# Write out main data + +DEFAULT = 'DEFAULT' +COMPACT = 'COMPACT' +SLOPPY = 'SLOPPY' + +compression_level = { + DEFAULT: 5, + COMPACT: 9, + SLOPPY: 9, +} logging.info('Generating output...') print("/* == Start of generated table == */") @@ -104,6 +129,9 @@ print('#include "hb.hh"') print() + +# Write mapping data + code = packTab.Code('_hb_ucd') sc_array, _ = code.addArray('hb_script_t', 'sc_map', sc_array) dm1_p0_array, _ = code.addArray('uint16_t', 'dm1_p0_map', dm1_p0_array) @@ -120,18 +148,24 @@ ('dm', dm, None, dm_order), ] -for compression in (DEFAULT, COMPACT, SLOPPY): + +# Write main data + +for step in (DEFAULT, COMPACT, SLOPPY): + compression = compression_level[step] logging.info(' Compression=%d:' % compression) print() - if compression == DEFAULT: + if step == DEFAULT: print('#ifndef HB_OPTIMIZE_SIZE') - elif compression == COMPACT: + elif step == COMPACT: print('#elif !defined(HB_NO_UCD_UNASSIGNED)') - else: + elif step == SLOPPY: print('#else') + else: + assert False print() - if compression == SLOPPY: + if step == SLOPPY: for i in range(len(gc)): if (i % 128) and gc[i] == 'Cn': gc[i] = gc[i - 1] @@ -157,6 +191,7 @@ print() + print('#endif') print() diff --git a/third_party/harfbuzz-ng/src/src/gen-use-table.py b/third_party/harfbuzz-ng/src/src/gen-use-table.py index 0600a33886be..e8b76dfb5fbd 100755 --- a/third_party/harfbuzz-ng/src/src/gen-use-table.py +++ b/third_party/harfbuzz-ng/src/src/gen-use-table.py @@ -1,6 +1,9 @@ #!/usr/bin/env python3 # flake8: noqa: F821 +import logging +logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.INFO) + """usage: ./gen-use-table.py IndicSyllabicCategory.txt IndicPositionalCategory.txt ArabicShaping.txt DerivedCoreProperties.txt UnicodeData.txt Blocks.txt Scripts.txt IndicSyllabicCategory-Additional.txt IndicPositionalCategory-Additional.txt Input files: @@ -465,10 +468,29 @@ def print_block (block, start, end, use_data): import packTab data = {u:v[0] for u,v in use_data.items()} -code = packTab.Code('hb_use') -sol = packTab.pack_table(data, compression=5, default='O') -sol.genCode(code, f'get_category') -code.print_c(linkage='static inline') + +DEFAULT = 5 +COMPACT = 9 +for compression in (DEFAULT, COMPACT): + + logging.info(' Compression=%d:' % compression) + print() + if compression == DEFAULT: + print('#ifndef HB_OPTIMIZE_SIZE') + elif compression == COMPACT: + print('#else') + else: + assert False + print() + + code = packTab.Code('hb_use') + sol = packTab.pack_table(data, compression=compression, default='O') + logging.info(' FullCost=%d' % (sol.fullCost)) + sol.genCode(code, f'get_category') + code.print_c(linkage='static inline') + print () + +print('#endif') print () for k in sorted(use_mapping.keys()): diff --git a/third_party/harfbuzz-ng/src/src/graph/graph.hh b/third_party/harfbuzz-ng/src/src/graph/graph.hh index 06e84780cc13..38ca5db09618 100644 --- a/third_party/harfbuzz-ng/src/src/graph/graph.hh +++ b/third_party/harfbuzz-ng/src/src/graph/graph.hh @@ -49,6 +49,50 @@ struct graph_t unsigned end = 0; unsigned priority = 0; + + bool link_positions_valid (unsigned num_objects, bool removed_nil) + { + hb_set_t assigned_bytes; + for (const auto& l : obj.real_links) + { + if (l.objidx >= num_objects + || (removed_nil && !l.objidx)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Invalid object index."); + return false; + } + + unsigned start = l.position; + unsigned end = start + l.width - 1; + + if (unlikely (l.width < 2 || l.width > 4)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Invalid link width."); + return false; + } + + if (unlikely (end >= table_size ())) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Link position is out of bounds."); + return false; + } + + if (unlikely (assigned_bytes.intersects (start, end))) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Found offsets whose positions overlap."); + return false; + } + + assigned_bytes.add_range (start, end); + } + + return !assigned_bytes.in_error (); + } + void normalize () { obj.real_links.qsort (); @@ -79,7 +123,7 @@ struct graph_t while (a || b) { DEBUG_MSG (SUBSET_REPACK, nullptr, - " 0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b); + " 0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b); a++; b++; } @@ -132,7 +176,7 @@ struct graph_t for (unsigned i = 0; i < parents.length; i++) { if (parents[i] != parent_index) continue; - parents.remove (i); + parents.remove_unordered (i); break; } } @@ -148,7 +192,7 @@ struct graph_t if ((obj.head + link.position) != offset) continue; - obj.real_links.remove (i); + obj.real_links.remove_unordered (i); return; } } @@ -286,8 +330,6 @@ struct graph_t vertices_scratch_.alloc (objects.length); for (unsigned i = 0; i < objects.length; i++) { - // TODO(grieger): check all links point to valid objects. - // If this graph came from a serialization buffer object 0 is the // nil object. We don't need it for our purposes here so drop it. if (i == 0 && !objects[i]) @@ -299,6 +341,9 @@ struct graph_t vertex_t* v = vertices_.push (); if (check_success (!vertices_.in_error ())) v->obj = *objects[i]; + + check_success (v->link_positions_valid (objects.length, removed_nil)); + if (!removed_nil) continue; // Fix indices to account for removed nil object. for (auto& l : v->obj.all_links_writer ()) { @@ -418,6 +463,13 @@ struct graph_t hb_swap (sorted_graph[new_id], vertices_[next_id]); const vertex_t& next = sorted_graph[new_id]; + if (unlikely (!check_success(new_id >= 0))) { + // We are out of ids. Which means we've visited a node more than once. + // This graph contains a cycle which is not allowed. + DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle."); + return; + } + id_map[next_id] = new_id--; for (const auto& link : next.obj.all_links ()) { @@ -648,6 +700,9 @@ struct graph_t } } + if (in_error ()) + return false; + if (!made_changes) return false; @@ -781,7 +836,11 @@ struct graph_t if (index_map.has (node_idx)) return; - index_map.set (node_idx, duplicate (node_idx)); + unsigned clone_idx = duplicate (node_idx); + if (!check_success (clone_idx != (unsigned) -1)) + return; + + index_map.set (node_idx, clone_idx); for (const auto& l : object (node_idx).all_links ()) { duplicate_subgraph (l.objidx, index_map); } @@ -866,12 +925,12 @@ struct graph_t { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. - DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u => %u", parent_idx, child_idx); return -1; } - DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u => %u", parent_idx, child_idx); unsigned clone_idx = duplicate (child_idx); @@ -929,7 +988,7 @@ struct graph_t */ bool raise_childrens_priority (unsigned parent_idx) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %u", parent_idx); // This operation doesn't change ordering until a sort is run, so no need // to invalidate positions. It does not change graph structure so no need @@ -941,6 +1000,72 @@ struct graph_t return made_change; } + bool is_fully_connected () + { + update_parents(); + + if (root().parents) + // Root cannot have parents. + return false; + + for (unsigned i = 0; i < root_idx (); i++) + { + if (!vertices_[i].parents) + return false; + } + return true; + } + +#if 0 + /* + * Saves the current graph to a packed binary format which the repacker fuzzer takes + * as a seed. + */ + void save_fuzzer_seed (hb_tag_t tag) const + { + FILE* f = fopen ("./repacker_fuzzer_seed", "w"); + fwrite ((void*) &tag, sizeof (tag), 1, f); + + uint16_t num_objects = vertices_.length; + fwrite ((void*) &num_objects, sizeof (num_objects), 1, f); + + for (const auto& v : vertices_) + { + uint16_t blob_size = v.table_size (); + fwrite ((void*) &blob_size, sizeof (blob_size), 1, f); + fwrite ((const void*) v.obj.head, blob_size, 1, f); + } + + uint16_t link_count = 0; + for (const auto& v : vertices_) + link_count += v.obj.real_links.length; + + fwrite ((void*) &link_count, sizeof (link_count), 1, f); + + typedef struct + { + uint16_t parent; + uint16_t child; + uint16_t position; + uint8_t width; + } link_t; + + for (unsigned i = 0; i < vertices_.length; i++) + { + for (const auto& l : vertices_[i].obj.real_links) + { + link_t link { + (uint16_t) i, (uint16_t) l.objidx, + (uint16_t) l.position, (uint8_t) l.width + }; + fwrite ((void*) &link, sizeof (link), 1, f); + } + } + + fclose (f); + } +#endif + void print_orphaned_nodes () { if (!DEBUG_ENABLED(SUBSET_REPACK)) return; @@ -949,6 +1074,10 @@ struct graph_t parents_invalid = true; update_parents(); + if (root().parents) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges."); + } + for (unsigned i = 0; i < root_idx (); i++) { const auto& v = vertices_[i]; @@ -1065,6 +1194,11 @@ struct graph_t } } + for (unsigned i = 0; i < vertices_.length; i++) + // parents arrays must be accurate or downstream operations like cycle detection + // and sorting won't work correctly. + check_success (!vertices_[i].parents.in_error ()); + parents_invalid = false; } diff --git a/third_party/harfbuzz-ng/src/src/graph/gsubgpos-graph.hh b/third_party/harfbuzz-ng/src/src/graph/gsubgpos-graph.hh index 9213cf599e56..c170638409f8 100644 --- a/third_party/harfbuzz-ng/src/src/graph/gsubgpos-graph.hh +++ b/third_party/harfbuzz-ng/src/src/graph/gsubgpos-graph.hh @@ -201,7 +201,7 @@ struct Lookup : public OT::Lookup + new_subtable_count * OT::Offset16::static_size; char* buffer = (char*) hb_calloc (1, new_size); c.add_buffer (buffer); - memcpy (buffer, v.obj.head, v.table_size()); + hb_memcpy (buffer, v.obj.head, v.table_size()); v.obj.head = buffer; v.obj.tail = buffer + new_size; diff --git a/third_party/harfbuzz-ng/src/src/graph/markbasepos-graph.hh b/third_party/harfbuzz-ng/src/src/graph/markbasepos-graph.hh index 9b01b5d86d85..84ef5f71b93c 100644 --- a/third_party/harfbuzz-ng/src/src/graph/markbasepos-graph.hh +++ b/third_party/harfbuzz-ng/src/src/graph/markbasepos-graph.hh @@ -112,7 +112,7 @@ struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix auto& child = c.graph.vertices_[child_idx]; child.remove_parent (this_index); - o.real_links.remove (i); + o.real_links.remove_unordered (i); num_links--; i--; } @@ -372,7 +372,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2iter ()) + + hb_enumerate (mark_coverage.table->iter ()) | hb_filter (marks, hb_first) | hb_map_retains_sorting (hb_second) ; @@ -431,7 +431,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2iter ()) + + hb_enumerate (mark_coverage.table->iter ()) | hb_filter (marks, hb_first) | hb_map_retains_sorting (hb_second) ; diff --git a/third_party/harfbuzz-ng/src/src/graph/pairpos-graph.hh b/third_party/harfbuzz-ng/src/src/graph/pairpos-graph.hh index 041e5069b087..1c13eb24f945 100644 --- a/third_party/harfbuzz-ng/src/src/graph/pairpos-graph.hh +++ b/third_party/harfbuzz-ng/src/src/graph/pairpos-graph.hh @@ -434,7 +434,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4values[0], + hb_memcpy (&pair_pos_prime->values[0], start_addr, num_records * split_context.class1_record_size); diff --git a/third_party/harfbuzz-ng/src/src/graph/serialize.hh b/third_party/harfbuzz-ng/src/src/graph/serialize.hh index ecc6cc5aea2b..040fd1de5fd5 100644 --- a/third_party/harfbuzz-ng/src/src/graph/serialize.hh +++ b/third_party/harfbuzz-ng/src/src/graph/serialize.hh @@ -33,6 +33,23 @@ struct overflow_record_t { unsigned parent; unsigned child; + + bool operator != (const overflow_record_t o) const + { return !(*this == o); } + + inline bool operator == (const overflow_record_t& o) const + { + return parent == o.parent && + child == o.child; + } + + inline uint32_t hash () const + { + uint32_t current = 0; + current = current * 31 + hb_hash (parent); + current = current * 31 + hb_hash (child); + return current; + } }; inline @@ -94,6 +111,7 @@ will_overflow (graph_t& graph, if (overflows) overflows->resize (0); graph.update_positions (); + hb_hashmap_t record_set; const auto& vertices = graph.vertices_; for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) { @@ -109,7 +127,10 @@ will_overflow (graph_t& graph, overflow_record_t r; r.parent = parent_idx; r.child = link.objidx; + if (record_set.has(&r)) continue; // don't keep duplicate overflows. + overflows->push (r); + record_set.set(&r, true); } } @@ -132,8 +153,8 @@ void print_overflows (graph_t& graph, const auto& child = graph.vertices_[o.child]; DEBUG_MSG (SUBSET_REPACK, nullptr, " overflow from " - "%4d (%4d in, %4d out, space %2d) => " - "%4d (%4d in, %4d out, space %2d)", + "%4u (%4u in, %4u out, space %2u) => " + "%4u (%4u in, %4u out, space %2u)", o.parent, parent.incoming_edges (), parent.obj.real_links.length + parent.obj.virtual_links.length, @@ -144,7 +165,7 @@ void print_overflows (graph_t& graph, graph.space_for (o.child)); } if (overflows.length > 10) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); + DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %u more overflows.", overflows.length - 10); } } @@ -223,7 +244,7 @@ inline hb_blob_t* serialize (const graph_t& graph) return nullptr; } - memcpy (start, vertices[i].obj.head, size); + hb_memcpy (start, vertices[i].obj.head, size); // Only real links needs to be serialized. for (const auto& link : vertices[i].obj.real_links) diff --git a/third_party/harfbuzz-ng/src/src/harfbuzz-cairo.pc.in b/third_party/harfbuzz-ng/src/src/harfbuzz-cairo.pc.in new file mode 100644 index 000000000000..df97ff151288 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/harfbuzz-cairo.pc.in @@ -0,0 +1,12 @@ +prefix=%prefix% +exec_prefix=%exec_prefix% +libdir=%libdir% +includedir=%includedir% + +Name: harfbuzz cairo integration +Description: HarfBuzz cairo integration +Version: %VERSION% + +Requires: harfbuzz = %VERSION% +Libs: -L${libdir} -lharfbuzz-cairo +Cflags: -I${includedir}/harfbuzz diff --git a/third_party/harfbuzz-ng/src/src/harfbuzz-config.cmake.in b/third_party/harfbuzz-ng/src/src/harfbuzz-config.cmake.in index 0de082c2a63e..ced97919a23d 100644 --- a/third_party/harfbuzz-ng/src/src/harfbuzz-config.cmake.in +++ b/third_party/harfbuzz-ng/src/src/harfbuzz-config.cmake.in @@ -12,13 +12,17 @@ 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}") +if ("@default_library@" MATCHES "static") + set(_harfbuzz_lib_suffix ".a") else () - # Unsupported. - set(harfbuzz_FOUND 0) + 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 () endif () # Add the libraries. diff --git a/third_party/harfbuzz-ng/src/src/harfbuzz-subset.cc b/third_party/harfbuzz-ng/src/src/harfbuzz-subset.cc index a43485e6fbae..c0e23b3eb820 100644 --- a/third_party/harfbuzz-ng/src/src/harfbuzz-subset.cc +++ b/third_party/harfbuzz-ng/src/src/harfbuzz-subset.cc @@ -7,6 +7,7 @@ #include "hb-buffer.cc" #include "hb-common.cc" #include "hb-draw.cc" +#include "hb-face-builder.cc" #include "hb-face.cc" #include "hb-fallback-shape.cc" #include "hb-font.cc" @@ -40,6 +41,9 @@ #include "hb-ot-shaper-vowel-constraints.cc" #include "hb-ot-tag.cc" #include "hb-ot-var.cc" +#include "hb-outline.cc" +#include "hb-paint-extents.cc" +#include "hb-paint.cc" #include "hb-set.cc" #include "hb-shape-plan.cc" #include "hb-shape.cc" @@ -50,6 +54,7 @@ #include "hb-subset-cff1.cc" #include "hb-subset-cff2.cc" #include "hb-subset-input.cc" +#include "hb-subset-instancer-solver.cc" #include "hb-subset-plan.cc" #include "hb-subset-repacker.cc" #include "hb-subset.cc" diff --git a/third_party/harfbuzz-ng/src/src/harfbuzz.cc b/third_party/harfbuzz-ng/src/src/harfbuzz.cc index fe4e21db07ff..d7e8a93f3932 100644 --- a/third_party/harfbuzz-ng/src/src/harfbuzz.cc +++ b/third_party/harfbuzz-ng/src/src/harfbuzz.cc @@ -8,6 +8,7 @@ #include "hb-coretext.cc" #include "hb-directwrite.cc" #include "hb-draw.cc" +#include "hb-face-builder.cc" #include "hb-face.cc" #include "hb-fallback-shape.cc" #include "hb-font.cc" @@ -45,6 +46,9 @@ #include "hb-ot-shaper-vowel-constraints.cc" #include "hb-ot-tag.cc" #include "hb-ot-var.cc" +#include "hb-outline.cc" +#include "hb-paint-extents.cc" +#include "hb-paint.cc" #include "hb-set.cc" #include "hb-shape-plan.cc" #include "hb-shape.cc" diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-layout-common.hh b/third_party/harfbuzz-ng/src/src/hb-aat-layout-common.hh index 6cbed826921d..7d53c354dabc 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-layout-common.hh +++ b/third_party/harfbuzz-ng/src/src/hb-aat-layout-common.hh @@ -28,6 +28,7 @@ #define HB_AAT_LAYOUT_COMMON_HH #include "hb-aat-layout.hh" +#include "hb-aat-map.hh" #include "hb-open-type.hh" namespace OT { @@ -39,6 +40,43 @@ namespace AAT { using namespace OT; +struct ankr; + +struct hb_aat_apply_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "APPLY"; } + template + 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; + const OT::GDEF *gdef_table; + const hb_sorted_vector_t *range_flags = nullptr; + hb_mask_t subtable_flags = 0; + + /* Unused. For debug tracing only. */ + unsigned int lookup_index; + + 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 (&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; } +}; + + /* * Lookup Table */ @@ -426,7 +464,8 @@ enum { DELETED_GLYPH = 0xFFFF }; template struct Entry { - bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + // This does seem like it's ever called. + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); /* Note, we don't recurse-sanitize data because we don't access it. @@ -454,7 +493,8 @@ struct Entry template <> struct Entry { - bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const + // This does seem like it's ever called. + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); @@ -740,16 +780,44 @@ struct StateTableDriver num_glyphs (face_->get_num_glyphs ()) {} template - void drive (context_t *c) + void drive (context_t *c, hb_aat_apply_context_t *ac) { if (!c->in_place) buffer->clear_output (); int state = StateTableT::STATE_START_OF_TEXT; + // If there's only one range, we already checked the flag. + auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr; for (buffer->idx = 0; buffer->successful;) { + /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ + if (last_range) + { + auto *range = last_range; + if (buffer->idx < buffer->len) + { + unsigned cluster = buffer->cur().cluster; + while (cluster < range->cluster_first) + range--; + while (cluster > range->cluster_last) + range++; + + + last_range = range; + } + if (!(range->flags & ac->subtable_flags)) + { + if (buffer->idx == buffer->len || unlikely (!buffer->successful)) + break; + + state = StateTableT::STATE_START_OF_TEXT; + (void) buffer->next_glyph (); + continue; + } + } + unsigned int klass = buffer->idx < buffer->len ? - machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : + machine.get_class (buffer->cur().codepoint, num_glyphs) : (unsigned) StateTableT::CLASS_END_OF_TEXT; DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); const EntryT &entry = machine.get_entry (state, klass); @@ -845,41 +913,6 @@ struct StateTableDriver }; -struct ankr; - -struct hb_aat_apply_context_t : - hb_dispatch_context_t -{ - const char *get_name () { return "APPLY"; } - template - 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; - const OT::GDEF *gdef_table; - - /* Unused. For debug tracing only. */ - unsigned int lookup_index; - - 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 (&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 */ diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-layout-kerx-table.hh b/third_party/harfbuzz-ng/src/src/hb-aat-layout-kerx-table.hh index 995492cd5a70..35d7c84c2bcb 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-layout-kerx-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-aat-layout-kerx-table.hh @@ -350,7 +350,7 @@ struct KerxSubTableFormat1 driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->font->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (true); } @@ -594,7 +594,7 @@ struct KerxSubTableFormat4 driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->font->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (true); } @@ -869,6 +869,8 @@ struct KerxTable bool apply (AAT::hb_aat_apply_context_t *c) const { + c->buffer->unsafe_to_concat (); + typedef typename T::SubTable SubTable; bool ret = false; @@ -889,7 +891,7 @@ struct KerxTable reverse = bool (st->u.header.coverage & st->u.header.Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index)) goto skip; if (!seenCrossStream && @@ -921,7 +923,7 @@ struct KerxTable if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index); skip: st = &StructAfter (*st); diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-layout-morx-table.hh b/third_party/harfbuzz-ng/src/src/hb-aat-layout-morx-table.hh index aa4ad4cf3c19..f41ecc197fb8 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-layout-morx-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-aat-layout-morx-table.hh @@ -131,14 +131,14 @@ struct RearrangementSubtable hb_glyph_info_t *info = buffer->info; hb_glyph_info_t buf[4]; - memcpy (buf, info + start, l * sizeof (buf[0])); - memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); + hb_memcpy (buf, info + start, l * sizeof (buf[0])); + hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); if (l != r) memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0])); - memcpy (info + start, buf + 2, r * sizeof (buf[0])); - memcpy (info + end - l, buf, l * sizeof (buf[0])); + hb_memcpy (info + start, buf + 2, r * sizeof (buf[0])); + hb_memcpy (info + end - l, buf, l * sizeof (buf[0])); if (reverse_l) { buf[0] = info[end - 1]; @@ -169,7 +169,7 @@ struct RearrangementSubtable driver_context_t dc (this); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -325,7 +325,7 @@ struct ContextualSubtable driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -525,7 +525,7 @@ struct LigatureSubtable if (unlikely (!componentData.sanitize (&c->sanitizer))) break; ligature_idx += componentData; - DEBUG_MSG (APPLY, nullptr, "Action store %u last %u", + DEBUG_MSG (APPLY, nullptr, "Action store %d last %d", bool (action & LigActionStore), bool (action & LigActionLast)); if (action & (LigActionStore | LigActionLast)) @@ -577,7 +577,7 @@ struct LigatureSubtable driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -618,8 +618,27 @@ struct NoncontextualSubtable hb_glyph_info_t *info = c->buffer->info; unsigned int count = c->buffer->len; + // If there's only one range, we already checked the flag. + auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr; for (unsigned int i = 0; i < count; i++) { + /* This block copied from StateTableDriver::drive. Keep in sync. */ + if (last_range) + { + auto *range = last_range; + { + unsigned cluster = info[i].cluster; + while (cluster < range->cluster_first) + range--; + while (cluster > range->cluster_last) + range++; + + last_range = range; + } + if (!(range->flags & c->subtable_flags)) + continue; + } + const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement) { @@ -820,7 +839,7 @@ struct InsertionSubtable driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -968,7 +987,7 @@ struct Chain // Check whether this type/setting pair was requested in the map, and if so, apply its flags. // (The search here only looks at the type and setting fields of feature_info_t.) hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; - if (map->features.bsearch (info)) + if (map->current_features.bsearch (info)) { flags &= feature.disableFlags; flags |= feature.enableFlags; @@ -994,8 +1013,7 @@ struct Chain return flags; } - void apply (hb_aat_apply_context_t *c, - hb_mask_t flags) const + void apply (hb_aat_apply_context_t *c) const { const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount)); unsigned int count = subtableCount; @@ -1003,8 +1021,10 @@ struct Chain { bool reverse; - if (!(subtable->subFeatureFlags & flags)) + if (hb_none (hb_iter (c->range_flags) | + hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) goto skip; + c->subtable_flags = subtable->subFeatureFlags; if (!(subtable->get_coverage() & ChainSubtable::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != @@ -1043,7 +1063,7 @@ struct Chain bool (subtable->get_coverage () & ChainSubtable::Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) goto skip; if (reverse) @@ -1054,7 +1074,7 @@ struct Chain if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index); if (unlikely (!c->buffer->successful)) return; @@ -1120,22 +1140,31 @@ struct mortmorx { const Chain *chain = &firstChain; unsigned int count = chainCount; + if (unlikely (!map->chain_flags.resize (count))) + return; for (unsigned int i = 0; i < count; i++) { - map->chain_flags.push (chain->compile_flags (mapper)); + map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper), + mapper->range_first, + mapper->range_last}); chain = &StructAfter> (*chain); } } - void apply (hb_aat_apply_context_t *c) const + void apply (hb_aat_apply_context_t *c, + const hb_aat_map_t &map) const { if (unlikely (!c->buffer->successful)) return; + + c->buffer->unsafe_to_concat (); + c->set_lookup_index (0); const Chain *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { - chain->apply (c, c->plan->aat_map.chain_flags[i]); + c->range_flags = &map.chain_flags[i]; + chain->apply (c); if (unlikely (!c->buffer->successful)) return; chain = &StructAfter> (*chain); } diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-layout.cc b/third_party/harfbuzz-ng/src/src/hb-aat-layout.cc index d60126fe19ad..c9147ff73b18 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-layout.cc +++ b/third_party/harfbuzz-ng/src/src/hb-aat-layout.cc @@ -244,15 +244,23 @@ hb_aat_layout_has_substitution (hb_face_t *face) void hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer) + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned num_features) { + hb_aat_map_builder_t builder (font->face, plan->props); + for (unsigned i = 0; i < num_features; i++) + builder.add_feature (features[i]); + hb_aat_map_t map; + builder.compile (map); + hb_blob_t *morx_blob = font->face->table.morx.get_blob (); const AAT::morx& morx = *morx_blob->as (); if (morx.has_data ()) { AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); if (!buffer->message (font, "start table morx")) return; - morx.apply (&c); + morx.apply (&c, map); (void) buffer->message (font, "end table morx"); return; } @@ -263,7 +271,7 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, { AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); if (!buffer->message (font, "start table mort")) return; - mort.apply (&c); + mort.apply (&c, map); (void) buffer->message (font, "end table mort"); return; } @@ -289,7 +297,7 @@ is_deleted_glyph (const hb_glyph_info_t *info) void hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) { - hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph); + buffer->delete_glyphs_inplace (is_deleted_glyph); } /** diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-layout.hh b/third_party/harfbuzz-ng/src/src/hb-aat-layout.hh index 5e4e3bda1545..15c382aa92dd 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-layout.hh +++ b/third_party/harfbuzz-ng/src/src/hb-aat-layout.hh @@ -53,7 +53,9 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, HB_INTERNAL void hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer); + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned num_features); HB_INTERNAL void hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer); diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-map.cc b/third_party/harfbuzz-ng/src/src/hb-aat-map.cc index 2c38c3502968..5bdb8004f2f8 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-map.cc +++ b/third_party/harfbuzz-ng/src/src/hb-aat-map.cc @@ -36,27 +36,29 @@ #include "hb-aat-layout-feat-table.hh" -void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) +void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature) { if (!face->table.feat->has_data ()) return; - if (tag == HB_TAG ('a','a','l','t')) + if (feature.tag == HB_TAG ('a','a','l','t')) { if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES)) return; - feature_info_t *info = features.push(); - info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; - info->setting = (hb_aat_layout_feature_selector_t) value; - info->seq = features.length; - info->is_exclusive = true; + feature_range_t *range = features.push(); + range->start = feature.start; + range->end = feature.end; + range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; + range->info.setting = (hb_aat_layout_feature_selector_t) feature.value; + range->info.seq = features.length; + range->info.is_exclusive = true; return; } - const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); + const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag); if (!mapping) return; - const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType); - if (!feature->has_data ()) + const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType); + if (!feature_name->has_data ()) { /* Special case: Chain::compile_flags will fall back to the deprecated version of * small-caps if necessary, so we need to check for that possibility. @@ -64,38 +66,106 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE && mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) { - feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); - if (!feature->has_data ()) return; + feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); + if (!feature_name->has_data ()) return; } else return; } - feature_info_t *info = features.push(); - info->type = mapping->aatFeatureType; - info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; - info->seq = features.length; - info->is_exclusive = feature->is_exclusive (); + feature_range_t *range = features.push(); + range->start = feature.start; + range->end = feature.end; + range->info.type = mapping->aatFeatureType; + range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable; + range->info.seq = features.length; + range->info.is_exclusive = feature_name->is_exclusive (); } void hb_aat_map_builder_t::compile (hb_aat_map_t &m) { - /* Sort features and merge duplicates */ - if (features.length) + /* Compute active features per range, and compile each. */ + + /* Sort features by start/end events. */ + hb_vector_t feature_events; + for (unsigned int i = 0; i < features.length; i++) + { + auto &feature = features[i]; + + if (features[i].start == features[i].end) + continue; + + feature_event_t *event; + + event = feature_events.push (); + event->index = features[i].start; + event->start = true; + event->feature = feature.info; + + event = feature_events.push (); + event->index = features[i].end; + event->start = false; + event->feature = feature.info; + } + feature_events.qsort (); + /* Add a strategic final event. */ + { + feature_info_t feature; + feature.seq = features.length + 1; + + feature_event_t *event = feature_events.push (); + event->index = -1; /* This value does magic. */ + event->start = false; + event->feature = feature; + } + + /* Scan events and save features for each range. */ + hb_sorted_vector_t active_features; + unsigned int last_index = 0; + for (unsigned int i = 0; i < feature_events.length; i++) { - features.qsort (); - unsigned int j = 0; - for (unsigned int i = 1; i < features.length; i++) - if (features[i].type != features[j].type || - /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off - * respectively, so we mask out the low-order bit when checking for "duplicates" - * (selectors referring to the same feature setting) here. */ - (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1)))) - features[++j] = features[i]; - features.shrink (j + 1); + feature_event_t *event = &feature_events[i]; + + if (event->index != last_index) + { + /* Save a snapshot of active features and the range. */ + + /* Sort features and merge duplicates */ + current_features = active_features; + range_first = last_index; + range_last = event->index - 1; + if (current_features.length) + { + current_features.qsort (); + unsigned int j = 0; + for (unsigned int i = 1; i < current_features.length; i++) + if (current_features[i].type != current_features[j].type || + /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off + * respectively, so we mask out the low-order bit when checking for "duplicates" + * (selectors referring to the same feature setting) here. */ + (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1)))) + current_features[++j] = current_features[i]; + current_features.shrink (j + 1); + } + + hb_aat_layout_compile_map (this, &m); + + last_index = event->index; + } + + if (event->start) + { + active_features.push (event->feature); + } else { + feature_info_t *feature = active_features.lsearch (event->feature); + if (feature) + active_features.remove_ordered (feature - active_features.arrayZ); + } } - hb_aat_layout_compile_map (this, &m); + for (auto &chain_flags : m.chain_flags) + // With our above setup this value is one less than desired; adjust it. + chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END; } diff --git a/third_party/harfbuzz-ng/src/src/hb-aat-map.hh b/third_party/harfbuzz-ng/src/src/hb-aat-map.hh index c914f58d707a..cb22ffee42d2 100644 --- a/third_party/harfbuzz-ng/src/src/hb-aat-map.hh +++ b/third_party/harfbuzz-ng/src/src/hb-aat-map.hh @@ -35,16 +35,15 @@ struct hb_aat_map_t friend struct hb_aat_map_builder_t; public: - - void init () + struct range_flags_t { - memset (this, 0, sizeof (*this)); - chain_flags.init (); - } - void fini () { chain_flags.fini (); } + hb_mask_t flags; + unsigned cluster_first; + unsigned cluster_last; // end - 1 + }; public: - hb_vector_t chain_flags; + hb_vector_t> chain_flags; }; struct hb_aat_map_builder_t @@ -56,7 +55,7 @@ struct hb_aat_map_builder_t face (face_), props (props_) {} - HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); + HB_INTERNAL void add_feature (const hb_feature_t &feature); HB_INTERNAL void compile (hb_aat_map_t &m); @@ -78,7 +77,7 @@ struct hb_aat_map_builder_t return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); } - /* compares type & setting only, not is_exclusive flag or seq number */ + /* compares type & setting only */ int cmp (const feature_info_t& f) const { return (f.type != type) ? (f.type < type ? -1 : 1) : @@ -86,12 +85,38 @@ struct hb_aat_map_builder_t } }; + struct feature_range_t + { + feature_info_t info; + unsigned start; + unsigned end; + }; + + private: + struct feature_event_t + { + unsigned int index; + bool start; + feature_info_t feature; + + 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 : + a->start < b->start ? -1 : a->start > b->start ? 1 : + feature_info_t::cmp (&a->feature, &b->feature); + } + }; + public: hb_face_t *face; hb_segment_properties_t props; public: - hb_sorted_vector_t features; + hb_sorted_vector_t features; + hb_sorted_vector_t current_features; + unsigned range_first = HB_FEATURE_GLOBAL_START; + unsigned range_last = HB_FEATURE_GLOBAL_END; }; diff --git a/third_party/harfbuzz-ng/src/src/hb-algs.hh b/third_party/harfbuzz-ng/src/src/hb-algs.hh index cc37c073da12..13587eac0178 100644 --- a/third_party/harfbuzz-ng/src/src/hb-algs.hh +++ b/third_party/harfbuzz-ng/src/src/hb-algs.hh @@ -110,9 +110,10 @@ struct BEInt constexpr operator Type () const { #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + (__BYTE_ORDER == __BIG_ENDIAN || \ + (__BYTE_ORDER == __LITTLE_ENDIAN && \ + hb_has_builtin(__builtin_bswap16))) /* Spoon-feed the compiler a big-endian integer with alignment 1. * https://github.com/harfbuzz/harfbuzz/pull/1398 */ #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -155,9 +156,10 @@ struct BEInt struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; constexpr operator Type () const { #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ - ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + (__BYTE_ORDER == __BIG_ENDIAN || \ + (__BYTE_ORDER == __LITTLE_ENDIAN && \ + hb_has_builtin(__builtin_bswap32))) /* Spoon-feed the compiler a big-endian integer with alignment 1. * https://github.com/harfbuzz/harfbuzz/pull/1398 */ #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -236,17 +238,6 @@ struct template constexpr auto impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) - template constexpr uint32_t - impl (const hb::shared_ptr& v, hb_priority<1>) const - { - return v.get () ? v.get ()->hash () : 0; - } - template constexpr uint32_t - impl (const hb::unique_ptr& v, hb_priority<1>) const - { - return v.get () ? v.get ()->hash () : 0; - } - template constexpr auto impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash>{} (hb_deref (v))) @@ -495,6 +486,17 @@ struct } HB_FUNCOBJ (hb_equal); +struct +{ + template void + operator () (T& a, T& b) const + { + using std::swap; // allow ADL + swap (a, b); + } +} +HB_FUNCOBJ (hb_swap); + template struct hb_pair_t @@ -507,7 +509,7 @@ struct hb_pair_t hb_enable_if (std::is_default_constructible::value && std::is_default_constructible::value)> hb_pair_t () : first (), second () {} - hb_pair_t (T1 a, T2 b) : first (a), second (b) {} + hb_pair_t (T1 a, T2 b) : first (std::forward (a)), second (std::forward (b)) {} template (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); } bool operator <= (const pair_t& o) const { return !(*this > o); } + static int cmp (const void *pa, const void *pb) + { + pair_t *a = (pair_t *) pa; + pair_t *b = (pair_t *) pb; + + if (a->first < b->first) return -1; + if (a->first > b->first) return +1; + if (a->second < b->second) return -1; + if (a->second > b->second) return +1; + return 0; + } + + friend void swap (hb_pair_t& a, hb_pair_t& b) + { + hb_swap (a.first, b.first); + hb_swap (a.second, b.second); + } + + T1 first; T2 second; }; @@ -570,17 +591,6 @@ struct } HB_FUNCOBJ (hb_clamp); -struct -{ - template void - operator () (T& a, T& b) const - { - using std::swap; // allow ADL - swap (a, b); - } -} -HB_FUNCOBJ (hb_swap); - /* * Bithacks. */ @@ -590,13 +600,17 @@ template static inline unsigned int hb_popcount (T v) { -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +#if hb_has_builtin(__builtin_popcount) if (sizeof (T) <= sizeof (unsigned int)) return __builtin_popcount (v); +#endif +#if hb_has_builtin(__builtin_popcountl) if (sizeof (T) <= sizeof (unsigned long)) return __builtin_popcountl (v); +#endif +#if hb_has_builtin(__builtin_popcountll) if (sizeof (T) <= sizeof (unsigned long long)) return __builtin_popcountll (v); #endif @@ -633,13 +647,17 @@ hb_bit_storage (T v) { if (unlikely (!v)) return 0; -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +#if hb_has_builtin(__builtin_clz) if (sizeof (T) <= sizeof (unsigned int)) return sizeof (unsigned int) * 8 - __builtin_clz (v); +#endif +#if hb_has_builtin(__builtin_clzl) if (sizeof (T) <= sizeof (unsigned long)) return sizeof (unsigned long) * 8 - __builtin_clzl (v); +#endif +#if hb_has_builtin(__builtin_clzll) if (sizeof (T) <= sizeof (unsigned long long)) return sizeof (unsigned long long) * 8 - __builtin_clzll (v); #endif @@ -707,13 +725,17 @@ hb_ctz (T v) { if (unlikely (!v)) return 8 * sizeof (T); -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) +#if hb_has_builtin(__builtin_ctz) if (sizeof (T) <= sizeof (unsigned int)) return __builtin_ctz (v); +#endif +#if hb_has_builtin(__builtin_ctzl) if (sizeof (T) <= sizeof (unsigned long)) return __builtin_ctzl (v); +#endif +#if hb_has_builtin(__builtin_ctzll) if (sizeof (T) <= sizeof (unsigned long long)) return __builtin_ctzll (v); #endif @@ -849,19 +871,14 @@ hb_in_range (T u, T lo, T hi) return (T)(u - lo) <= (T)(hi - lo); } template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) +hb_in_ranges (T u, T lo1, T hi1) { - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); + return hb_in_range (u, lo1, hi1); } -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); -} -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) +template static inline bool +hb_in_ranges (T u, T lo1, T hi1, Ts... ds) { - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4); + return hb_in_range (u, lo1, hi1) || hb_in_ranges (u, ds...); } @@ -869,10 +886,18 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) * Overflow checking. */ -/* Consider __builtin_mul_overflow use here also */ static inline bool -hb_unsigned_mul_overflows (unsigned int count, unsigned int size) +hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr) { +#if hb_has_builtin(__builtin_mul_overflow) + unsigned stack_result; + if (!result) + result = &stack_result; + return __builtin_mul_overflow (count, size, result); +#endif + + if (result) + *result = count * size; return (size > 0) && (count >= ((unsigned int) -1) / size); } @@ -1164,9 +1189,12 @@ hb_qsort (void *base, size_t nel, size_t width, } -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2) +template static inline void +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr) { + static_assert (hb_is_trivially_copy_assignable (T), ""); + static_assert (hb_is_trivially_copy_assignable (T3), ""); + for (unsigned int i = 1; i < len; i++) { unsigned int j = i; @@ -1189,12 +1217,6 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *) } } -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) -{ - hb_stable_sort (array, len, compar, (int *) nullptr); -} - static inline hb_bool_t hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) { @@ -1322,47 +1344,62 @@ struct HB_FUNCOBJ (hb_dec); -/* Compiler-assisted vectorization. */ - -/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), - * basically a fixed-size bitset. */ -template -struct hb_vector_size_t +/* Adapted from kurbo implementation with extra parameters added, + * and finding for a particular range instead of 0. + * + * For documentation and implementation see: + * + * [ITP method]: https://en.wikipedia.org/wiki/ITP_Method + * [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597 + * https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html + * https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248 + */ +template +double solve_itp (func_t f, + double a, double b, + double epsilon, + double min_y, double max_y, + double &ya, double &yb, double &y) { - elt_t& operator [] (unsigned int i) { return v[i]; } - const elt_t& operator [] (unsigned int i) const { return v[i]; } - - void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); } - - template - hb_vector_size_t process (const Op& op) const + unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0)); + const unsigned n0 = 1; // Hardwired + const double k1 = 0.2 / (b - a); // Hardwired. + unsigned nmax = n0 + n1_2; + double scaled_epsilon = epsilon * double (1llu << nmax); + double _2_epsilon = 2.0 * epsilon; + while (b - a > _2_epsilon) { - hb_vector_size_t r; - for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) - r.v[i] = op (v[i]); - return r; - } - template - hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const - { - hb_vector_size_t r; - for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) - r.v[i] = op (v[i], o.v[i]); - return r; + double x1_2 = 0.5 * (a + b); + double r = scaled_epsilon - 0.5 * (b - a); + double xf = (yb * a - ya * b) / (yb - ya); + double sigma = x1_2 - xf; + double b_a = b - a; + // This has k2 = 2 hardwired for efficiency. + double b_a_k2 = b_a * b_a; + double delta = k1 * b_a_k2; + int sigma_sign = sigma >= 0 ? +1 : -1; + double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2; + double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign; + double yitp = f (xitp); + if (yitp > max_y) + { + b = xitp; + yb = yitp; + } + else if (yitp < min_y) + { + a = xitp; + ya = yitp; + } + else + { + y = yitp; + return xitp; + } + scaled_epsilon *= 0.5; } - hb_vector_size_t operator | (const hb_vector_size_t &o) const - { return process (hb_bitwise_or, o); } - hb_vector_size_t operator & (const hb_vector_size_t &o) const - { return process (hb_bitwise_and, o); } - hb_vector_size_t operator ^ (const hb_vector_size_t &o) const - { return process (hb_bitwise_xor, o); } - hb_vector_size_t operator ~ () const - { return process (hb_bitwise_neg); } - - private: - static_assert (0 == byte_size % sizeof (elt_t), ""); - elt_t v[byte_size / sizeof (elt_t)]; -}; + return 0.5 * (a + b); +} #endif /* HB_ALGS_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-array.hh b/third_party/harfbuzz-ng/src/src/hb-array.hh index 5884007c1987..e82c081535e4 100644 --- a/third_party/harfbuzz-ng/src/src/hb-array.hh +++ b/third_party/harfbuzz-ng/src/src/hb-array.hh @@ -100,10 +100,18 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> /* 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 and length. */ + * for range-based for loop and just compare arrayZ and length. + * + * The above comment is outdated now because we implemented separate begin/end to + * objects that were using hb_array_t for range-based loop before. */ bool operator != (const hb_array_t& o) const { return this->arrayZ != o.arrayZ || this->length != o.length; } + /* Faster range-based for loop without bounds-check. */ + Type *begin () const { return arrayZ; } + Type *end () const { return arrayZ + length; } + + /* Extra operators. */ Type * operator & () const { return arrayZ; } @@ -112,11 +120,11 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> HB_INTERNAL bool operator == (const hb_array_t &o) const; - uint32_t hash () 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]); - } + for (auto &v : *this) + current = current * 31 + hb_hash (v); return current; } @@ -184,23 +192,18 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*)) { + //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) hb_qsort (arrayZ, length, this->get_item_size (), cmp_); return hb_sorted_array_t (*this); } hb_sorted_array_t qsort () { + //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp); return hb_sorted_array_t (*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. @@ -262,17 +265,31 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> void fini () { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; } - template + template )))> 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 ()); + if (unlikely (!c->extend_size (out, get_size (), false))) 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 ))> + 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 (), false))) return_trace (hb_array_t ()); + hb_memcpy (out, arrayZ, get_size ()); + return_trace (hb_array_t (out, length)); + } + template bool sanitize (hb_sanitize_context_t *c) const { return c->check_array (arrayZ, length); } @@ -287,6 +304,9 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> unsigned int backwards_length = 0; }; template inline hb_array_t +hb_array () +{ return hb_array_t (); } +template inline hb_array_t hb_array (T *array, unsigned int length) { return hb_array_t (array, length); } template inline hb_array_t @@ -295,8 +315,8 @@ hb_array (T (&array_)[length_]) template struct hb_sorted_array_t : - hb_iter_t, Type&>, - hb_array_t + hb_array_t, + hb_iter_t, Type&> { typedef hb_iter_t iter_base_t; HB_ITER_USING (iter_base_t); @@ -316,8 +336,8 @@ struct hb_sorted_array_t : template constexpr hb_sorted_array_t (const hb_array_t &o) : - hb_iter_t (), - hb_array_t (o) {} + hb_array_t (o), + hb_iter_t () {} template hb_sorted_array_t& operator = (const hb_array_t &o) @@ -329,6 +349,11 @@ struct hb_sorted_array_t : bool operator != (const hb_sorted_array_t& o) const { return this->arrayZ != o.arrayZ || this->length != o.length; } + /* Faster range-based for loop without bounds-check. */ + Type *begin () const { return this->arrayZ; } + Type *end () const { return this->arrayZ + this->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 *) (this))->sub_array (start_offset, seg_count)); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const @@ -421,18 +446,42 @@ inline bool hb_array_t::operator == (const hb_array_t -inline uint32_t hb_array_t::hash () const { +inline uint32_t hb_array_t::hash () const +{ uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) - current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); + unsigned i = 0; + +#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ + ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + for (; i + 4 <= this->length; i += 4) + current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v); +#endif + + for (; i < this->length; i++) + current = current * 31 + hb_hash (this->arrayZ[i]); return current; } + template <> -inline uint32_t hb_array_t::hash () const { +inline uint32_t hb_array_t::hash () const +{ uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) - current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); + unsigned i = 0; + +#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ + ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + for (; i + 4 <= this->length; i += 4) + current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v); +#endif + + for (; i < this->length; i++) + current = current * 31 + hb_hash (this->arrayZ[i]); return current; } diff --git a/third_party/harfbuzz-ng/src/src/hb-atomic.hh b/third_party/harfbuzz-ng/src/src/hb-atomic.hh index 14c6fb3264eb..a6283de1408a 100644 --- a/third_party/harfbuzz-ng/src/src/hb-atomic.hh +++ b/third_party/harfbuzz-ng/src/src/hb-atomic.hh @@ -84,11 +84,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #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 *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) -#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_relaxed)) -#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_release)) -#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast const *> (AI)->load (std::memory_order_relaxed)) -#define hb_atomic_int_impl_get(AI) (reinterpret_cast const *> (AI)->load (std::memory_order_acquire)) +#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) +#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release)) +#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_int_impl_get(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_acquire)) #define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast const *> (P)->load (std::memory_order_relaxed)) @@ -111,10 +111,15 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #endif +/* This should never be disabled, even under HB_NO_MT. + * except that MSVC gives me an internal compiler error, so disabled there. + * + * https://github.com/harfbuzz/harfbuzz/pull/4119 + */ #ifndef _hb_compiler_memory_r_barrier -/* This we always use std::atomic for; and should never be disabled... - * except that MSVC gives me an internal compiler error on it. */ -#if !defined(_MSC_VER) +#if defined(__ATOMIC_ACQUIRE) // gcc-like +#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory") +#elif !defined(_MSC_VER) #include #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire) #else @@ -145,15 +150,35 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #endif #ifndef hb_atomic_int_impl_set inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } +inline void hb_atomic_int_impl_set (short *AI, short 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; } +inline short hb_atomic_int_impl_get (const short *AI) { short 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 +struct hb_atomic_short_t +{ + hb_atomic_short_t () = default; + constexpr hb_atomic_short_t (short v) : v (v) {} + + hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; } + operator short () const { return get_relaxed (); } + + void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } + void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); } + short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } + short get_acquire () const { return hb_atomic_int_impl_get (&v); } + short inc () { return hb_atomic_int_impl_add (&v, 1); } + short dec () { return hb_atomic_int_impl_add (&v, -1); } + + short v = 0; +}; + struct hb_atomic_int_t { hb_atomic_int_t () = default; diff --git a/third_party/harfbuzz-ng/src/src/hb-bimap.hh b/third_party/harfbuzz-ng/src/src/hb-bimap.hh index 8e8c988716d6..9edefd971065 100644 --- a/third_party/harfbuzz-ng/src/src/hb-bimap.hh +++ b/third_party/harfbuzz-ng/src/src/hb-bimap.hh @@ -83,9 +83,15 @@ struct hb_bimap_t unsigned int get_population () const { return forw_map.get_population (); } + protected: hb_map_t forw_map; hb_map_t back_map; + + public: + auto keys () const HB_AUTO_RETURN (+ forw_map.keys()) + auto values () const HB_AUTO_RETURN (+ forw_map.values()) + auto iter () const HB_AUTO_RETURN (+ forw_map.iter()) }; /* Inremental bimap: only lhs is given, rhs is incrementally assigned */ @@ -108,6 +114,9 @@ struct hb_inc_bimap_t : hb_bimap_t hb_codepoint_t skip () { return next_value++; } + hb_codepoint_t skip (unsigned count) + { return next_value += count; } + hb_codepoint_t get_next_value () const { return next_value; } diff --git a/third_party/harfbuzz-ng/src/src/hb-bit-page.hh b/third_party/harfbuzz-ng/src/src/hb-bit-page.hh index 95ae1b7bf986..9b027ac59054 100644 --- a/third_party/harfbuzz-ng/src/src/hb-bit-page.hh +++ b/third_party/harfbuzz-ng/src/src/hb-bit-page.hh @@ -30,27 +30,84 @@ #include "hb.hh" + +/* Compiler-assisted vectorization. */ + +/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), + * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot + * guarantee alignment requirements. */ +template +struct hb_vector_size_t +{ + elt_t& operator [] (unsigned int i) { return v[i]; } + const elt_t& operator [] (unsigned int i) const { return v[i]; } + + void init0 () + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + v[i] = 0; + } + void init1 () + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + v[i] = (elt_t) -1; + } + + template + hb_vector_size_t process (const Op& op) const + { + hb_vector_size_t r; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r.v[i] = op (v[i]); + return r; + } + template + hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const + { + hb_vector_size_t r; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r.v[i] = op (v[i], o.v[i]); + return r; + } + hb_vector_size_t operator | (const hb_vector_size_t &o) const + { return process (hb_bitwise_or, o); } + hb_vector_size_t operator & (const hb_vector_size_t &o) const + { return process (hb_bitwise_and, o); } + hb_vector_size_t operator ^ (const hb_vector_size_t &o) const + { return process (hb_bitwise_xor, o); } + hb_vector_size_t operator ~ () const + { return process (hb_bitwise_neg); } + + hb_array_t iter () const + { return hb_array (v); } + + private: + static_assert (0 == byte_size % sizeof (elt_t), ""); + elt_t v[byte_size / sizeof (elt_t)]; +}; + + struct hb_bit_page_t { - void init0 () { v.clear (); } - void init1 () { v.clear (0xFF); } + void init0 () { v.init0 (); } + void init1 () { v.init1 (); } - constexpr unsigned len () const + static inline constexpr unsigned len () { return ARRAY_LENGTH_CONST (v); } bool is_empty () const { - for (unsigned i = 0; i < len (); i++) - if (v[i]) - return false; - return true; + return + + hb_iter (v) + | hb_none + ; } uint32_t hash () const { - uint32_t h = 0; - for (unsigned i = 0; i < len (); i++) - h = h * 31 + hb_hash (v[i]); - return h; + return + + hb_iter (v) + | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u) + ; } void add (hb_codepoint_t g) { elt (g) |= mask (g); } @@ -69,7 +126,7 @@ struct hb_bit_page_t *la |= ~(mask (a) - 1); la++; - memset (la, 0xff, (char *) lb - (char *) la); + hb_memset (la, 0xff, (char *) lb - (char *) la); *lb |= ((mask (b) << 1) - 1); } @@ -85,7 +142,7 @@ struct hb_bit_page_t *la &= mask (a) - 1; la++; - memset (la, 0, (char *) lb - (char *) la); + hb_memset (la, 0, (char *) lb - (char *) la); *lb &= ~((mask (b) << 1) - 1); } @@ -101,13 +158,13 @@ struct hb_bit_page_t hb_codepoint_t *p, unsigned int size) const { - unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_v = start_value / ELT_BITS; unsigned int start_bit = start_value & ELT_MASK; unsigned int count = 0; for (unsigned i = start_v; i < len () && count < size; i++) { elt_t bits = v[i]; - uint32_t v_base = base | (i << ELT_BITS_LOG_2); + uint32_t v_base = base | (i * ELT_BITS); for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) { if ((elt_t(1) << j) & bits) { @@ -132,13 +189,13 @@ struct hb_bit_page_t unsigned int size, hb_codepoint_t *next_value) const { - unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_v = start_value / ELT_BITS; unsigned int start_bit = start_value & ELT_MASK; unsigned int count = 0; for (unsigned i = start_v; i < len () && count < size; i++) { elt_t bits = v[i]; - uint32_t v_offset = i << ELT_BITS_LOG_2; + uint32_t v_offset = i * ELT_BITS; for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) { if ((elt_t(1) << j) & bits) @@ -161,7 +218,10 @@ struct hb_bit_page_t bool is_equal (const hb_bit_page_t &other) const { - return 0 == hb_memcmp (&v, &other.v, sizeof (v)); + for (unsigned i = 0; i < len (); i++) + if (v[i] != other.v[i]) + return false; + return true; } bool is_subset (const hb_bit_page_t &larger_page) const { @@ -173,10 +233,10 @@ struct hb_bit_page_t unsigned int get_population () const { - unsigned int pop = 0; - for (unsigned int i = 0; i < len (); i++) - pop += hb_popcount (v[i]); - return pop; + return + + hb_iter (v) + | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u) + ; } bool next (hb_codepoint_t *codepoint) const @@ -250,10 +310,10 @@ struct hb_bit_page_t static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; typedef unsigned long long elt_t; - static constexpr unsigned PAGE_BITS = 512; - static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); - static constexpr unsigned PAGE_BITS_LOG_2 = 9; + static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits + static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2; static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, ""); + static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1; static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } @@ -262,8 +322,6 @@ struct hb_bit_page_t typedef hb_vector_size_t vector_t; static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8; - static constexpr unsigned ELT_BITS_LOG_2 = 6; - static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, ""); static constexpr unsigned ELT_MASK = ELT_BITS - 1; static constexpr unsigned BITS = sizeof (vector_t) * 8; diff --git a/third_party/harfbuzz-ng/src/src/hb-bit-set-invertible.hh b/third_party/harfbuzz-ng/src/src/hb-bit-set-invertible.hh index 27fb0732eabd..1eb1b1c20920 100644 --- a/third_party/harfbuzz-ng/src/src/hb-bit-set-invertible.hh +++ b/third_party/harfbuzz-ng/src/src/hb-bit-set-invertible.hh @@ -74,6 +74,11 @@ struct hb_bit_set_invertible_t inverted = !inverted; } + bool is_inverted () const + { + return inverted; + } + bool is_empty () const { hb_codepoint_t v = INVALID; @@ -123,10 +128,8 @@ struct hb_bit_set_invertible_t bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; } /* Has interface. */ - static constexpr bool SENTINEL = false; - typedef bool value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + bool operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k]; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } diff --git a/third_party/harfbuzz-ng/src/src/hb-bit-set.hh b/third_party/harfbuzz-ng/src/src/hb-bit-set.hh index a63887efda76..c30b2af7b0d9 100644 --- a/third_party/harfbuzz-ng/src/src/hb-bit-set.hh +++ b/third_party/harfbuzz-ng/src/src/hb-bit-set.hh @@ -38,7 +38,7 @@ struct hb_bit_set_t hb_bit_set_t () = default; ~hb_bit_set_t () = default; - hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); } + hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); } hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); } hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; } hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; } @@ -85,12 +85,16 @@ struct hb_bit_set_t void err () { if (successful) successful = false; } /* TODO Remove */ bool in_error () const { return !successful; } - bool resize (unsigned int count) + bool resize (unsigned int count, bool clear = true, bool exact_size = false) { if (unlikely (!successful)) return false; - if (unlikely (!pages.resize (count) || !page_map.resize (count))) + + if (pages.length == 0 && count == 1) + exact_size = true; // Most sets are small and local + + if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size))) { - pages.resize (page_map.length); + pages.resize (page_map.length, clear, exact_size); successful = false; return false; } @@ -190,7 +194,7 @@ struct hb_bit_set_t unsigned int end = major_start (m + 1); do { - if (v || page) /* The v check is to optimize out the page check if v is true. */ + if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ page->set (g, v); array = &StructAtOffsetUnaligned (array, stride); @@ -234,7 +238,7 @@ struct hb_bit_set_t if (g < last_g) return false; last_g = g; - if (v || page) /* The v check is to optimize out the page check if v is true. */ + if (g != INVALID && (v || page)) /* The v check is to optimize out the page check if v is true. */ page->add (g); array = &StructAtOffsetUnaligned (array, stride); @@ -330,10 +334,8 @@ struct hb_bit_set_t } /* Has interface. */ - static constexpr bool SENTINEL = false; - typedef bool value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + bool operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k]; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } @@ -348,11 +350,11 @@ struct hb_bit_set_t hb_codepoint_t c = first - 1; return next (&c) && c <= last; } - void set (const hb_bit_set_t &other) + void set (const hb_bit_set_t &other, bool exact_size = false) { if (unlikely (!successful)) return; unsigned int count = other.pages.length; - if (unlikely (!resize (count))) + if (unlikely (!resize (count, false, exact_size))) return; population = other.population; @@ -391,7 +393,7 @@ struct hb_bit_set_t bool is_subset (const hb_bit_set_t &larger_set) const { if (has_population () && larger_set.has_population () && - population != larger_set.population) + population > larger_set.population) return false; uint32_t spi = 0; @@ -424,7 +426,7 @@ struct hb_bit_set_t private: bool allocate_compact_workspace (hb_vector_t& workspace) { - if (unlikely (!workspace.resize (pages.length))) + if (unlikely (!workspace.resize_exact (pages.length))) { successful = false; return false; @@ -540,21 +542,21 @@ struct hb_bit_set_t b = nb; for (; a && b; ) { - if (page_map[a - 1].major == other.page_map[b - 1].major) + if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major) { a--; b--; count--; - page_map[count] = page_map[a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; page_at (count).v = op (page_at (a).v, other.page_at (b).v); } - else if (page_map[a - 1].major > other.page_map[b - 1].major) + else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major) { a--; if (passthru_left) { count--; - page_map[count] = page_map[a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; } } else @@ -563,8 +565,8 @@ struct hb_bit_set_t if (passthru_right) { count--; - page_map[count].major = other.page_map[b].major; - page_map[count].index = next_page++; + page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; + page_map.arrayZ[count].index = next_page++; page_at (count).v = other.page_at (b).v; } } @@ -574,15 +576,15 @@ struct hb_bit_set_t { a--; count--; - page_map[count] = page_map [a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; } if (passthru_right) while (b) { b--; count--; - page_map[count].major = other.page_map[b].major; - page_map[count].index = next_page++; + page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; + page_map.arrayZ[count].index = next_page++; page_at (count).v = other.page_at (b).v; } assert (!count); @@ -605,8 +607,6 @@ struct hb_bit_set_t bool next (hb_codepoint_t *codepoint) const { - // TODO: this should be merged with prev() as both implementations - // are very similar. if (unlikely (*codepoint == INVALID)) { *codepoint = get_min (); return *codepoint != INVALID; @@ -640,7 +640,7 @@ struct hb_bit_set_t for (; i < page_map.length; i++) { - const page_map_t ¤t = page_map.arrayZ[i]; + const page_map_t ¤t = page_map_array[i]; hb_codepoint_t m = pages_array[current.index].get_min (); if (m != INVALID) { @@ -663,21 +663,21 @@ struct hb_bit_set_t page_map_t map = {get_major (*codepoint), 0}; unsigned int i; page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST); - if (i < page_map.length && page_map[i].major == map.major) + if (i < page_map.length && page_map.arrayZ[i].major == map.major) { - if (pages[page_map[i].index].previous (codepoint)) + if (pages[page_map.arrayZ[i].index].previous (codepoint)) { - *codepoint += page_map[i].major * page_t::PAGE_BITS; + *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS; return true; } } i--; for (; (int) i >= 0; i--) { - hb_codepoint_t m = pages[page_map[i].index].get_max (); + hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max (); if (m != INVALID) { - *codepoint = page_map[i].major * page_t::PAGE_BITS + m; + *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m; return true; } } @@ -905,7 +905,7 @@ struct hb_bit_set_t { auto &cached_page = page_map.arrayZ[i]; if (cached_page.major == major) - return &pages[cached_page.index]; + return &pages.arrayZ[cached_page.index]; } page_map_t map = {major, pages.length}; @@ -917,15 +917,15 @@ struct hb_bit_set_t if (unlikely (!resize (pages.length + 1))) return nullptr; - pages[map.index].init0 (); - memmove (page_map + i + 1, - page_map + i, + pages.arrayZ[map.index].init0 (); + memmove (page_map.arrayZ + i + 1, + page_map.arrayZ + i, (page_map.length - 1 - i) * page_map.item_size); page_map[i] = map; } last_page_lookup = i; - return &pages[page_map[i].index]; + return &pages.arrayZ[page_map.arrayZ[i].index]; } const page_t *page_for (hb_codepoint_t g) const { @@ -939,7 +939,7 @@ struct hb_bit_set_t { auto &cached_page = page_map.arrayZ[i]; if (cached_page.major == major) - return &pages[cached_page.index]; + return &pages.arrayZ[cached_page.index]; } page_map_t key = {major}; @@ -947,10 +947,18 @@ struct hb_bit_set_t return nullptr; last_page_lookup = i; - return &pages[page_map[i].index]; + return &pages.arrayZ[page_map[i].index]; + } + page_t &page_at (unsigned int i) + { + assert (i < page_map.length); + return pages.arrayZ[page_map.arrayZ[i].index]; + } + const page_t &page_at (unsigned int i) const + { + assert (i < page_map.length); + return pages.arrayZ[page_map.arrayZ[i].index]; } - page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } - const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; } unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; } hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; } diff --git a/third_party/harfbuzz-ng/src/src/hb-blob.cc b/third_party/harfbuzz-ng/src/src/hb-blob.cc index 9bc12ea3fa0c..265effba0379 100644 --- a/third_party/harfbuzz-ng/src/src/hb-blob.cc +++ b/third_party/harfbuzz-ng/src/src/hb-blob.cc @@ -495,7 +495,7 @@ hb_blob_t::try_make_writable () DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data); - memcpy (new_data, this->data, this->length); + hb_memcpy (new_data, this->data, this->length); this->destroy_user_data (); this->mode = HB_MEMORY_MODE_WRITABLE; this->data = new_data; @@ -676,7 +676,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); if (unlikely (!wchar_file_name)) goto fail_without_close; mbstowcs (wchar_file_name, file_name, size); -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) { CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); @@ -697,7 +697,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) { LARGE_INTEGER length; GetFileSizeEx (fd, &length); @@ -710,7 +710,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) #endif if (unlikely (!file->mapping)) goto fail; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_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); diff --git a/third_party/harfbuzz-ng/src/src/hb-blob.h b/third_party/harfbuzz-ng/src/src/hb-blob.h index 4eb42314da32..db50067e164f 100644 --- a/third_party/harfbuzz-ng/src/src/hb-blob.h +++ b/third_party/harfbuzz-ng/src/src/hb-blob.h @@ -63,7 +63,7 @@ HB_BEGIN_DECLS * HarfBuzz and doing that just once (no reuse!), * * - If the font is mmap()ed, it's okay to use - * @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode + * @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, however, using that mode * correctly is very tricky. Use @HB_MEMORY_MODE_READONLY instead. **/ typedef enum { diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.hh b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.hh index 87095855d63a..004a9fb8b701 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.hh +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.hh @@ -32,37 +32,37 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-json.hh" +#line 33 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { 0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, - 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, - 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, - 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, - 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, - 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, - 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u, + 48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, + 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, + 9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, + 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, + 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, + 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 123u, 0u, 0u, 0 }; static const char _deserialize_json_key_spans[] = { 0, 115, 26, 21, 2, 1, 50, 49, - 10, 117, 117, 117, 1, 50, 49, 10, - 117, 117, 1, 1, 50, 49, 117, 117, - 2, 1, 50, 49, 10, 117, 117, 1, - 50, 49, 10, 117, 117, 1, 1, 50, - 49, 117, 117, 1, 50, 49, 59, 117, - 59, 117, 117, 1, 50, 49, 117, 85, + 10, 117, 117, 85, 117, 1, 50, 49, + 10, 117, 117, 1, 1, 50, 49, 117, + 117, 2, 1, 50, 49, 10, 117, 117, + 1, 50, 49, 10, 117, 117, 1, 1, + 50, 49, 117, 117, 1, 50, 49, 59, + 117, 59, 117, 117, 1, 50, 49, 117, 115, 0 }; static const short _deserialize_json_index_offsets[] = { 0, 0, 116, 143, 165, 168, 170, 221, - 271, 282, 400, 518, 636, 638, 689, 739, - 750, 868, 986, 988, 990, 1041, 1091, 1209, - 1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, - 1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034, - 2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534, - 2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169, + 271, 282, 400, 518, 604, 722, 724, 775, + 825, 836, 954, 1072, 1074, 1076, 1127, 1177, + 1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648, + 1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118, + 2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560, + 2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137, 3255, 3371 }; @@ -131,57 +131,54 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 24, 1, 20, - 20, 20, 20, 20, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 20, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 21, 1, 1, 1, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19, - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 24, 1, 25, + 25, 25, 25, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 22, 1, 25, 1, 25, - 25, 25, 25, 25, 1, 1, 1, 1, + 1, 1, 1, 27, 1, 20, 20, 20, + 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 25, 1, + 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 26, 1, 26, 26, 26, 26, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 26, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 27, 1, - 1, 28, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 1, 30, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 1, 32, - 32, 32, 32, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 33, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 22, 1, 28, 1, 28, 28, 28, + 28, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 29, 1, + 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 30, 1, 1, 31, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 1, 33, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 1, 35, 35, 35, + 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 34, 1, 32, 32, 32, - 32, 32, 1, 1, 1, 1, 1, 1, + 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 33, 1, 1, 1, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -189,291 +186,294 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 37, 1, 35, 35, 35, 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 34, 1, 35, 1, 36, 1, 36, - 36, 36, 36, 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 36, 1, + 1, 1, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 37, 1, 37, 37, 37, 37, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 38, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 1, 40, 40, 40, 40, - 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 40, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 41, + 1, 1, 1, 1, 1, 1, 1, 37, + 1, 38, 1, 39, 1, 39, 39, 39, + 39, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 40, 1, + 40, 40, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 41, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 1, 43, 43, 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 42, 1, 40, 40, 40, 40, 40, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 40, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 41, 1, 1, - 1, 43, 43, 43, 43, 43, 43, 43, - 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 45, 1, + 43, 43, 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 43, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 44, 1, 1, 1, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 42, 1, - 44, 45, 1, 46, 1, 46, 46, 46, - 46, 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 47, 1, - 47, 47, 47, 47, 47, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 47, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 48, 1, 1, 49, - 50, 50, 50, 50, 50, 50, 50, 50, - 50, 1, 51, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 1, 53, 53, 53, - 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 53, 1, 1, 1, + 1, 1, 1, 1, 45, 1, 47, 48, + 1, 49, 1, 49, 49, 49, 49, 49, 1, 1, 1, 1, 1, 1, 1, 1, - 54, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 49, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 50, 50, + 50, 50, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 51, 1, 1, 52, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 1, + 54, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 1, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 56, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 55, 1, 53, 53, 53, 53, 53, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 53, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 54, 1, - 1, 1, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 58, + 1, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 55, - 1, 56, 1, 56, 56, 56, 56, 56, + 56, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 57, 1, 1, 1, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 57, 1, 57, 57, - 57, 57, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 58, 1, 1, 59, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 1, - 61, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 1, 63, 63, 63, 63, 63, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 58, 1, 59, + 1, 59, 59, 59, 59, 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 63, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 64, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 60, 1, 60, 60, 60, 60, + 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 61, 1, 1, 62, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 1, 64, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 1, 66, 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 66, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 67, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 65, - 1, 63, 63, 63, 63, 63, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 63, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 64, 1, 1, 1, - 62, 62, 62, 62, 62, 62, 62, 62, - 62, 62, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 68, 1, 66, + 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 65, 1, 66, - 1, 67, 1, 67, 67, 67, 67, 67, + 1, 1, 67, 1, 1, 1, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 67, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 68, 1, 68, 68, - 68, 68, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 68, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 69, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 1, - 71, 71, 71, 71, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 72, 1, 1, 1, 1, + 1, 1, 1, 68, 1, 69, 1, 70, + 1, 70, 70, 70, 70, 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 71, 1, 71, 71, 71, 71, + 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 72, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 1, 74, 74, + 74, 74, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 73, 1, 71, 71, - 71, 71, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 72, 1, 1, 1, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 76, 1, 74, 74, 74, 74, + 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 74, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 75, + 1, 1, 1, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 73, 1, 75, 1, 75, 75, - 75, 75, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 76, - 1, 76, 76, 76, 76, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 76, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 78, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 1, 81, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 80, 80, 80, - 80, 80, 80, 80, 80, 82, 80, 83, - 83, 83, 83, 83, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 83, 1, + 76, 1, 78, 1, 78, 78, 78, 78, + 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 84, 1, 1, 1, 1, 1, + 1, 1, 1, 78, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 79, 1, 79, + 79, 79, 79, 79, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 79, 1, + 80, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 81, 82, + 82, 82, 82, 82, 82, 82, 82, 82, + 1, 84, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 85, 83, 86, 86, 86, + 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 85, 1, 80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 88, 1, 83, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 80, - 1, 86, 86, 86, 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 86, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 87, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 83, 1, 89, + 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 88, 1, 86, - 86, 86, 86, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 87, 1, 1, 1, 89, 89, - 89, 89, 89, 89, 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 91, 1, 89, 89, 89, + 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 90, 1, 1, 1, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 88, 1, 90, 1, 90, - 90, 90, 90, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 91, 1, 91, 91, 91, 91, 91, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 91, 1, 93, 1, 93, 93, 93, + 93, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 91, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 92, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 1, 86, 86, 86, 86, - 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 86, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 87, - 1, 1, 1, 94, 94, 94, 94, 94, + 1, 1, 1, 1, 1, 1, 94, 1, 94, 94, 94, 94, 94, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 94, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 95, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 1, 89, 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 89, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 90, 1, 1, + 1, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 88, 1, 95, 95, 95, 95, 95, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 95, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 96, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 97, 1, + 1, 1, 1, 1, 1, 1, 91, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, @@ -492,39 +492,39 @@ static const char _deserialize_json_indicies[] = { }; static const char _deserialize_json_trans_targs[] = { - 1, 0, 2, 2, 3, 4, 18, 24, - 37, 43, 51, 5, 12, 6, 7, 8, - 9, 11, 9, 11, 10, 2, 55, 10, - 55, 13, 14, 15, 16, 17, 16, 17, - 10, 2, 55, 19, 20, 21, 22, 23, - 10, 2, 55, 23, 25, 31, 26, 27, - 28, 29, 30, 29, 30, 10, 2, 55, - 32, 33, 34, 35, 36, 35, 36, 10, - 2, 55, 38, 39, 40, 41, 42, 10, - 2, 55, 42, 44, 45, 46, 49, 50, - 46, 47, 48, 10, 2, 55, 10, 2, - 55, 50, 52, 53, 49, 54, 54, 55, - 56, 57 + 1, 0, 2, 2, 3, 4, 19, 25, + 38, 44, 52, 5, 13, 6, 7, 8, + 9, 12, 9, 12, 10, 2, 11, 10, + 11, 11, 56, 57, 14, 15, 16, 17, + 18, 17, 18, 10, 2, 11, 20, 21, + 22, 23, 24, 10, 2, 11, 24, 26, + 32, 27, 28, 29, 30, 31, 30, 31, + 10, 2, 11, 33, 34, 35, 36, 37, + 36, 37, 10, 2, 11, 39, 40, 41, + 42, 43, 10, 2, 11, 43, 45, 46, + 47, 50, 51, 47, 48, 49, 10, 2, + 11, 10, 2, 11, 51, 53, 54, 50, + 55, 55 }; static const char _deserialize_json_trans_actions[] = { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 3, 3, 4, 0, - 5, 0, 0, 2, 2, 2, 0, 0, - 6, 6, 7, 0, 0, 0, 2, 2, - 8, 8, 9, 0, 0, 0, 0, 0, - 2, 2, 2, 0, 0, 10, 10, 11, - 0, 0, 2, 2, 2, 0, 0, 12, - 12, 13, 0, 0, 0, 2, 2, 14, - 14, 15, 0, 0, 0, 2, 16, 16, - 0, 17, 0, 18, 18, 19, 20, 20, - 21, 17, 0, 0, 22, 22, 23, 0, - 0, 0 + 5, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 6, 6, 7, 0, 0, + 0, 2, 2, 8, 8, 9, 0, 0, + 0, 0, 0, 2, 2, 2, 0, 0, + 10, 10, 11, 0, 0, 2, 2, 2, + 0, 0, 12, 12, 13, 0, 0, 0, + 2, 2, 14, 14, 15, 0, 0, 0, + 2, 16, 16, 0, 17, 0, 18, 18, + 19, 20, 20, 21, 17, 0, 0, 22, + 22, 23 }; static const int deserialize_json_start = 1; -static const int deserialize_json_first_final = 55; +static const int deserialize_json_first_final = 56; static const int deserialize_json_error = 0; static const int deserialize_json_en_main = 1; @@ -548,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, 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}; -#line 561 "hb-buffer-deserialize-json.hh" +#line 552 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 566 "hb-buffer-deserialize-json.hh" +#line 555 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -590,8 +588,8 @@ _resume: case 1: #line 38 "hb-buffer-deserialize-json.rl" { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } break; case 5: @@ -774,7 +772,7 @@ _resume: *end_ptr = p; } break; -#line 778 "hb-buffer-deserialize-json.hh" +#line 733 "hb-buffer-deserialize-json.hh" } _again: @@ -786,7 +784,7 @@ _again: _out: {} } -#line 139 "hb-buffer-deserialize-json.rl" +#line 137 "hb-buffer-deserialize-json.rl" *end_ptr = p; diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.rl b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.rl index d5e3c138db16..b12dd0f1a1e6 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.rl +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-json.rl @@ -36,8 +36,8 @@ alphtype unsigned char; write data; action clear_item { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } action add_item { @@ -106,7 +106,7 @@ item = @add_item ; -main := space* item (comma item)* space* (','|']')?; +main := space* item (comma item)* space* (','|']'); }%% @@ -125,9 +125,7 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, while (p < pe && ISSPACE (*p)) p++; if (p < pe && *p == (buffer->len ? ',' : '[')) - { *end_ptr = ++p; - } const char *tok = nullptr; int cs; diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-glyphs.hh b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-glyphs.hh new file mode 100644 index 000000000000..5fe75659b49c --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-glyphs.hh @@ -0,0 +1,692 @@ + +#line 1 "hb-buffer-deserialize-text-glyphs.rl" +/* + * 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_GLYPHS_HH +#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH + +#include "hb.hh" + + +#line 33 "hb-buffer-deserialize-text-glyphs.hh" +static const unsigned char _deserialize_text_glyphs_trans_keys[] = { + 0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 0 +}; + +static const char _deserialize_text_glyphs_key_spans[] = { + 0, 10, 13, 10, 13, 10, 10, 13, + 10, 1, 13, 10, 14, 82, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116 +}; + +static const short _deserialize_text_glyphs_index_offsets[] = { + 0, 0, 11, 25, 36, 50, 61, 72, + 86, 97, 99, 113, 124, 139, 222, 339, + 456, 573, 690, 807, 924, 1041, 1158, 1275, + 1392, 1509, 1626 +}; + +static const char _deserialize_text_glyphs_indicies[] = { + 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 3, 1, 1, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 1, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 1, 8, 1, 1, + 9, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 1, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 1, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 1, 15, 1, 1, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 1, 18, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 20, 1, 21, 1, 1, 22, + 23, 23, 23, 23, 23, 23, 23, 23, + 23, 1, 24, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 1, 20, 1, 1, + 1, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 1, 26, 26, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 26, 1, + 1, 26, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 26, 26, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 26, 1, 28, + 28, 28, 28, 28, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 28, 27, + 27, 29, 27, 27, 27, 27, 27, 27, + 27, 30, 1, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 31, 27, 27, 32, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 33, 1, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 28, 27, 34, 34, 34, 34, + 34, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 34, 26, 26, 35, 26, + 26, 26, 26, 26, 26, 26, 36, 1, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 37, 26, 26, 38, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 39, + 1, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 40, + 26, 41, 41, 41, 41, 41, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 41, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 42, 1, 43, 43, + 43, 43, 43, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 43, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 44, 1, 41, 41, 41, 41, 41, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 41, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 42, 1, + 46, 46, 46, 46, 46, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 46, + 1, 1, 47, 1, 1, 1, 1, 1, + 1, 1, 1, 48, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 49, 1, 50, 50, 50, + 50, 50, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 51, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 52, 1, 50, 50, 50, 50, 50, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 50, 1, 1, 51, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 52, 1, 46, + 46, 46, 46, 46, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 48, 1, 1, 1, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 49, 1, 53, 53, 53, 53, + 53, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 1, 54, 1, + 1, 1, 1, 1, 1, 1, 55, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 56, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 57, + 1, 58, 58, 58, 58, 58, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 58, 1, 1, 59, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 61, 1, 58, 58, + 58, 58, 58, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 58, 1, 1, + 59, 1, 1, 1, 1, 1, 1, 1, + 60, 1, 1, 1, 1, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 61, 1, 53, 53, 53, 53, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 53, 1, 1, 54, 1, 1, + 1, 1, 1, 1, 1, 55, 1, 1, + 1, 1, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 1, 1, 1, 1, + 1, 1, 56, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 0 +}; + +static const char _deserialize_text_glyphs_trans_targs[] = { + 16, 0, 18, 3, 19, 22, 19, 22, + 5, 20, 21, 20, 21, 23, 26, 8, + 9, 12, 9, 12, 10, 11, 24, 25, + 24, 25, 15, 15, 14, 1, 2, 6, + 7, 13, 15, 1, 2, 6, 7, 13, + 14, 17, 14, 17, 14, 18, 17, 1, + 4, 14, 17, 1, 14, 17, 1, 2, + 7, 14, 17, 1, 2, 14, 26 +}; + +static const char _deserialize_text_glyphs_trans_actions[] = { + 1, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 4, 3, 5, 5, 5, + 5, 4, 6, 7, 7, 7, 7, 0, + 6, 8, 8, 0, 0, 0, 9, 10, + 10, 9, 11, 12, 11, 13, 14, 14, + 14, 13, 15, 16, 16, 15, 0 +}; + +static const char _deserialize_text_glyphs_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 6, + 8, 0, 8, 9, 11, 11, 9, 13, + 15, 15, 13 +}; + +static const int deserialize_text_glyphs_start = 14; +static const int deserialize_text_glyphs_first_final = 14; +static const int deserialize_text_glyphs_error = 0; + +static const int deserialize_text_glyphs_en_main = 14; + + +#line 98 "hb-buffer-deserialize-text-glyphs.rl" + + +static hb_bool_t +_hb_buffer_deserialize_text_glyphs (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, *eof = pe, *orig_pe = pe; + + /* 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 *end = strchr ((char *) p, ']'); + if (end) + pe = eof = end; + else + { + end = strrchr ((char *) p, '|'); + if (end) + pe = eof = end; + else + pe = eof = p; + } + + const char *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + hb_glyph_position_t pos = {0}; + +#line 346 "hb-buffer-deserialize-text-glyphs.hh" + { + cs = deserialize_text_glyphs_start; + } + +#line 349 "hb-buffer-deserialize-text-glyphs.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_glyphs_trans_keys + (cs<<1); + _inds = _deserialize_text_glyphs_indicies + _deserialize_text_glyphs_index_offsets[cs]; + + _slen = _deserialize_text_glyphs_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_glyphs_trans_targs[_trans]; + + if ( _deserialize_text_glyphs_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_glyphs_trans_actions[_trans] ) { + case 1: +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} + break; + case 7: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 14: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 2: +#line 64 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 16: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 10: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 12: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } + break; + case 4: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} + break; + case 6: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 15: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 68 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 3: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 516 "hb-buffer-deserialize-text-glyphs.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_glyphs_eof_actions[cs] ) { + case 6: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 15: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 68 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 3: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 616 "hb-buffer-deserialize-text-glyphs.hh" + } + } + + _out: {} + } + +#line 136 "hb-buffer-deserialize-text-glyphs.rl" + + + if (pe < orig_pe && *pe == ']') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text.rl b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-glyphs.rl similarity index 73% rename from third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text.rl rename to third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-glyphs.rl index 0f33eb89d444..21db14b568bb 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text.rl +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-glyphs.rl @@ -24,20 +24,20 @@ * Google Author(s): Behdad Esfahbod */ -#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH -#define HB_BUFFER_DESERIALIZE_TEXT_HH +#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH +#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH #include "hb.hh" %%{ -machine deserialize_text; +machine deserialize_text_glyphs; alphtype unsigned char; write data; action clear_item { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } action add_item { @@ -52,9 +52,6 @@ action tok { tok = p; } -action ensure_glyphs { if (unlikely (!buffer->ensure_glyphs ())) return false; } -action ensure_unicode { if (unlikely (!buffer->ensure_unicode ())) return false; } - action parse_glyph { /* TODO Unescape delimiters. */ if (!hb_font_glyph_from_string (font, @@ -63,8 +60,6 @@ action parse_glyph { return false; } -action parse_hexdigits {if (!parse_hex (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; } @@ -76,7 +71,7 @@ unum = '0' | [1-9] digit*; num = '-'? unum; glyph_id = unum; -glyph_name = ([^\\\]=@+,|] | '\\' [\\\]=@+,|]) *; +glyph_name = ([^\\\]=@+,#|] | '\\' [\\\]=@+,|]) *; glyph = (glyph_id | glyph_name) >tok %parse_glyph; cluster = '=' (unum >tok %parse_cluster); @@ -93,45 +88,45 @@ glyph_item = glyphflags? ) >clear_item - @ensure_glyphs - %add_item - ; - -unicode = 'U' '+' xdigit+ >tok %parse_hexdigits; - -unicode_item = - ( - unicode - cluster? - ) - >clear_item - @ensure_unicode %add_item ; -glyphs = glyph_item (space* '|' space* glyph_item)* space* ('|'|']')?; -unicodes = unicode_item (space* '|' space* unicode_item)* space* ('|'|'>')?; +glyphs = glyph_item (space* '|' space* glyph_item)* space*; -main := space* ( ('[' glyphs) | ('<' unicodes) ); +main := space* glyphs; }%% static hb_bool_t -_hb_buffer_deserialize_text (hb_buffer_t *buffer, +_hb_buffer_deserialize_text_glyphs (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; + const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe; /* Ensure we have positions. */ (void) hb_buffer_get_glyph_positions (buffer, nullptr); while (p < pe && ISSPACE (*p)) p++; - - const char *eof = pe, *tok = nullptr; + if (p < pe && *p == (buffer->len ? '|' : '[')) + *end_ptr = ++p; + + const char *end = strchr ((char *) p, ']'); + if (end) + pe = eof = end; + else + { + end = strrchr ((char *) p, '|'); + if (end) + pe = eof = end; + else + pe = eof = p; + } + + const char *tok = nullptr; int cs; hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; @@ -140,9 +135,16 @@ _hb_buffer_deserialize_text (hb_buffer_t *buffer, write exec; }%% + if (pe < orig_pe && *pe == ']') + { + pe++; + if (p == pe) + p++; + } + *end_ptr = p; - return p == pe && *(p-1) != ']'; + return p == pe; } -#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ +#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-unicode.hh b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-unicode.hh new file mode 100644 index 000000000000..8ca73bf25f41 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-unicode.hh @@ -0,0 +1,332 @@ + +#line 1 "hb-buffer-deserialize-text-unicode.rl" +/* + * 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_UNICODE_HH +#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH + +#include "hb.hh" + + +#line 33 "hb-buffer-deserialize-text-unicode.hh" +static const unsigned char _deserialize_text_unicode_trans_keys[] = { + 0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 0 +}; + +static const char _deserialize_text_unicode_key_spans[] = { + 0, 109, 60, 55, 10, 116, 116, 116, + 116 +}; + +static const short _deserialize_text_unicode_index_offsets[] = { + 0, 0, 110, 171, 227, 238, 355, 472, + 589 +}; + +static const char _deserialize_text_unicode_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 3, + 1, 1, 1, 1, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 1, 7, + 7, 7, 7, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 1, 1, 1, 9, 1, 1, 1, 8, + 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8, + 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 11, 11, 11, 11, + 11, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 12, 12, 12, 12, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 12, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 13, 1, 12, 12, + 12, 12, 12, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 13, 1, 0 +}; + +static const char _deserialize_text_unicode_trans_targs[] = { + 1, 0, 2, 3, 5, 7, 8, 6, + 5, 4, 1, 6, 6, 1, 8 +}; + +static const char _deserialize_text_unicode_trans_actions[] = { + 0, 0, 1, 0, 2, 2, 2, 3, + 0, 4, 3, 0, 5, 5, 0 +}; + +static const char _deserialize_text_unicode_eof_actions[] = { + 0, 0, 0, 0, 0, 3, 0, 5, + 5 +}; + +static const int deserialize_text_unicode_start = 1; +static const int deserialize_text_unicode_first_final = 5; +static const int deserialize_text_unicode_error = 0; + +static const int deserialize_text_unicode_en_main = 1; + + +#line 79 "hb-buffer-deserialize-text-unicode.rl" + + +static hb_bool_t +_hb_buffer_deserialize_text_unicode (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, *eof = pe, *orig_pe = pe; + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '<')) + *end_ptr = ++p; + + const char *end = strchr ((char *) p, '>'); + if (end) + pe = eof = end; + else + { + end = strrchr ((char *) p, '|'); + if (end) + pe = eof = end; + else + pe = eof = p; + } + + + const char *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + const hb_glyph_position_t pos = {0}; + +#line 194 "hb-buffer-deserialize-text-unicode.hh" + { + cs = deserialize_text_unicode_start; + } + +#line 197 "hb-buffer-deserialize-text-unicode.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_unicode_trans_keys + (cs<<1); + _inds = _deserialize_text_unicode_indicies + _deserialize_text_unicode_index_offsets[cs]; + + _slen = _deserialize_text_unicode_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_unicode_trans_targs[_trans]; + + if ( _deserialize_text_unicode_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_unicode_trans_actions[_trans] ) { + case 1: +#line 38 "hb-buffer-deserialize-text-unicode.rl" + { + hb_memset (&info, 0, sizeof (info)); +} + break; + case 2: +#line 51 "hb-buffer-deserialize-text-unicode.rl" + { + tok = p; +} + break; + case 4: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } + break; + case 3: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 57 "hb-buffer-deserialize-text-unicode.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 256 "hb-buffer-deserialize-text-unicode.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_unicode_eof_actions[cs] ) { + case 3: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 57 "hb-buffer-deserialize-text-unicode.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 289 "hb-buffer-deserialize-text-unicode.hh" + } + } + + _out: {} + } + +#line 115 "hb-buffer-deserialize-text-unicode.rl" + + + if (pe < orig_pe && *pe == '>') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-unicode.rl b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-unicode.rl new file mode 100644 index 000000000000..92873b804f3b --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text-unicode.rl @@ -0,0 +1,129 @@ +/* + * 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_UNICODE_HH +#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH + +#include "hb.hh" + +%%{ + +machine deserialize_text_unicode; +alphtype unsigned char; +write data; + +action clear_item { + hb_memset (&info, 0, sizeof (info)); +} + +action add_item { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + +action tok { + tok = p; +} + +action parse_hexdigits {if (!parse_hex (tok, p, &info.codepoint )) return false; } + +action parse_cluster { if (!parse_uint (tok, p, &info.cluster )) return false; } + +unum = '0' | [1-9] digit*; +num = '-'? unum; + +cluster = '=' (unum >tok %parse_cluster); + +unicode = [Uu] '+'? xdigit+ >tok %parse_hexdigits; + +unicode_item = + ( + unicode + cluster? + ) + >clear_item + %add_item + ; + +unicodes = unicode_item (space* '|' space* unicode_item)* space*; + +main := space* unicodes; + +}%% + +static hb_bool_t +_hb_buffer_deserialize_text_unicode (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, *eof = pe, *orig_pe = pe; + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '<')) + *end_ptr = ++p; + + const char *end = strchr ((char *) p, '>'); + if (end) + pe = eof = end; + else + { + end = strrchr ((char *) p, '|'); + if (end) + pe = eof = end; + else + pe = eof = p; + } + + + const char *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + const hb_glyph_position_t pos = {0}; + %%{ + write init; + write exec; + }%% + + if (pe < orig_pe && *pe == '>') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text.hh b/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text.hh deleted file mode 100644 index 9062610de233..000000000000 --- a/third_party/harfbuzz-ng/src/src/hb-buffer-deserialize-text.hh +++ /dev/null @@ -1,1061 +0,0 @@ - -#line 1 "hb-buffer-deserialize-text.rl" -/* - * 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" - - -#line 36 "hb-buffer-deserialize-text.hh" -static const unsigned char _deserialize_text_trans_keys[] = { - 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, - 48u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, - 44u, 57u, 43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 0 -}; - -static const char _deserialize_text_key_spans[] = { - 0, 83, 1, 1, 55, 77, 10, 13, - 10, 10, 10, 13, 10, 1, 13, 10, - 14, 82, 13, 10, 116, 116, 0, 77, - 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116 -}; - -static const short _deserialize_text_index_offsets[] = { - 0, 0, 84, 86, 88, 144, 222, 233, - 247, 258, 269, 280, 294, 305, 307, 321, - 332, 347, 430, 444, 455, 572, 689, 690, - 768, 885, 1002, 1119, 1236, 1353, 1470, 1587, - 1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523, - 2640, 2757, 2874 -}; - -static const char _deserialize_text_indicies[] = { - 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 4, 1, 5, - 1, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 1, 1, 1, 1, 1, - 1, 1, 6, 6, 6, 6, 6, 6, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 6, 6, 6, 6, 6, 6, - 1, 7, 7, 7, 7, 7, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 7, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 1, 8, - 9, 9, 9, 9, 9, 9, 9, 9, - 9, 1, 10, 1, 1, 11, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 1, - 13, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 1, 15, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 1, 17, 18, - 18, 18, 18, 18, 18, 18, 18, 18, - 1, 19, 1, 1, 20, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 1, 22, - 23, 23, 23, 23, 23, 23, 23, 23, - 23, 1, 24, 1, 25, 1, 1, 26, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 1, 28, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 1, 24, 1, 1, - 1, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 1, 30, 30, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 30, 1, - 1, 30, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 30, 30, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 30, 1, 31, - 1, 1, 32, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 1, 34, 35, 35, - 35, 35, 35, 35, 35, 35, 35, 1, - 36, 36, 36, 36, 36, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 36, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 1, 1, 1, 38, 39, 1, 1, - 37, 37, 37, 37, 37, 37, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 37, 37, 37, 37, 37, 37, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 40, 1, 41, 41, 41, - 41, 41, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 41, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 42, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 43, 1, 1, 7, 7, 7, 7, 7, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 7, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 4, - 1, 44, 44, 44, 44, 44, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 44, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 45, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 46, 1, 44, 44, - 44, 44, 44, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 44, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 1, - 1, 1, 1, 45, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 46, 1, 49, 49, 49, 49, 49, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 49, 48, 48, 50, 48, 48, - 48, 48, 48, 48, 48, 51, 1, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 52, - 48, 48, 53, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 54, 55, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 56, 48, - 57, 57, 57, 57, 57, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 57, - 30, 30, 58, 30, 30, 30, 30, 30, - 30, 30, 59, 1, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 60, 30, 30, 61, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 62, 63, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 64, 30, 57, 57, 57, - 57, 57, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 57, 30, 30, 58, - 30, 30, 30, 30, 30, 30, 30, 59, - 1, 30, 30, 30, 65, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 30, 30, - 30, 60, 30, 30, 61, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 62, 63, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 64, 30, 67, 67, 67, 67, 67, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 67, 1, 1, 68, 1, 1, 1, - 1, 1, 1, 1, 1, 69, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 70, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 71, 1, 72, - 72, 72, 72, 72, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 72, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 42, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 73, 1, 74, 74, 74, 74, - 74, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 74, 48, 48, 50, 48, - 48, 48, 48, 48, 48, 48, 51, 1, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 52, 48, 48, 53, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 54, - 55, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 48, - 48, 48, 48, 48, 48, 48, 48, 56, - 48, 75, 75, 75, 75, 75, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 75, 1, 1, 76, 1, 1, 1, 1, - 1, 1, 1, 77, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 78, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 45, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 79, 1, 80, 80, - 80, 80, 80, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 80, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 81, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 82, 1, 80, 80, 80, 80, 80, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 80, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 83, 83, 83, 83, 83, 83, - 83, 83, 83, 83, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 81, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 82, 1, - 84, 84, 84, 84, 84, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 84, - 1, 1, 85, 1, 1, 1, 1, 1, - 1, 1, 86, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 87, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 88, 1, 84, 84, 84, - 84, 84, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 84, 1, 1, 85, - 1, 1, 1, 1, 1, 1, 1, 86, - 1, 1, 1, 1, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 87, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 88, 1, 75, 75, 75, 75, 75, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 75, 1, 1, 76, 1, 1, 1, - 1, 1, 1, 1, 77, 1, 1, 1, - 1, 89, 89, 89, 89, 89, 89, 89, - 89, 89, 89, 1, 1, 1, 1, 1, - 1, 78, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 45, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 79, 1, 90, - 90, 90, 90, 90, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 90, 1, - 1, 91, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 92, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 93, 1, 90, 90, 90, 90, - 90, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 90, 1, 1, 91, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 35, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 92, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 93, - 1, 67, 67, 67, 67, 67, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 67, 1, 1, 68, 1, 1, 1, 1, - 1, 1, 1, 1, 69, 1, 1, 1, - 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 70, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 71, 1, 94, 94, - 94, 94, 94, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 94, 30, 30, - 58, 30, 30, 30, 30, 30, 30, 30, - 59, 1, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 60, 30, 30, 61, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 62, 95, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 96, 30, 94, 94, 94, 94, 94, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 94, 30, 30, 58, 30, 30, - 30, 30, 30, 30, 30, 59, 1, 30, - 30, 30, 97, 97, 97, 97, 97, 97, - 97, 97, 97, 97, 30, 30, 30, 60, - 30, 30, 61, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 62, 95, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 96, 30, - 0 -}; - -static const char _deserialize_text_trans_targs[] = { - 1, 0, 2, 26, 3, 4, 20, 5, - 24, 25, 8, 29, 40, 29, 40, 32, - 37, 33, 34, 12, 13, 16, 13, 16, - 14, 15, 35, 36, 35, 36, 27, 19, - 38, 39, 38, 39, 21, 20, 6, 22, - 23, 21, 22, 23, 21, 22, 23, 25, - 27, 27, 28, 7, 9, 11, 17, 22, - 31, 27, 28, 7, 9, 11, 17, 22, - 31, 41, 42, 30, 10, 18, 22, 31, - 30, 31, 31, 30, 10, 7, 11, 31, - 30, 22, 31, 34, 30, 10, 7, 22, - 31, 37, 30, 10, 22, 31, 27, 22, - 31, 42 -}; - -static const char _deserialize_text_trans_actions[] = { - 0, 0, 0, 0, 1, 0, 2, 0, - 2, 2, 3, 4, 4, 5, 5, 4, - 4, 4, 4, 3, 3, 3, 0, 0, - 6, 3, 4, 4, 5, 5, 5, 3, - 4, 4, 5, 5, 7, 8, 9, 7, - 7, 0, 0, 0, 10, 10, 10, 8, - 12, 13, 14, 15, 15, 15, 16, 11, - 11, 18, 19, 20, 20, 20, 0, 17, - 17, 4, 4, 21, 22, 22, 21, 21, - 0, 0, 13, 10, 23, 23, 23, 10, - 24, 24, 24, 5, 25, 26, 26, 25, - 25, 5, 27, 28, 27, 27, 30, 29, - 29, 5 -}; - -static const char _deserialize_text_eof_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7, 0, 0, 0, - 10, 10, 11, 17, 17, 21, 0, 11, - 10, 24, 24, 25, 25, 10, 27, 27, - 21, 29, 29 -}; - -static const int deserialize_text_start = 1; -static const int deserialize_text_first_final = 20; -static const int deserialize_text_error = 0; - -static const int deserialize_text_en_main = 1; - - -#line 117 "hb-buffer-deserialize-text.rl" - - -static hb_bool_t -_hb_buffer_deserialize_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++; - - const char *eof = pe, *tok = nullptr; - int cs; - hb_glyph_info_t info = {0}; - hb_glyph_position_t pos = {0}; - -#line 513 "hb-buffer-deserialize-text.hh" - { - cs = deserialize_text_start; - } - -#line 518 "hb-buffer-deserialize-text.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _deserialize_text_trans_keys + (cs<<1); - _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs]; - - _slen = _deserialize_text_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && - (*p) <= _keys[1] ? - (*p) - _keys[0] : _slen ]; - - cs = _deserialize_text_trans_targs[_trans]; - - if ( _deserialize_text_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _deserialize_text_trans_actions[_trans] ) { - case 1: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} - break; - case 3: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 5: -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 8: -#line 56 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_unicode ())) return false; } - break; - case 20: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 9: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } - break; - case 23: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } - break; - case 6: -#line 69 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } - break; - case 26: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } - break; - case 22: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } - break; - case 28: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } - break; - case 16: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 4: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 2: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 56 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_unicode ())) return false; } - break; - case 17: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 19: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 7: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 10: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 25: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 21: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 27: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 24: -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 12: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 15: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 18: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 29: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 14: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 30: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 13: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 898 "hb-buffer-deserialize-text.hh" - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - switch ( _deserialize_text_eof_actions[cs] ) { - case 17: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 7: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 10: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 25: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 21: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 27: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 24: -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 29: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 73 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.mask )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 1047 "hb-buffer-deserialize-text.hh" - } - } - - _out: {} - } - -#line 141 "hb-buffer-deserialize-text.rl" - - - *end_ptr = p; - - return p == pe && *(p-1) != ']'; -} - -#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-serialize.cc b/third_party/harfbuzz-ng/src/src/hb-buffer-serialize.cc index d1e177543033..16f189519b19 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer-serialize.cc +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-serialize.cc @@ -183,7 +183,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -241,7 +241,7 @@ _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -329,7 +329,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -381,7 +381,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -721,7 +721,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv) } #include "hb-buffer-deserialize-json.hh" -#include "hb-buffer-deserialize-text.hh" +#include "hb-buffer-deserialize-text-glyphs.hh" +#include "hb-buffer-deserialize-text-unicode.hh" /** * hb_buffer_deserialize_glyphs: @@ -736,7 +737,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv) * Deserializes glyphs @buffer from textual representation in the format * produced by hb_buffer_serialize_glyphs(). * - * Return value: `true` if @buf is not fully consumed, `false` otherwise. + * Return value: `true` if parse was successful, `false` if an error + * occurred. * * Since: 0.9.7 **/ @@ -779,9 +781,9 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text_glyphs (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_deserialize_json (buffer, @@ -808,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, * Deserializes Unicode @buffer from textual representation in the format * produced by hb_buffer_serialize_unicode(). * - * Return value: `true` if @buf is not fully consumed, `false` otherwise. + * Return value: `true` if parse was successful, `false` if an error + * occurred. * * Since: 2.7.3 **/ @@ -849,9 +852,9 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text_unicode (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_deserialize_json (buffer, diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer-verify.cc b/third_party/harfbuzz-ng/src/src/hb-buffer-verify.cc index 5453e1ca94ee..f111b2d8dcf8 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer-verify.cc +++ b/third_party/harfbuzz-ng/src/src/hb-buffer-verify.cc @@ -150,7 +150,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, assert (text_start < text_end); if (0) - printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); hb_buffer_clear_contents (fragment); @@ -186,7 +186,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, bool ret = true; hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff) + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); ret = false; @@ -292,7 +292,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, assert (text_start < text_end); if (0) - printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); #if 0 hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); @@ -313,7 +313,6 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, bool ret = true; hb_buffer_diff_flags_t diff; - /* * Shape the two fragment streams. */ @@ -382,7 +381,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, * Diff results. */ diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff) + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); ret = false; diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/src/hb-buffer.cc index 57a5ae03ed1c..616cee807f6a 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer.cc +++ b/third_party/harfbuzz-ng/src/src/hb-buffer.cc @@ -40,6 +40,11 @@ * Buffers serve a dual role in HarfBuzz; before shaping, they hold * the input characters that are passed to hb_shape(), and after * shaping they hold the output glyphs. + * + * The input buffer is a sequence of Unicode codepoints, with + * associated attributes such as direction and script. The output + * buffer is a sequence of glyphs, with associated attributes such + * as position and cluster. **/ @@ -172,12 +177,13 @@ hb_buffer_t::enlarge (unsigned int size) while (size >= new_allocated) new_allocated += (new_allocated >> 1) + 32; - static_assert ((sizeof (info[0]) == sizeof (pos[0])), ""); - if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0])))) + unsigned new_bytes; + if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes))) goto done; - new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0])); - new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0])); + static_assert (sizeof (info[0]) == sizeof (pos[0]), ""); + new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes); + new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes); done: if (unlikely (!new_pos || !new_info)) @@ -208,7 +214,7 @@ hb_buffer_t::make_room_for (unsigned int num_in, assert (have_output); out_info = (hb_glyph_info_t *) pos; - memcpy (out_info, info, out_len * sizeof (out_info[0])); + hb_memcpy (out_info, info, out_len * sizeof (out_info[0])); } return true; @@ -229,7 +235,7 @@ hb_buffer_t::shift_forward (unsigned int count) * 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])); + hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0])); } len += count; idx += count; @@ -298,8 +304,8 @@ hb_buffer_t::clear () out_len = 0; out_info = info; - memset (context, 0, sizeof context); - memset (context_len, 0, sizeof context_len); + hb_memset (context, 0, sizeof context); + hb_memset (context_len, 0, sizeof context_len); deallocate_var_all (); serial = 0; @@ -313,15 +319,14 @@ hb_buffer_t::enter () serial = 0; shaping_failed = false; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR))) + unsigned mul; + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul))) { - max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR, - (unsigned) HB_BUFFER_MAX_LEN_MIN); + max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN); } - if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR))) + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul))) { - max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR, - (unsigned) HB_BUFFER_MAX_OPS_MIN); + max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN); } } void @@ -345,7 +350,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint, glyph = &info[len]; - memset (glyph, 0, sizeof (*glyph)); + hb_memset (glyph, 0, sizeof (*glyph)); glyph->codepoint = codepoint; glyph->mask = 0; glyph->cluster = cluster; @@ -522,15 +527,17 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, cluster = hb_min (cluster, info[i].cluster); /* Extend end */ - while (end < len && info[end - 1].cluster == info[end].cluster) - end++; + if (cluster != info[end - 1].cluster) + while (end < len && info[end - 1].cluster == info[end].cluster) + end++; /* Extend start */ - while (idx < start && info[start - 1].cluster == info[start].cluster) - start--; + if (cluster != info[start].cluster) + while (idx < start && info[start - 1].cluster == info[start].cluster) + start--; /* If we hit the start of buffer, continue in out-buffer. */ - if (idx == start) + if (idx == start && info[start].cluster != cluster) for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) set_cluster (out_info[i - 1], cluster); @@ -605,6 +612,53 @@ hb_buffer_t::delete_glyph () skip_glyph (); } +void +hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)) +{ + /* Merge clusters and delete filtered glyphs. + * NOTE! We can't use out-buffer as we have positioning data. */ + unsigned int j = 0; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (filter (&info[i])) + { + /* Merge clusters. + * Same logic as delete_glyph(), but for in-place removal. */ + + unsigned int cluster = info[i].cluster; + if (i + 1 < count && cluster == info[i + 1].cluster) + continue; /* Cluster survives; do nothing. */ + + if (j) + { + /* Merge cluster backward. */ + if (cluster < info[j - 1].cluster) + { + unsigned int mask = info[i].mask; + unsigned int old_cluster = info[j - 1].cluster; + for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) + set_cluster (info[k - 1], cluster, mask); + } + continue; + } + + if (i + 1 < count) + merge_clusters (i, i + 2); /* Merge cluster forward. */ + + continue; + } + + if (j != i) + { + info[j] = info[i]; + pos[j] = pos[i]; + } + j++; + } + len = j; +} + void hb_buffer_t::guess_segment_properties () { @@ -846,6 +900,32 @@ hb_buffer_get_user_data (const hb_buffer_t *buffer, * Sets the type of @buffer contents. Buffers are either empty, contain * characters (before shaping), or contain glyphs (the result of shaping). * + * You rarely need to call this function, since a number of other + * functions transition the content type for you. Namely: + * + * - A newly created buffer starts with content type + * %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(), + * hb_buffer_clear_contents(), as well as calling hb_buffer_set_length() + * with an argument of zero all set the buffer content type to invalid + * as well. + * + * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(), + * hb_buffer_add_utf32(), hb_buffer_add_codepoints() and + * hb_buffer_add_latin1() expect that buffer is either empty and + * have a content type of invalid, or that buffer content type is + * %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content + * type to Unicode if they added anything to an empty buffer. + * + * - Finally hb_shape() and hb_shape_full() expect that the buffer + * is either empty and have content type of invalid, or that buffer + * content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon + * success they set the buffer content type to + * %HB_BUFFER_CONTENT_TYPE_GLYPHS. + * + * The above transitions are designed such that one can use a buffer + * in a loop of "reset : add-text : shape" without needing to ever + * modify the content type manually. + * * Since: 0.9.5 **/ void @@ -933,7 +1013,6 @@ hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer) void hb_buffer_set_direction (hb_buffer_t *buffer, hb_direction_t direction) - { if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1385,9 +1464,9 @@ hb_buffer_set_length (hb_buffer_t *buffer, /* Wipe the new space */ if (length > buffer->len) { - memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); + hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); if (buffer->have_positions) - memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); + hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); } buffer->len = length; @@ -1795,7 +1874,9 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer, * marks at stat of run. * * This function does not check the validity of @text, it is up to the caller - * to ensure it contains a valid Unicode code points. + * to ensure it contains a valid Unicode scalar values. In contrast, + * hb_buffer_add_utf32() can be used that takes similar input but performs + * sanity-check on the input. * * Since: 0.9.31 **/ @@ -1858,9 +1939,9 @@ hb_buffer_append (hb_buffer_t *buffer, hb_segment_properties_overlay (&buffer->props, &source->props); - memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); + hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) - memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); + hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) { @@ -2048,7 +2129,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 & ~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; @@ -2103,6 +2184,13 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, hb_buffer_message_func_t func, void *user_data, hb_destroy_func_t destroy) { + if (unlikely (hb_object_is_immutable (buffer))) + { + if (destroy) + destroy (user_data); + return; + } + if (buffer->message_destroy) buffer->message_destroy (buffer->message_data); diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer.h b/third_party/harfbuzz-ng/src/src/hb-buffer.h index 8c1748983582..bff78543c876 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer.h +++ b/third_party/harfbuzz-ng/src/src/hb-buffer.h @@ -763,7 +763,7 @@ hb_buffer_diff (hb_buffer_t *buffer, /* - * Debugging. + * Tracing. */ /** diff --git a/third_party/harfbuzz-ng/src/src/hb-buffer.hh b/third_party/harfbuzz-ng/src/src/hb-buffer.hh index 26c3f0fac8cd..5a43cabcb757 100644 --- a/third_party/harfbuzz-ng/src/src/hb-buffer.hh +++ b/third_party/harfbuzz-ng/src/src/hb-buffer.hh @@ -32,28 +32,9 @@ #include "hb.hh" #include "hb-unicode.hh" +#include "hb-set-digest.hh" -#ifndef HB_BUFFER_MAX_LEN_FACTOR -#define HB_BUFFER_MAX_LEN_FACTOR 64 -#endif -#ifndef HB_BUFFER_MAX_LEN_MIN -#define HB_BUFFER_MAX_LEN_MIN 16384 -#endif -#ifndef HB_BUFFER_MAX_LEN_DEFAULT -#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ -#endif - -#ifndef HB_BUFFER_MAX_OPS_FACTOR -#define HB_BUFFER_MAX_OPS_FACTOR 1024 -#endif -#ifndef HB_BUFFER_MAX_OPS_MIN -#define HB_BUFFER_MAX_OPS_MIN 16384 -#endif -#ifndef HB_BUFFER_MAX_OPS_DEFAULT -#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ -#endif - static_assert ((sizeof (hb_glyph_info_t) == 20), ""); static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), ""); @@ -207,6 +188,14 @@ struct hb_buffer_t 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]; } + hb_set_digest_t digest () const + { + hb_set_digest_t d; + d.init (); + d.add_array (&info[0].codepoint, len, sizeof (info[0])); + return d; + } + HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); HB_INTERNAL void clear (); @@ -402,6 +391,8 @@ struct hb_buffer_t 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 (); + HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)); + /* Adds glyph flags in mask to infos with clusters between start and end. @@ -590,21 +581,59 @@ struct hb_buffer_t unsigned int cluster, hb_mask_t mask) { - for (unsigned int i = start; i < end; i++) - if (cluster != infos[i].cluster) + if (unlikely (start == end)) + return; + + unsigned cluster_first = infos[start].cluster; + unsigned cluster_last = infos[end - 1].cluster; + + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS || + (cluster != cluster_first && cluster != cluster_last)) + { + for (unsigned int i = start; i < end; i++) + if (cluster != infos[i].cluster) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i].mask |= mask; + } + return; + } + + /* Monotone clusters */ + + if (cluster == cluster_first) + { + for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i - 1].mask |= mask; + } + } + else /* cluster == cluster_last */ + { + for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++) { scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; infos[i].mask |= mask; } + } } - static unsigned + unsigned _infos_find_min_cluster (const hb_glyph_info_t *infos, unsigned start, unsigned end, unsigned cluster = UINT_MAX) { - for (unsigned int i = start; i < end; i++) - cluster = hb_min (cluster, infos[i].cluster); - return cluster; + if (unlikely (start == end)) + return cluster; + + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + { + for (unsigned int i = start; i < end; i++) + cluster = hb_min (cluster, infos[i].cluster); + return cluster; + } + + return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster)); } void clear_glyph_flags (hb_mask_t mask = 0) diff --git a/third_party/harfbuzz-ng/src/src/hb-cache.hh b/third_party/harfbuzz-ng/src/src/hb-cache.hh index 897f313fbd44..8371465c6c2c 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cache.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cache.hh @@ -30,7 +30,19 @@ #include "hb.hh" -/* Implements a lockfree cache for int->int functions. */ +/* Implements a lockfree cache for int->int functions. + * + * The cache is a fixed-size array of 16-bit or 32-bit integers. + * The key is split into two parts: the cache index and the rest. + * + * The cache index is used to index into the array. The rest is used + * to store the key and the value. + * + * The value is stored in the least significant bits of the integer. + * The key is stored in the most significant bits of the integer. + * The key is shifted by cache_bits to the left to make room for the + * value. + */ template ::type, typename std::conditional::type >::type; static_assert ((key_bits >= cache_bits), ""); - static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (item_t)), ""); + static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); + + hb_cache_t () { init (); } void init () { clear (); } - void fini () {} void clear () { diff --git a/third_party/harfbuzz-ng/src/src/hb-cairo-utils.cc b/third_party/harfbuzz-ng/src/src/hb-cairo-utils.cc new file mode 100644 index 000000000000..0f94d8169f24 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-cairo-utils.cc @@ -0,0 +1,874 @@ +/* + * Copyright © 2022 Red Hat, Inc + * Copyright © 2021, 2022 Black Foundry + * + * 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): Matthias Clasen + */ + +#include "hb.hh" + +#ifdef HAVE_CAIRO + +#include "hb-cairo-utils.hh" + +#include + +/* Some routines in this file were ported from BlackRenderer by Black Foundry. + * Used by permission to relicense to HarfBuzz license. + * + * https://github.com/BlackFoundryCom/black-renderer + */ + +#define PREALLOCATED_COLOR_STOPS 16 + +typedef struct { + float r, g, b, a; +} hb_cairo_color_t; + +static inline cairo_extend_t +hb_cairo_extend (hb_paint_extend_t extend) +{ + switch (extend) + { + case HB_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD; + case HB_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT; + case HB_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT; + default: break; + } + + return CAIRO_EXTEND_PAD; +} + +#ifdef CAIRO_HAS_PNG_FUNCTIONS +typedef struct +{ + hb_blob_t *blob; + unsigned int offset; +} hb_cairo_read_blob_data_t; + +static cairo_status_t +hb_cairo_read_blob (void *closure, + unsigned char *data, + unsigned int length) +{ + hb_cairo_read_blob_data_t *r = (hb_cairo_read_blob_data_t *) closure; + const char *d; + unsigned int size; + + d = hb_blob_get_data (r->blob, &size); + + if (r->offset + length > size) + return CAIRO_STATUS_READ_ERROR; + + memcpy (data, d + r->offset, length); + r->offset += length; + + return CAIRO_STATUS_SUCCESS; +} +#endif + +static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0}; + +static void +_hb_cairo_destroy_blob (void *p) +{ + hb_blob_destroy ((hb_blob_t *) p); +} + +hb_bool_t +_hb_cairo_paint_glyph_image (hb_cairo_context_t *c, + hb_blob_t *blob, + unsigned width, + unsigned height, + hb_tag_t format, + float slant, + hb_glyph_extents_t *extents) +{ + cairo_t *cr = c->cr; + + if (!extents) /* SVG currently. */ + return false; + + cairo_surface_t *surface = nullptr; + +#ifdef CAIRO_HAS_PNG_FUNCTIONS + if (format == HB_PAINT_IMAGE_FORMAT_PNG) + { + hb_cairo_read_blob_data_t r; + r.blob = blob; + r.offset = 0; + surface = cairo_image_surface_create_from_png_stream (hb_cairo_read_blob, &r); + + /* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(. + * Just pull them out of the surface. */ + width = cairo_image_surface_get_width (surface); + height = cairo_image_surface_get_width (surface); + } + else +#endif + if (format == HB_PAINT_IMAGE_FORMAT_BGRA) + { + /* Byte-endian conversion. */ + unsigned data_size = hb_blob_get_length (blob); + if (data_size < width * height * 4) + return false; + + unsigned char *data; +#ifdef __BYTE_ORDER + if (__BYTE_ORDER == __BIG_ENDIAN) + { + data = (unsigned char *) hb_blob_get_data_writable (blob, nullptr); + if (!data) + return false; + + unsigned count = width * height * 4; + for (unsigned i = 0; i < count; i += 4) + { + unsigned char b; + b = data[i]; + data[i] = data[i+3]; + data[i+3] = b; + b = data[i+1]; + data[i+1] = data[i+2]; + data[i+2] = b; + } + } + else +#endif + data = (unsigned char *) hb_blob_get_data (blob, nullptr); + + surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_ARGB32, + width, height, + width * 4); + + cairo_surface_set_user_data (surface, + _hb_cairo_surface_blob_user_data_key, + hb_blob_reference (blob), + _hb_cairo_destroy_blob); + } + + if (!surface) + return false; + + cairo_save (cr); + /* this clip is here to work around recording surface limitations */ + cairo_rectangle (cr, + extents->x_bearing, + extents->y_bearing, + extents->width, + extents->height); + cairo_clip (cr); + + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); + + cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0}; + cairo_pattern_set_matrix (pattern, &matrix); + + /* Undo slant in the extents and apply it in the context. */ + extents->width -= extents->height * slant; + extents->x_bearing -= extents->y_bearing * slant; + cairo_matrix_t cairo_matrix = {1., 0., (double) slant, 1., 0., 0.}; + cairo_transform (cr, &cairo_matrix); + + cairo_translate (cr, extents->x_bearing, extents->y_bearing); + cairo_scale (cr, extents->width, extents->height); + cairo_set_source (cr, pattern); + + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + cairo_restore (cr); + + return true; +} + +static void +_hb_cairo_reduce_anchors (float x0, float y0, + float x1, float y1, + float x2, float y2, + float *xx0, float *yy0, + float *xx1, float *yy1) +{ + float q1x, q1y, q2x, q2y; + float s; + float k; + + q2x = x2 - x0; + q2y = y2 - y0; + q1x = x1 - x0; + q1y = y1 - y0; + + s = q2x * q2x + q2y * q2y; + if (s < 0.000001f) + { + *xx0 = x0; *yy0 = y0; + *xx1 = x1; *yy1 = y1; + return; + } + + k = (q2x * q1x + q2y * q1y) / s; + *xx0 = x0; + *yy0 = y0; + *xx1 = x1 - k * q2x; + *yy1 = y1 - k * q2y; +} + +static int +_hb_cairo_cmp_color_stop (const void *p1, + const void *p2) +{ + const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1; + const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2; + + if (c1->offset < c2->offset) + return -1; + else if (c1->offset > c2->offset) + return 1; + else + return 0; +} + +static void +_hb_cairo_normalize_color_line (hb_color_stop_t *stops, + unsigned int len, + float *omin, + float *omax) +{ + float min, max; + + hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop); + + min = max = stops[0].offset; + for (unsigned int i = 0; i < len; i++) + { + min = hb_min (min, stops[i].offset); + max = hb_max (max, stops[i].offset); + } + + if (min != max) + { + for (unsigned int i = 0; i < len; i++) + stops[i].offset = (stops[i].offset - min) / (max - min); + } + + *omin = min; + *omax = max; +} + +static bool +_hb_cairo_get_color_stops (hb_cairo_context_t *c, + hb_color_line_t *color_line, + unsigned *count, + hb_color_stop_t **stops) +{ + unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr); + if (len > *count) + { + *stops = (hb_color_stop_t *) hb_malloc (len * sizeof (hb_color_stop_t)); + if (unlikely (!stops)) + return false; + } + hb_color_line_get_color_stops (color_line, 0, &len, *stops); + for (unsigned i = 0; i < len; i++) + if ((*stops)[i].is_foreground) + { +#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE + double r, g, b, a; + cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font); + if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS) + (*stops)[i].color = HB_COLOR (round (b * 255.), round (g * 255.), round (r * 255.), + round (a * hb_color_get_alpha ((*stops)[i].color))); + else +#endif + (*stops)[i].color = HB_COLOR (0, 0, 0, hb_color_get_alpha ((*stops)[i].color)); + } + + *count = len; + return true; +} + +void +_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, + float x1, float y1, + float x2, float y2) +{ + cairo_t *cr = c->cr; + + unsigned int len = PREALLOCATED_COLOR_STOPS; + hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; + hb_color_stop_t *stops = stops_; + float xx0, yy0, xx1, yy1; + float xxx0, yyy0, xxx1, yyy1; + float min, max; + cairo_pattern_t *pattern; + + if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) + return; + _hb_cairo_normalize_color_line (stops, len, &min, &max); + + _hb_cairo_reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1); + + xxx0 = xx0 + min * (xx1 - xx0); + yyy0 = yy0 + min * (yy1 - yy0); + xxx1 = xx0 + max * (xx1 - xx0); + yyy1 = yy0 + max * (yy1 - yy0); + + pattern = cairo_pattern_create_linear ((double) xxx0, (double) yyy0, (double) xxx1, (double) yyy1); + cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line))); + for (unsigned int i = 0; i < len; i++) + { + double r, g, b, a; + r = hb_color_get_red (stops[i].color) / 255.; + g = hb_color_get_green (stops[i].color) / 255.; + b = hb_color_get_blue (stops[i].color) / 255.; + a = hb_color_get_alpha (stops[i].color) / 255.; + cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a); + } + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + if (stops != stops_) + hb_free (stops); +} + +void +_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, float r0, + float x1, float y1, float r1) +{ + cairo_t *cr = c->cr; + + unsigned int len = PREALLOCATED_COLOR_STOPS; + hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; + hb_color_stop_t *stops = stops_; + float min, max; + float xx0, yy0, xx1, yy1; + float rr0, rr1; + cairo_pattern_t *pattern; + + if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) + return; + _hb_cairo_normalize_color_line (stops, len, &min, &max); + + xx0 = x0 + min * (x1 - x0); + yy0 = y0 + min * (y1 - y0); + xx1 = x0 + max * (x1 - x0); + yy1 = y0 + max * (y1 - y0); + rr0 = r0 + min * (r1 - r0); + rr1 = r0 + max * (r1 - r0); + + pattern = cairo_pattern_create_radial ((double) xx0, (double) yy0, (double) rr0, (double) xx1, (double) yy1, (double) rr1); + cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line))); + + for (unsigned int i = 0; i < len; i++) + { + double r, g, b, a; + r = hb_color_get_red (stops[i].color) / 255.; + g = hb_color_get_green (stops[i].color) / 255.; + b = hb_color_get_blue (stops[i].color) / 255.; + a = hb_color_get_alpha (stops[i].color) / 255.; + cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a); + } + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + if (stops != stops_) + hb_free (stops); +} + +typedef struct { + float x, y; +} hb_cairo_point_t; + +static inline float +_hb_cairo_interpolate (float f0, float f1, float f) +{ + return f0 + f * (f1 - f0); +} + +static inline void +_hb_cairo_premultiply (hb_cairo_color_t *c) +{ + c->r *= c->a; + c->g *= c->a; + c->b *= c->a; +} + +static inline void +_hb_cairo_unpremultiply (hb_cairo_color_t *c) +{ + if (c->a != 0.f) + { + c->r /= c->a; + c->g /= c->a; + c->b /= c->a; + } +} + +static void +_hb_cairo_interpolate_colors (hb_cairo_color_t *c0, hb_cairo_color_t *c1, float k, hb_cairo_color_t *c) +{ + // According to the COLR specification, gradients + // should be interpolated in premultiplied form + _hb_cairo_premultiply (c0); + _hb_cairo_premultiply (c1); + c->r = c0->r + k * (c1->r - c0->r); + c->g = c0->g + k * (c1->g - c0->g); + c->b = c0->b + k * (c1->b - c0->b); + c->a = c0->a + k * (c1->a - c0->a); + _hb_cairo_unpremultiply (c); +} + +static inline float +_hb_cairo_dot (hb_cairo_point_t p, hb_cairo_point_t q) +{ + return p.x * q.x + p.y * q.y; +} + +static inline hb_cairo_point_t +_hb_cairo_normalize (hb_cairo_point_t p) +{ + float len = sqrtf (_hb_cairo_dot (p, p)); + + return hb_cairo_point_t { p.x / len, p.y / len }; +} + +static inline hb_cairo_point_t +_hb_cairo_sum (hb_cairo_point_t p, hb_cairo_point_t q) +{ + return hb_cairo_point_t { p.x + q.x, p.y + q.y }; +} + +static inline hb_cairo_point_t +_hb_cairo_difference (hb_cairo_point_t p, hb_cairo_point_t q) +{ + return hb_cairo_point_t { p.x - q.x, p.y - q.y }; +} + +static inline hb_cairo_point_t +_hb_cairo_scale (hb_cairo_point_t p, float f) +{ + return hb_cairo_point_t { p.x * f, p.y * f }; +} + +typedef struct { + hb_cairo_point_t center, p0, c0, c1, p1; + hb_cairo_color_t color0, color1; +} hb_cairo_patch_t; + +static void +_hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cairo_patch_t *p) +{ + cairo_mesh_pattern_begin_patch (pattern); + cairo_mesh_pattern_move_to (pattern, (double) center->x, (double) center->y); + cairo_mesh_pattern_line_to (pattern, (double) p->p0.x, (double) p->p0.y); + cairo_mesh_pattern_curve_to (pattern, + (double) p->c0.x, (double) p->c0.y, + (double) p->c1.x, (double) p->c1.y, + (double) p->p1.x, (double) p->p1.y); + cairo_mesh_pattern_line_to (pattern, (double) center->x, (double) center->y); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, + (double) p->color0.r, + (double) p->color0.g, + (double) p->color0.b, + (double) p->color0.a); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 1, + (double) p->color0.r, + (double) p->color0.g, + (double) p->color0.b, + (double) p->color0.a); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, + (double) p->color1.r, + (double) p->color1.g, + (double) p->color1.b, + (double) p->color1.a); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 3, + (double) p->color1.r, + (double) p->color1.g, + (double) p->color1.b, + (double) p->color1.a); + cairo_mesh_pattern_end_patch (pattern); +} + +#define MAX_ANGLE (HB_PI / 8.f) + +static void +_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius, + float a0, hb_cairo_color_t *c0, + float a1, hb_cairo_color_t *c1, + cairo_pattern_t *pattern) +{ + hb_cairo_point_t center = hb_cairo_point_t { cx, cy }; + int num_splits; + hb_cairo_point_t p0; + hb_cairo_color_t color0, color1; + + num_splits = ceilf (fabsf (a1 - a0) / MAX_ANGLE); + p0 = hb_cairo_point_t { cosf (a0), sinf (a0) }; + color0 = *c0; + + for (int a = 0; a < num_splits; a++) + { + float k = (a + 1.) / num_splits; + float angle1; + hb_cairo_point_t p1; + hb_cairo_point_t A, U; + hb_cairo_point_t C0, C1; + hb_cairo_patch_t patch; + + angle1 = _hb_cairo_interpolate (a0, a1, k); + _hb_cairo_interpolate_colors (c0, c1, k, &color1); + + patch.color0 = color0; + patch.color1 = color1; + + p1 = hb_cairo_point_t { cosf (angle1), sinf (angle1) }; + patch.p0 = _hb_cairo_sum (center, _hb_cairo_scale (p0, radius)); + patch.p1 = _hb_cairo_sum (center, _hb_cairo_scale (p1, radius)); + + A = _hb_cairo_normalize (_hb_cairo_sum (p0, p1)); + U = hb_cairo_point_t { -A.y, A.x }; + C0 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p0, A), p0) / _hb_cairo_dot (U, p0))); + C1 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p1, A), p1) / _hb_cairo_dot (U, p1))); + + patch.c0 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C0, _hb_cairo_scale (_hb_cairo_difference (C0, p0), 0.33333f)), radius)); + patch.c1 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C1, _hb_cairo_scale (_hb_cairo_difference (C1, p1), 0.33333f)), radius)); + + _hb_cairo_add_patch (pattern, ¢er, &patch); + + p0 = p1; + color0 = color1; + } +} + +static void +_hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops, + unsigned int n_stops, + cairo_extend_t extend, + float cx, float cy, + float radius, + float start_angle, + float end_angle, + cairo_pattern_t *pattern) +{ + float angles_[PREALLOCATED_COLOR_STOPS]; + float *angles = angles_; + hb_cairo_color_t colors_[PREALLOCATED_COLOR_STOPS]; + hb_cairo_color_t *colors = colors_; + hb_cairo_color_t color0, color1; + + if (start_angle == end_angle) + { + if (extend == CAIRO_EXTEND_PAD) + { + hb_cairo_color_t c; + if (start_angle > 0) + { + c.r = hb_color_get_red (stops[0].color) / 255.; + c.g = hb_color_get_green (stops[0].color) / 255.; + c.b = hb_color_get_blue (stops[0].color) / 255.; + c.a = hb_color_get_alpha (stops[0].color) / 255.; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0., &c, + start_angle, &c, + pattern); + } + if (end_angle < HB_2_PI) + { + c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.; + c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.; + c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.; + c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + end_angle, &c, + HB_2_PI, &c, + pattern); + } + } + return; + } + + assert (start_angle != end_angle); + + /* handle directions */ + if (end_angle < start_angle) + { + hb_swap (start_angle, end_angle); + + for (unsigned i = 0; i < n_stops - 1 - i; i++) + hb_swap (stops[i], stops[n_stops - 1 - i]); + for (unsigned i = 0; i < n_stops; i++) + stops[i].offset = 1 - stops[i].offset; + } + + if (n_stops > PREALLOCATED_COLOR_STOPS) + { + angles = (float *) hb_malloc (sizeof (float) * n_stops); + colors = (hb_cairo_color_t *) hb_malloc (sizeof (hb_cairo_color_t) * n_stops); + if (unlikely (!angles || !colors)) + { + hb_free (angles); + hb_free (colors); + return; + } + } + + for (unsigned i = 0; i < n_stops; i++) + { + angles[i] = start_angle + stops[i].offset * (end_angle - start_angle); + colors[i].r = hb_color_get_red (stops[i].color) / 255.; + colors[i].g = hb_color_get_green (stops[i].color) / 255.; + colors[i].b = hb_color_get_blue (stops[i].color) / 255.; + colors[i].a = hb_color_get_alpha (stops[i].color) / 255.; + } + + if (extend == CAIRO_EXTEND_PAD) + { + unsigned pos; + + color0 = colors[0]; + for (pos = 0; pos < n_stops; pos++) + { + if (angles[pos] >= 0) + { + if (pos > 0) + { + float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + _hb_cairo_interpolate_colors (&colors[pos-1], &colors[pos], k, &color0); + } + break; + } + } + if (pos == n_stops) + { + /* everything is below 0 */ + color0 = colors[n_stops-1]; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0., &color0, + HB_2_PI, &color0, + pattern); + goto done; + } + + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0., &color0, + angles[pos], &colors[pos], + pattern); + + for (pos++; pos < n_stops; pos++) + { + if (angles[pos] <= HB_2_PI) + { + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + angles[pos - 1], &colors[pos-1], + angles[pos], &colors[pos], + pattern); + } + else + { + float k = (HB_2_PI - angles[pos - 1]) / (angles[pos] - angles[pos - 1]); + _hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1); + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + angles[pos - 1], &colors[pos - 1], + HB_2_PI, &color1, + pattern); + break; + } + } + + if (pos == n_stops) + { + /* everything is below 2*M_PI */ + color0 = colors[n_stops - 1]; + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + angles[n_stops - 1], &color0, + HB_2_PI, &color0, + pattern); + goto done; + } + } + else + { + int k; + float span; + + span = angles[n_stops - 1] - angles[0]; + k = 0; + if (angles[0] >= 0) + { + float ss = angles[0]; + while (ss > 0) + { + if (span > 0) + { + ss -= span; + k--; + } + else + { + ss += span; + k++; + } + } + } + else if (angles[0] < 0) + { + float ee = angles[n_stops - 1]; + while (ee < 0) + { + if (span > 0) + { + ee += span; + k++; + } + else + { + ee -= span; + k--; + } + } + } + + //assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span); + span = fabs (span); + + for (signed l = k; l < 1000; l++) + { + for (unsigned i = 1; i < n_stops; i++) + { + float a0, a1; + hb_cairo_color_t *c0, *c1; + + if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT)) + { + a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span; + a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span; + c0 = &colors[n_stops - 1 - (i - 1)]; + c1 = &colors[n_stops - 1 - i]; + } + else + { + a0 = angles[i-1] + l * span; + a1 = angles[i] + l * span; + c0 = &colors[i-1]; + c1 = &colors[i]; + } + + if (a1 < 0) + continue; + if (a0 < 0) + { + hb_cairo_color_t color; + float f = (0 - a0)/(a1 - a0); + _hb_cairo_interpolate_colors (c0, c1, f, &color); + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + 0, &color, + a1, c1, + pattern); + } + else if (a1 >= HB_2_PI) + { + hb_cairo_color_t color; + float f = (HB_2_PI - a0)/(a1 - a0); + _hb_cairo_interpolate_colors (c0, c1, f, &color); + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + a0, c0, + HB_2_PI, &color, + pattern); + goto done; + } + else + { + _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius, + a0, c0, + a1, c1, + pattern); + } + } + } + } + +done: + + if (angles != angles_) + hb_free (angles); + if (colors != colors_) + hb_free (colors); +} + +void +_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float cx, float cy, + float start_angle, + float end_angle) +{ + cairo_t *cr = c->cr; + + unsigned int len = PREALLOCATED_COLOR_STOPS; + hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS]; + hb_color_stop_t *stops = stops_; + cairo_extend_t extend; + double x1, y1, x2, y2; + float max_x, max_y, radius; + cairo_pattern_t *pattern; + + if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops))) + return; + + hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop); + + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + max_x = (float) hb_max ((x1 - (double) cx) * (x1 - (double) cx), (x2 - (double) cx) * (x2 - (double) cx)); + max_y = (float) hb_max ((y1 - (double) cy) * (y1 - (double) cy), (y2 - (double) cy) * (y2 - (double) cy)); + radius = sqrtf (max_x + max_y); + + extend = hb_cairo_extend (hb_color_line_get_extend (color_line)); + pattern = cairo_pattern_create_mesh (); + + _hb_cairo_add_sweep_gradient_patches (stops, len, extend, cx, cy, + radius, start_angle, end_angle, pattern); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + if (stops != stops_) + hb_free (stops); +} + +#endif diff --git a/third_party/harfbuzz-ng/src/src/hb-cairo-utils.hh b/third_party/harfbuzz-ng/src/src/hb-cairo-utils.hh new file mode 100644 index 000000000000..a26bf59d9189 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-cairo-utils.hh @@ -0,0 +1,107 @@ +/* + * Copyright © 2022 Red Hat, 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): Matthias Clasen + */ + +#ifndef HB_CAIRO_UTILS_H +#define HB_CAIRO_UTILS_H + +#include "hb.hh" +#include "hb-cairo.h" + + +typedef struct +{ + cairo_scaled_font_t *scaled_font; + cairo_t *cr; + hb_map_t *color_cache; +} hb_cairo_context_t; + +static inline cairo_operator_t +_hb_paint_composite_mode_to_cairo (hb_paint_composite_mode_t mode) +{ + switch (mode) + { + case HB_PAINT_COMPOSITE_MODE_CLEAR: return CAIRO_OPERATOR_CLEAR; + case HB_PAINT_COMPOSITE_MODE_SRC: return CAIRO_OPERATOR_SOURCE; + case HB_PAINT_COMPOSITE_MODE_DEST: return CAIRO_OPERATOR_DEST; + case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return CAIRO_OPERATOR_OVER; + case HB_PAINT_COMPOSITE_MODE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER; + case HB_PAINT_COMPOSITE_MODE_SRC_IN: return CAIRO_OPERATOR_IN; + case HB_PAINT_COMPOSITE_MODE_DEST_IN: return CAIRO_OPERATOR_DEST_IN; + case HB_PAINT_COMPOSITE_MODE_SRC_OUT: return CAIRO_OPERATOR_OUT; + case HB_PAINT_COMPOSITE_MODE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT; + case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: return CAIRO_OPERATOR_ATOP; + case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP; + case HB_PAINT_COMPOSITE_MODE_XOR: return CAIRO_OPERATOR_XOR; + case HB_PAINT_COMPOSITE_MODE_PLUS: return CAIRO_OPERATOR_ADD; + case HB_PAINT_COMPOSITE_MODE_SCREEN: return CAIRO_OPERATOR_SCREEN; + case HB_PAINT_COMPOSITE_MODE_OVERLAY: return CAIRO_OPERATOR_OVERLAY; + case HB_PAINT_COMPOSITE_MODE_DARKEN: return CAIRO_OPERATOR_DARKEN; + case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN; + case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE; + case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN; + case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT; + case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT; + case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE; + case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION; + case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY; + case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE; + case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION; + case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR; + case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY; + default: return CAIRO_OPERATOR_CLEAR; + } +} + +HB_INTERNAL hb_bool_t +_hb_cairo_paint_glyph_image (hb_cairo_context_t *c, + hb_blob_t *blob, + unsigned width, + unsigned height, + hb_tag_t format, + float slant, + hb_glyph_extents_t *extents); + +HB_INTERNAL void +_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, + float x1, float y1, + float x2, float y2); + +HB_INTERNAL void +_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, float r0, + float x1, float y1, float r1); + +HB_INTERNAL void +_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c, + hb_color_line_t *color_line, + float x0, float y0, + float start_angle, float end_angle); + + +#endif /* HB_CAIRO_UTILS_H */ diff --git a/third_party/harfbuzz-ng/src/src/hb-cairo.cc b/third_party/harfbuzz-ng/src/src/hb-cairo.cc new file mode 100644 index 000000000000..f005afd17e78 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-cairo.cc @@ -0,0 +1,1010 @@ +/* + * Copyright © 2022 Red Hat, 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): Matthias Clasen + */ + +#include "hb.hh" + +#ifdef HAVE_CAIRO + +#include "hb-cairo.h" + +#include "hb-cairo-utils.hh" + +#include "hb-machinery.hh" +#include "hb-utf.hh" + + +/** + * SECTION:hb-cairo + * @title: hb-cairo + * @short_description: Cairo integration + * @include: hb-cairo.h + * + * Functions for using HarfBuzz with the cairo library. + * + * HarfBuzz supports using cairo for rendering. + **/ + +static void +hb_cairo_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_move_to (cr, (double) to_x, (double) to_y); +} + +static void +hb_cairo_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_line_to (cr, (double) to_x, (double) to_y); +} + +static void +hb_cairo_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_curve_to (cr, + (double) control1_x, (double) control1_y, + (double) control2_x, (double) control2_y, + (double) to_x, (double) to_y); +} + +static void +hb_cairo_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st HB_UNUSED, + void *user_data HB_UNUSED) +{ + cairo_t *cr = (cairo_t *) draw_data; + + cairo_close_path (cr); +} + +static inline void free_static_cairo_draw_funcs (); + +static struct hb_cairo_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t +{ + static hb_draw_funcs_t *create () + { + hb_draw_funcs_t *funcs = hb_draw_funcs_create (); + + hb_draw_funcs_set_move_to_func (funcs, hb_cairo_move_to, nullptr, nullptr); + hb_draw_funcs_set_line_to_func (funcs, hb_cairo_line_to, nullptr, nullptr); + hb_draw_funcs_set_cubic_to_func (funcs, hb_cairo_cubic_to, nullptr, nullptr); + hb_draw_funcs_set_close_path_func (funcs, hb_cairo_close_path, nullptr, nullptr); + + hb_draw_funcs_make_immutable (funcs); + + hb_atexit (free_static_cairo_draw_funcs); + + return funcs; + } +} static_cairo_draw_funcs; + +static inline +void free_static_cairo_draw_funcs () +{ + static_cairo_draw_funcs.free_instance (); +} + +static hb_draw_funcs_t * +hb_cairo_draw_get_funcs () +{ + return static_cairo_draw_funcs.get_unconst (); +} + + +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + +static void +hb_cairo_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + float xx, float yx, + float xy, float yy, + float dx, float dy, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_matrix_t m; + + cairo_save (cr); + cairo_matrix_init (&m, (double) xx, (double) yx, + (double) xy, (double) yy, + (double) dx, (double) dy); + cairo_transform (cr, &m); +} + +static void +hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_restore (cr); +} + +static void +hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_codepoint_t glyph, + hb_font_t *font, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_new_path (cr); + hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr); + cairo_close_path (cr); + cairo_clip (cr); +} + +static void +hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + float xmin, float ymin, float xmax, float ymax, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_rectangle (cr, + (double) xmin, (double) ymin, + (double) (xmax - xmin), (double) (ymax - ymin)); + cairo_clip (cr); +} + +static void +hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_restore (cr); +} + +static void +hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_save (cr); + cairo_push_group (cr); +} + +static void +hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_paint_composite_mode_t mode, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode)); + cairo_paint (cr); + + cairo_restore (cr); +} + +static void +hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_bool_t use_foreground, + hb_color_t color, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + + if (use_foreground) + { +#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE + double r, g, b, a; + cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font); + if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS) + cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.); + else +#endif + cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.); + } + else + cairo_set_source_rgba (cr, + hb_color_get_red (color) / 255., + hb_color_get_green (color) / 255., + hb_color_get_blue (color) / 255., + hb_color_get_alpha (color) / 255.); + cairo_paint (cr); +} + +static hb_bool_t +hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_blob_t *blob, + unsigned width, + unsigned height, + hb_tag_t format, + float slant, + hb_glyph_extents_t *extents, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents); +} + +static void +hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line, + float x0, float y0, + float x1, float y1, + float x2, float y2, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + _hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2); +} + +static void +hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line, + float x0, float y0, float r0, + float x1, float y1, float r1, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + _hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1); +} + +static void +hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED, + void *paint_data, + hb_color_line_t *color_line, + float x0, float y0, + float start_angle, float end_angle, + void *user_data HB_UNUSED) +{ + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + + _hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle); +} + +static const cairo_user_data_key_t color_cache_key = {0}; + +static void +_hb_cairo_destroy_map (void *p) +{ + hb_map_destroy ((hb_map_t *) p); +} + +static hb_bool_t +hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs, + void *paint_data, + unsigned int color_index, + hb_color_t *color, + void *user_data HB_UNUSED) +{ +#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR + hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data; + cairo_t *cr = c->cr; + +#define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF) + + hb_map_t *color_cache = c->color_cache; + hb_codepoint_t *v; + if (likely (color_cache && color_cache->has (color_index, &v))) + { + if (*v == HB_DEADBEEF) + return false; + *color = *v; + return true; + } + + cairo_font_options_t *options; + double red, green, blue, alpha; + + options = cairo_font_options_create (); + cairo_get_font_options (cr, options); + if (CAIRO_STATUS_SUCCESS == + cairo_font_options_get_custom_palette_color (options, color_index, + &red, &green, &blue, &alpha)) + { + cairo_font_options_destroy (options); + *color = HB_COLOR (round (255 * blue), + round (255 * green), + round (255 * red), + round (255 * alpha)); + + if (likely (color_cache && *color != HB_DEADBEEF)) + color_cache->set (color_index, *color); + + return true; + } + cairo_font_options_destroy (options); + + if (likely (color_cache)) + color_cache->set (color_index, HB_DEADBEEF); + +#undef HB_DEADBEEF + +#endif + + return false; +} + +static inline void free_static_cairo_paint_funcs (); + +static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t +{ + static hb_paint_funcs_t *create () + { + hb_paint_funcs_t *funcs = hb_paint_funcs_create (); + + hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr); + hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr); + hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr); + hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr); + hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr); + hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr); + hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr); + hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr); + hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr); + hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr); + hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr); + hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr); + hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr); + + hb_paint_funcs_make_immutable (funcs); + + hb_atexit (free_static_cairo_paint_funcs); + + return funcs; + } +} static_cairo_paint_funcs; + +static inline +void free_static_cairo_paint_funcs () +{ + static_cairo_paint_funcs.free_instance (); +} + +static hb_paint_funcs_t * +hb_cairo_paint_get_funcs () +{ + return static_cairo_paint_funcs.get_unconst (); +} +#endif + +static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0}; +static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0}; + +static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); } +static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); } + +static cairo_status_t +hb_cairo_init_scaled_font (cairo_scaled_font_t *scaled_font, + cairo_t *cr HB_UNUSED, + cairo_font_extents_t *extents) +{ + cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font); + + hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_font_user_data_key); + + if (!font) + { + hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_face_user_data_key); + font = hb_font_create (face); + +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0) + cairo_font_options_t *font_options = cairo_font_options_create (); + + // Set variations + cairo_scaled_font_get_font_options (scaled_font, font_options); + const char *variations = cairo_font_options_get_variations (font_options); + hb_vector_t vars; + const char *p = variations; + while (p && *p) + { + const char *end = strpbrk ((char *) p, ", "); + hb_variation_t var; + if (hb_variation_from_string (p, end ? end - p : -1, &var)) + vars.push (var); + p = end ? end + 1 : nullptr; + } + hb_font_set_variations (font, &vars[0], vars.length); + + cairo_font_options_destroy (font_options); +#endif + + // Set scale; Note: should NOT set slant, or we'll double-slant. + unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face); + if (scale_factor) + { + cairo_matrix_t font_matrix; + cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix); + hb_font_set_scale (font, + round (font_matrix.xx * scale_factor), + round (font_matrix.yy * scale_factor)); + } + + auto *init_func = (hb_cairo_font_init_func_t) + cairo_font_face_get_user_data (font_face, + &hb_cairo_font_init_func_user_data_key); + if (init_func) + { + void *user_data = cairo_font_face_get_user_data (font_face, + &hb_cairo_font_init_user_data_user_data_key); + font = init_func (font, scaled_font, user_data); + } + + hb_font_make_immutable (font); + } + + cairo_scaled_font_set_user_data (scaled_font, + &hb_cairo_font_user_data_key, + (void *) hb_font_reference (font), + hb_cairo_font_destroy); + + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + + hb_font_extents_t hb_extents; + hb_font_get_h_extents (font, &hb_extents); + + extents->ascent = (double) hb_extents.ascender / y_scale; + extents->descent = (double) -hb_extents.descender / y_scale; + extents->height = extents->ascent + extents->descent; + +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + hb_map_t *color_cache = hb_map_create (); + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font, + &color_cache_key, + color_cache, + _hb_cairo_destroy_map))) + hb_map_destroy (color_cache); +#endif + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +hb_cairo_text_to_glyphs (cairo_scaled_font_t *scaled_font, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, + &hb_cairo_font_user_data_key); + + hb_buffer_t *buffer = hb_buffer_create (); + hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len); + hb_buffer_guess_segment_properties (buffer); + hb_shape (font, buffer, nullptr, 0); + + hb_cairo_glyphs_from_buffer (buffer, + true, + font->x_scale, font->y_scale, + 0., 0., + utf8, utf8_len, + glyphs, (unsigned *) num_glyphs, + clusters, (unsigned *) num_clusters, + cluster_flags); + + hb_buffer_destroy (buffer); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +hb_cairo_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents) +{ + hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, + &hb_cairo_font_user_data_key); + + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + cairo_scale (cr, +1./x_scale, -1./y_scale); + + hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr); + + cairo_fill (cr); + + return CAIRO_STATUS_SUCCESS; +} + +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + +static cairo_status_t +hb_cairo_render_color_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents) +{ + hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, + &hb_cairo_font_user_data_key); + + unsigned int palette = 0; +#ifdef CAIRO_COLOR_PALETTE_DEFAULT + cairo_font_options_t *options = cairo_font_options_create (); + cairo_scaled_font_get_font_options (scaled_font, options); + palette = cairo_font_options_get_color_palette (options); + cairo_font_options_destroy (options); +#endif + + hb_color_t color = HB_COLOR (0, 0, 0, 255); + hb_position_t x_scale, y_scale; + hb_font_get_scale (font, &x_scale, &y_scale); + cairo_scale (cr, +1./x_scale, -1./y_scale); + + hb_cairo_context_t c; + c.scaled_font = scaled_font; + c.cr = cr; + c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key); + + hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color); + + + return CAIRO_STATUS_SUCCESS; +} + +#endif + +static cairo_font_face_t * +user_font_face_create (hb_face_t *face) +{ + cairo_font_face_t *cairo_face; + + cairo_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font); + cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs); + cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph); +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face)) + cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph); +#endif + + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face, + &hb_cairo_face_user_data_key, + (void *) hb_face_reference (face), + hb_cairo_face_destroy))) + hb_face_destroy (face); + + return cairo_face; +} + +/** + * hb_cairo_font_face_create_for_font: + * @font: a #hb_font_t + * + * Creates a #cairo_font_face_t for rendering text according + * to @font. + * + * Note that the scale of @font does not affect the rendering, + * but the variations and slant that are set on @font do. + * + * Returns: (transfer full): a newly created #cairo_font_face_t + * + * Since: 7.0.0 + */ +cairo_font_face_t * +hb_cairo_font_face_create_for_font (hb_font_t *font) +{ + hb_font_make_immutable (font); + + auto *cairo_face = user_font_face_create (font->face); + + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face, + &hb_cairo_font_user_data_key, + (void *) hb_font_reference (font), + hb_cairo_font_destroy))) + hb_font_destroy (font); + + return cairo_face; +} + +/** + * hb_cairo_font_face_get_font: + * @font_face: a #cairo_font_face_t + * + * Gets the #hb_font_t that @font_face was created from. + * + * Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from + * + * Since: 7.0.0 + */ +hb_font_t * +hb_cairo_font_face_get_font (cairo_font_face_t *font_face) +{ + return (hb_font_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_font_user_data_key); +} + +/** + * hb_cairo_font_face_create_for_face: + * @face: a #hb_face_t + * + * Creates a #cairo_font_face_t for rendering text according + * to @face. + * + * Returns: (transfer full): a newly created #cairo_font_face_t + * + * Since: 7.0.0 + */ +cairo_font_face_t * +hb_cairo_font_face_create_for_face (hb_face_t *face) +{ + hb_face_make_immutable (face); + + return user_font_face_create (face); +} + +/** + * hb_cairo_font_face_get_face: + * @font_face: a #cairo_font_face_t + * + * Gets the #hb_face_t associated with @font_face. + * + * Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face + * + * Since: 7.0.0 + */ +hb_face_t * +hb_cairo_font_face_get_face (cairo_font_face_t *font_face) +{ + return (hb_face_t *) cairo_font_face_get_user_data (font_face, + &hb_cairo_face_user_data_key); +} + +/** + * hb_cairo_font_face_set_font_init_func: + * @font_face: a #cairo_font_face_t + * @func: The virtual method to use + * @user_data: user data accompanying the method + * @destroy: function to call when @user_data is not needed anymore + * + * Set the virtual method to be called when a cairo + * face created using hb_cairo_font_face_create_for_face() + * creates an #hb_font_t for a #cairo_scaled_font_t. + * + * Since: 7.0.0 + */ +void +hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face, + hb_cairo_font_init_func_t func, + void *user_data, + hb_destroy_func_t destroy) +{ + cairo_font_face_set_user_data (font_face, + &hb_cairo_font_init_func_user_data_key, + (void *) func, + nullptr); + if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face, + &hb_cairo_font_init_user_data_user_data_key, + (void *) user_data, + destroy)) && destroy) + { + destroy (user_data); + cairo_font_face_set_user_data (font_face, + &hb_cairo_font_init_func_user_data_key, + nullptr, + nullptr); + } +} + +/** + * hb_cairo_scaled_font_get_font: + * @scaled_font: a #cairo_scaled_font_t + * + * Gets the #hb_font_t associated with @scaled_font. + * + * Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font + * + * Since: 7.0.0 + */ +hb_font_t * +hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font) +{ + return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key); +} + + +/** + * hb_cairo_font_face_set_scale_factor: + * @scale_factor: The scale factor to use. See below + * @font_face: a #cairo_font_face_t + * + * Sets the scale factor of the @font_face. Default scale + * factor is zero. + * + * When a #cairo_font_face_t is created from a #hb_face_t using + * hb_cairo_font_face_create_for_face(), such face will create + * #hb_font_t objects during scaled-font creation. The scale + * factor defines how the scale set on such #hb_font_t objects + * relates to the font-matrix (as such font size) of the cairo + * scaled-font. + * + * If the scale-factor is zero (default), then the scale of the + * #hb_font_t object will be left at default, which is the UPEM + * value of the respective #hb_face_t. + * + * If the scale-factor is set to non-zero, then the X and Y scale + * of the #hb_font_t object will be respectively set to the + * @scale_factor times the xx and yy elements of the scale-matrix + * of the cairo scaled-font being created. + * + * When using the hb_cairo_glyphs_from_buffer() API to convert the + * HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t, + * if the scale-factor was non-zero, you can pass it directly to + * that API as both X and Y scale factors. + * + * If the scale-factor was zero however, or the cairo face was + * created using the alternative constructor + * hb_cairo_font_face_create_for_font(), you need to calculate the + * correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer() + * by dividing the #hb_font_t X/Y scale-factors by the + * cairo scaled-font's scale-matrix XX/YY components respectively + * and use those values. Or if you know that relationship offhand + * (because you set the scale of the #hb_font_t yourself), use + * the conversion rate involved. + * + * Since: 7.0.0 + */ +void +hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face, + unsigned int scale_factor) +{ + cairo_font_face_set_user_data (font_face, + &hb_cairo_scale_factor_user_data_key, + (void *) (uintptr_t) scale_factor, + nullptr); +} + +/** + * hb_cairo_font_face_get_scale_factor: + * @font_face: a #cairo_font_face_t + * + * Gets the scale factor set on the @font_face. Defaults to zero. + * See hb_cairo_font_face_set_scale_factor() for details. + * + * Returns: the scale factor of @font_face + * + * Since: 7.0.0 + */ +unsigned int +hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face) +{ + return (unsigned int) (uintptr_t) + cairo_font_face_get_user_data (font_face, + &hb_cairo_scale_factor_user_data_key); +} + + +/** + * hb_cairo_glyphs_from_buffer: + * @buffer: a #hb_buffer_t containing glyphs + * @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters + * @x_scale_factor: scale factor to divide #hb_position_t Y values by + * @y_scale_factor: scale factor to divide #hb_position_t X values by + * @x: X position to place first glyph + * @y: Y position to place first glyph + * @utf8: (nullable): the text that was shaped in @buffer + * @utf8_len: the length of @utf8 in bytes + * @glyphs: (out): return location for an array of #cairo_glyph_t + * @num_glyphs: (inout): return location for the length of @glyphs + * @clusters: (out) (nullable): return location for an array of cluster positions + * @num_clusters: (inout) (nullable): return location for the length of @clusters + * @cluster_flags: (out) (nullable): return location for cluster flags + * + * Extracts information from @buffer in a form that can be + * passed to cairo_show_text_glyphs() or cairo_show_glyphs(). + * This API is modeled after cairo_scaled_font_text_to_glyphs() and + * cairo_user_scaled_font_text_to_glyphs_func_t. + * + * The @num_glyphs argument should be preset to the number of glyph entries available + * in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of + * @num_glyphs must be zero. If the provided glyph array is too short for + * the conversion (or for convenience), a new glyph array may be allocated + * using cairo_glyph_allocate() and placed in @glyphs. Upon return, + * @num_glyphs should contain the number of generated glyphs. If the value + * @glyphs points at has changed after the call, the caller will free the + * allocated glyph array using cairo_glyph_free(). The caller will also free + * the original value of @glyphs, so this function shouldn't do so. + * + * If @clusters is not `NULL`, then @num_clusters and @cluster_flags + * should not be either, and @utf8 must be provided, and cluster + * mapping will be computed. The semantics of how + * cluster array allocation works is similar to the glyph array. That is, + * if @clusters initially points to a non-`NULL` value, that array may be used + * as a cluster buffer, and @num_clusters points to the number of cluster + * entries available there. If the provided cluster array is too short for + * the conversion (or for convenience), a new cluster array may be allocated + * using cairo_text_cluster_allocate() and placed in @clusters. In this case, + * the original value of @clusters will still be freed by the caller. Upon + * return, @num_clusters will contain the number of generated clusters. + * If the value @clusters points at has changed after the call, the caller + * will free the allocated cluster array using cairo_text_cluster_free(). + * + * See hb_cairo_font_face_set_scale_factor() for the details of + * the @scale_factor argument. + * + * The returned @glyphs vector actually has `@num_glyphs + 1` entries in + * it and the x,y values of the extra entry at the end add up the advance + * x,y of all the glyphs in the @buffer. + * + * Since: 7.0.0 + */ +void +hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, + hb_bool_t utf8_clusters, + double x_scale_factor, + double y_scale_factor, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + unsigned int *num_glyphs, + cairo_text_cluster_t **clusters, + unsigned int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + if (utf8 && utf8_len < 0) + utf8_len = strlen (utf8); + + unsigned orig_num_glyphs = *num_glyphs; + *num_glyphs = hb_buffer_get_length (buffer); + hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr); + hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr); + if (orig_num_glyphs < *num_glyphs + 1) + *glyphs = cairo_glyph_allocate (*num_glyphs + 1); + + if (clusters && utf8) + { + unsigned orig_num_clusters = *num_clusters; + *num_clusters = *num_glyphs ? 1 : 0; + for (unsigned int i = 1; i < *num_glyphs; i++) + if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) + (*num_clusters)++; + if (orig_num_clusters < *num_clusters) + *clusters = cairo_text_cluster_allocate (*num_clusters); + } + + double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.; + double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.; + hb_position_t hx = 0, hy = 0; + int i; + for (i = 0; i < (int) *num_glyphs; i++) + { + (*glyphs)[i].index = hb_glyph[i].codepoint; + (*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale; + (*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale; + hx += hb_position->x_advance; + hy += -hb_position->y_advance; + + hb_position++; + } + (*glyphs)[i].index = -1; + (*glyphs)[i].x = round (hx * x_scale); + (*glyphs)[i].y = round (hy * y_scale); + + if (clusters && *num_clusters && utf8) + { + memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0])); + hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer)); + *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0; + unsigned int cluster = 0; + const char *start = utf8, *end; + (*clusters)[cluster].num_glyphs++; + if (backward) + { + for (i = *num_glyphs - 2; i >= 0; i--) + { + if (hb_glyph[i].cluster != hb_glyph[i+1].cluster) + { + assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster); + if (utf8_clusters) + end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster; + else + end = (const char *) hb_utf_offset_to_pointer ((const uint8_t *) start, + (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster)); + (*clusters)[cluster].num_bytes = end - start; + start = end; + cluster++; + } + (*clusters)[cluster].num_glyphs++; + } + (*clusters)[cluster].num_bytes = utf8 + utf8_len - start; + } + else + { + for (i = 1; i < (int) *num_glyphs; i++) + { + if (hb_glyph[i].cluster != hb_glyph[i-1].cluster) + { + assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster); + if (utf8_clusters) + end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster; + else + end = (const char *) hb_utf_offset_to_pointer ((const uint8_t *) start, + (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster)); + (*clusters)[cluster].num_bytes = end - start; + start = end; + cluster++; + } + (*clusters)[cluster].num_glyphs++; + } + (*clusters)[cluster].num_bytes = utf8 + utf8_len - start; + } + } + else if (num_clusters) + *num_clusters = 0; +} + +#endif diff --git a/third_party/harfbuzz-ng/src/src/hb-cairo.h b/third_party/harfbuzz-ng/src/src/hb-cairo.h new file mode 100644 index 000000000000..21e284c8f93a --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-cairo.h @@ -0,0 +1,99 @@ +/* + * Copyright © 2022 Red Hat, 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): Matthias Clasen + */ + +#ifndef HB_CAIRO_H +#define HB_CAIRO_H + +#include "hb.h" + +#include + +HB_BEGIN_DECLS + +HB_EXTERN cairo_font_face_t * +hb_cairo_font_face_create_for_font (hb_font_t *font); + +HB_EXTERN hb_font_t * +hb_cairo_font_face_get_font (cairo_font_face_t *font_face); + +HB_EXTERN cairo_font_face_t * +hb_cairo_font_face_create_for_face (hb_face_t *face); + +HB_EXTERN hb_face_t * +hb_cairo_font_face_get_face (cairo_font_face_t *font_face); + +/** + * hb_cairo_font_init_func_t: + * @font: The #hb_font_t being created + * @scaled_font: The respective #cairo_scaled_font_t + * @user_data: User data accompanying this method + * + * The type of a virtual method to be called when a cairo + * face created using hb_cairo_font_face_create_for_face() + * creates an #hb_font_t for a #cairo_scaled_font_t. + * + * Return value: the #hb_font_t value to use; in most cases same as @font + * + * Since: 7.0.0 + */ +typedef hb_font_t * (*hb_cairo_font_init_func_t) (hb_font_t *font, + cairo_scaled_font_t *scaled_font, + void *user_data); + +HB_EXTERN void +hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face, + hb_cairo_font_init_func_t func, + void *user_data, + hb_destroy_func_t destroy); + +HB_EXTERN hb_font_t * +hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font); + +HB_EXTERN void +hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face, + unsigned int scale_factor); + +HB_EXTERN unsigned int +hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face); + +HB_EXTERN void +hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer, + hb_bool_t utf8_clusters, + double x_scale_factor, + double y_scale_factor, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + unsigned int *num_glyphs, + cairo_text_cluster_t **clusters, + unsigned int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + +HB_END_DECLS + +#endif /* HB_CAIRO_H */ diff --git a/third_party/harfbuzz-ng/src/src/hb-cff-interp-common.hh b/third_party/harfbuzz-ng/src/src/hb-cff-interp-common.hh index 5c2cb060a412..949bfebf9bec 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cff-interp-common.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cff-interp-common.hh @@ -284,65 +284,56 @@ struct UnsizedByteStr : UnsizedArrayOf /* 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 = hb_ubytes_t (); - offset = 0; - error = false; - } - - void fini () {} + byte_str_ref_t () + : str () {} byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0) - : str (str_), offset (offset_), error (false) {} + : str (str_) { set_offset (offset_); } void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0) { str = str_; - offset = offset_; - error = false; + set_offset (offset_); } const unsigned char& operator [] (int i) { - if (unlikely ((unsigned int) (offset + i) >= str.length)) + if (unlikely ((unsigned int) (get_offset () + i) >= str.length)) { set_error (); return Null (unsigned char); } - return str[offset + i]; + return str.arrayZ[get_offset () + i]; } + unsigned char head_unchecked () const { return str.arrayZ[get_offset ()]; } + /* Conversion to hb_ubytes_t */ - operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); } + operator hb_ubytes_t () const { return str.sub_array (get_offset ()); } hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const { return str.sub_array (offset_, len_); } bool avail (unsigned int count=1) const - { return (!in_error () && offset + count <= str.length); } + { return get_offset () + count <= str.length; } 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 (); - } + /* Automatically puts us in error if count is out-of-range. */ + set_offset (get_offset () + count); } - void set_error () { error = true; } - bool in_error () const { return error; } + /* We (ab)use ubytes backwards_length as a cursor (called offset), + * as well as to store error condition. */ - hb_ubytes_t str; - unsigned int offset; /* beginning of the sub-string within str */ + unsigned get_offset () const { return str.backwards_length; } + void set_offset (unsigned offset) { str.backwards_length = offset; } + + void set_error () { str.backwards_length = str.length + 1; } + bool in_error () const { return str.backwards_length > str.length; } + + unsigned total_size () const { return str.length; } protected: - bool error; + hb_ubytes_t str; }; using byte_str_array_t = hb_vector_t; @@ -491,8 +482,15 @@ struct arg_stack_t : cff_stack_t /* an operator prefixed by its operands in a byte string */ struct op_str_t { - hb_ubytes_t str; - op_code_t op; + /* This used to have a hb_ubytes_t. Using a pointer and length + * in a particular order, saves 8 bytes in this struct and more + * in our parsed_cs_op_t subclass. */ + + const unsigned char *ptr = nullptr; + + op_code_t op = OpCode_Invalid; + + uint8_t length = 0; }; /* base of OP_SERIALIZER */ @@ -503,9 +501,11 @@ struct op_serializer_t { TRACE_SERIALIZE (this); - HBUINT8 *d = c->allocate_size (opstr.str.length); + unsigned char *d = c->allocate_size (opstr.length); if (unlikely (!d)) return_trace (false); - memcpy (d, &opstr.str[0], opstr.str.length); + /* Faster than hb_memcpy for small strings. */ + for (unsigned i = 0; i < opstr.length; i++) + d[i] = opstr.ptr[i]; return_trace (true); } }; @@ -522,23 +522,17 @@ struct parsed_values_t void alloc (unsigned n) { - values.alloc (n); + values.alloc (n, true); } - 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_array (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) + void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ()) { VAL *val = values.push (v); val->op = op; - val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart); - opStart = str_ref.offset; + auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart); + val->ptr = arr.arrayZ; + val->length = arr.length; + opStart = str_ref.get_offset (); } bool has_op (op_code_t op) const @@ -549,8 +543,7 @@ struct parsed_values_t } 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); } + const VAL &operator [] (unsigned int i) const { return values[i]; } unsigned int opStart; hb_vector_t values; @@ -565,23 +558,23 @@ struct interp_env_t str_ref.reset (str_); } bool in_error () const - { return error || str_ref.in_error () || argStack.in_error (); } + { return str_ref.in_error () || argStack.in_error (); } - void set_error () { error = true; } + void set_error () { str_ref.set_error (); } 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]; + op = (op_code_t) str_ref.head_unchecked (); + str_ref.inc (); if (op == OpCode_escape) { if (unlikely (!str_ref.avail ())) return OpCode_Invalid; - op = Make_OpCode_ESC(str_ref[1]); + op = Make_OpCode_ESC (str_ref.head_unchecked ()); str_ref.inc (); } - str_ref.inc (); return op; } @@ -596,8 +589,6 @@ struct interp_env_t str_ref; arg_stack_t argStack; - protected: - bool error = false; }; using num_interp_env_t = interp_env_t<>; diff --git a/third_party/harfbuzz-ng/src/src/hb-cff-interp-cs-common.hh b/third_party/harfbuzz-ng/src/src/hb-cff-interp-cs-common.hh index f93c83ab4592..f40be51f0d77 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cff-interp-cs-common.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cff-interp-cs-common.hh @@ -57,7 +57,6 @@ struct call_context_t /* call stack */ const unsigned int kMaxCallLimit = 10; -const unsigned int kMaxOps = 10000; struct call_stack_t : cff_stack_t {}; template @@ -882,7 +881,7 @@ struct cs_interpreter_t : interpreter_t { SUPER::env.set_endchar (false); - unsigned max_ops = kMaxOps; + unsigned max_ops = HB_CFF_MAX_OPS; for (;;) { if (unlikely (!--max_ops)) { diff --git a/third_party/harfbuzz-ng/src/src/hb-cff-interp-dict-common.hh b/third_party/harfbuzz-ng/src/src/hb-cff-interp-dict-common.hh index 79fe9b42c5f7..53226b227e9f 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cff-interp-dict-common.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cff-interp-dict-common.hh @@ -35,10 +35,8 @@ 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 init () {} void fini () {} - - number_t single_val; }; typedef dict_val_t num_dict_val_t; diff --git a/third_party/harfbuzz-ng/src/src/hb-cff1-interp-cs.hh b/third_party/harfbuzz-ng/src/src/hb-cff1-interp-cs.hh index b306c2ecc9a9..d8868efa53f9 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cff1-interp-cs.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cff1-interp-cs.hh @@ -38,7 +38,8 @@ typedef biased_subrs_t cff1_biased_subrs_t; struct cff1_cs_interp_env_t : cs_interp_env_t { template - cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) + cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, + const int *coords_=nullptr, unsigned int num_coords_=0) : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { processed_width = false; diff --git a/third_party/harfbuzz-ng/src/src/hb-cff2-interp-cs.hh b/third_party/harfbuzz-ng/src/src/hb-cff2-interp-cs.hh index d0b9e7b08636..915b10cf39a9 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cff2-interp-cs.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cff2-interp-cs.hh @@ -40,20 +40,22 @@ struct blend_arg_t : number_t 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 blends_) + hb_array_t blends_) { numValues = numValues_; valueIndex = valueIndex_; - deltas.resize (numBlends); + unsigned numBlends = blends_.length; + if (unlikely (!deltas.resize_exact (numBlends))) + return; for (unsigned int i = 0; i < numBlends; i++) - deltas[i] = blends_[i]; + deltas.arrayZ[i] = blends_.arrayZ[i]; } bool blending () const { return deltas.length > 0; } void reset_blends () { numValues = valueIndex = 0; - deltas.resize (0); + deltas.shrink (0); } unsigned int numValues; @@ -61,7 +63,6 @@ struct blend_arg_t : number_t hb_vector_t deltas; }; -typedef interp_env_t BlendInterpEnv; typedef biased_subrs_t cff2_biased_subrs_t; template @@ -117,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t region_count = varStore->varStore.get_region_index_count (get_ivs ()); if (do_blend) { - if (unlikely (!scalars.resize (region_count))) + if (unlikely (!scalars.resize_exact (region_count))) SUPER::set_error (); else varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, @@ -154,13 +155,16 @@ struct cff2_cs_interp_env_t : cs_interp_env_t { if (likely (scalars.length == deltas.length)) { - for (unsigned int i = 0; i < scalars.length; i++) - v += (double) scalars[i] * deltas[i].to_real (); + unsigned count = scalars.length; + for (unsigned i = 0; i < count; i++) + v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real (); } } return v; } + bool have_coords () const { return num_coords; } + protected: const int *coords; unsigned int num_coords; @@ -220,7 +224,10 @@ struct cff2_cs_opset_t : cs_opset_t, PAR const hb_array_t blends, unsigned n, unsigned i) { - arg.set_blends (n, i, blends.length, blends); + if (env.have_coords ()) + arg.set_int (round (arg.to_real () + env.blend_deltas (blends))); + else + arg.set_blends (n, i, blends); } template diff --git a/third_party/harfbuzz-ng/src/src/hb-common.cc b/third_party/harfbuzz-ng/src/src/hb-common.cc index daaa7658cc1b..282a8e4d0f61 100644 --- a/third_party/harfbuzz-ng/src/src/hb-common.cc +++ b/third_party/harfbuzz-ng/src/src/hb-common.cc @@ -29,32 +29,6 @@ #include "hb.hh" #include "hb-machinery.hh" -#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE)) -#define HB_NO_SETLOCALE 1 -#endif - -#ifndef HB_NO_SETLOCALE - -#include -#ifdef HAVE_XLOCALE_H -#include // Needed on BSD/OS X for uselocale -#endif - -#ifdef WIN32 -#define hb_locale_t _locale_t -#else -#define hb_locale_t locale_t -#endif -#define hb_setlocale setlocale -#define hb_uselocale uselocale - -#else - -#define hb_locale_t void * -#define hb_setlocale(Category, Locale) "C" -#define hb_uselocale(Locale) ((hb_locale_t) 0) - -#endif /** * SECTION:hb-common @@ -285,7 +259,7 @@ struct hb_language_item_t { lang = (hb_language_t) hb_malloc(len); if (likely (lang)) { - memcpy((unsigned char *) lang, s, len); + hb_memcpy((unsigned char *) lang, s, len); for (unsigned char *p = (unsigned char *) lang; *p; p++) *p = canon_map[*p]; } @@ -379,7 +353,7 @@ hb_language_from_string (const char *str, int len) /* NUL-terminate it. */ char strbuf[64]; len = hb_min (len, (int) sizeof (strbuf) - 1); - memcpy (strbuf, str, len); + hb_memcpy (strbuf, str, len); strbuf[len] = '\0'; item = lang_find_or_insert (strbuf); } @@ -658,6 +632,7 @@ hb_script_get_horizontal_direction (hb_script_t script) case HB_SCRIPT_OLD_HUNGARIAN: case HB_SCRIPT_OLD_ITALIC: case HB_SCRIPT_RUNIC: + case HB_SCRIPT_TIFINAGH: return HB_DIRECTION_INVALID; } @@ -976,7 +951,7 @@ hb_feature_from_string (const char *str, int len, } if (feature) - memset (feature, 0, sizeof (*feature)); + hb_memset (feature, 0, sizeof (*feature)); return false; } @@ -1025,7 +1000,7 @@ hb_feature_to_string (hb_feature_t *feature, } assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); - memcpy (buf, s, len); + hb_memcpy (buf, s, len); buf[len] = '\0'; } @@ -1088,7 +1063,7 @@ hb_variation_from_string (const char *str, int len, } if (variation) - memset (variation, 0, sizeof (*variation)); + hb_memset (variation, 0, sizeof (*variation)); return false; } @@ -1166,7 +1141,7 @@ hb_variation_to_string (hb_variation_t *variation, assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); - memcpy (buf, s, len); + hb_memcpy (buf, s, len); buf[len] = '\0'; } diff --git a/third_party/harfbuzz-ng/src/src/hb-common.h b/third_party/harfbuzz-ng/src/src/hb-common.h index e92feb9898b4..a5da4e76a329 100644 --- a/third_party/harfbuzz-ng/src/src/hb-common.h +++ b/third_party/harfbuzz-ng/src/src/hb-common.h @@ -897,6 +897,32 @@ HB_EXTERN uint8_t hb_color_get_blue (hb_color_t color); #define hb_color_get_blue(color) (((color) >> 24) & 0xFF) +/** + * hb_glyph_extents_t: + * @x_bearing: Distance from the x-origin to the left extremum of the glyph. + * @y_bearing: Distance from the top extremum of the glyph to the y-origin. + * @width: Distance from the left extremum of the glyph to the right extremum. + * @height: Distance from the top extremum of the glyph to the bottom extremum. + * + * Glyph extent values, measured in font units. + * + * Note that @height is negative, in coordinate systems that grow up. + **/ +typedef struct hb_glyph_extents_t { + hb_position_t x_bearing; + hb_position_t y_bearing; + hb_position_t width; + hb_position_t height; +} hb_glyph_extents_t; + +/** + * hb_font_t: + * + * Data type for holding fonts. + * + */ +typedef struct hb_font_t hb_font_t; + HB_END_DECLS #endif /* HB_COMMON_H */ diff --git a/third_party/harfbuzz-ng/src/src/hb-config.hh b/third_party/harfbuzz-ng/src/src/hb-config.hh index 09197c16aa4a..52adaad4384c 100644 --- a/third_party/harfbuzz-ng/src/src/hb-config.hh +++ b/third_party/harfbuzz-ng/src/src/hb-config.hh @@ -35,8 +35,10 @@ #include "config.h" #endif -#ifndef HB_EXPERIMENTAL +#ifndef HB_EXPERIMENTAL_API #define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES #endif #ifdef HB_TINY @@ -79,11 +81,13 @@ #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_PAINT +#define HB_NO_SETLOCALE #define HB_NO_STYLE #define HB_NO_SUBSET_LAYOUT +#define HB_NO_VERTICAL #define HB_NO_VAR #endif @@ -113,6 +117,11 @@ #define HB_IF_NOT_DEPRECATED(x) x #endif +#ifdef HB_NO_SHAPER +#define HB_NO_OT_SHAPE +#define HB_NO_AAT_SHAPE +#endif + #ifdef HB_NO_AAT #define HB_NO_OT_NAME_LANGUAGE_AAT #define HB_NO_AAT_SHAPE @@ -127,6 +136,10 @@ #define HB_NO_SUBSET_CFF #endif +#ifdef HB_NO_DRAW +#define HB_NO_OUTLINE +#endif + #ifdef HB_NO_GETENV #define HB_NO_UNISCRIBE_BUG_COMPATIBLE #endif @@ -159,6 +172,7 @@ #define HB_NO_OT_SHAPER_HEBREW_FALLBACK #define HB_NO_OT_SHAPER_THAI_FALLBACK #define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS +#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI #endif #ifdef NDEBUG diff --git a/third_party/harfbuzz-ng/src/src/hb-coretext.cc b/third_party/harfbuzz-ng/src/src/hb-coretext.cc index 99b33c001e5a..a87cb5cd028f 100644 --- a/third_party/harfbuzz-ng/src/src/hb-coretext.cc +++ b/third_party/harfbuzz-ng/src/src/hb-coretext.cc @@ -347,10 +347,13 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) hb_ot_var_axis_info_t info; unsigned int c = 1; hb_ot_var_get_axis_infos (font->face, i, &c, &info); - CFDictionarySetValue (variations, - CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag), - CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i]) - ); + float v = hb_clamp (font->design_coords[i], info.min_value, info.max_value); + + CFNumberRef tag_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag); + CFNumberRef value_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &v); + CFDictionarySetValue (variations, tag_number, value_number); + CFRelease (tag_number); + CFRelease (value_number); } CFDictionaryRef attributes = @@ -508,7 +511,6 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, buffer->merge_clusters (i - 1, i + 1); } - hb_vector_t feature_records; hb_vector_t range_records; /* @@ -648,7 +650,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } else { active_feature_t *feature = active_features.lsearch (event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ); + active_features.remove_ordered (feature - active_features.arrayZ); } } } diff --git a/third_party/harfbuzz-ng/src/src/hb-cplusplus.hh b/third_party/harfbuzz-ng/src/src/hb-cplusplus.hh index a210ab79605b..531ef1b7c83f 100644 --- a/third_party/harfbuzz-ng/src/src/hb-cplusplus.hh +++ b/third_party/harfbuzz-ng/src/src/hb-cplusplus.hh @@ -160,6 +160,8 @@ HB_DEFINE_VTABLE (map); HB_DEFINE_VTABLE (set); HB_DEFINE_VTABLE (shape_plan); HB_DEFINE_VTABLE (unicode_funcs); +HB_DEFINE_VTABLE (draw_funcs); +HB_DEFINE_VTABLE (paint_funcs); #undef HB_DEFINE_VTABLE diff --git a/third_party/harfbuzz-ng/src/src/hb-debug.hh b/third_party/harfbuzz-ng/src/src/hb-debug.hh index cbe13e5214de..0ac4515fa855 100644 --- a/third_party/harfbuzz-ng/src/src/hb-debug.hh +++ b/third_party/harfbuzz-ng/src/src/hb-debug.hh @@ -113,7 +113,7 @@ _hb_print_func (const char *func) const char *paren = strchr (func, '('); if (paren) func_len = paren - func; - fprintf (stderr, "%.*s", func_len, func); + fprintf (stderr, "%.*s", (int) func_len, func); } } @@ -142,9 +142,9 @@ _hb_debug_msg_va (const char *what, fprintf (stderr, "%-10s", what ? what : ""); if (obj) - fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj); + fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj); else - fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), ""); + fprintf (stderr, " %*s ", (int) (2 * sizeof (void *)), ""); if (indented) { #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ @@ -306,7 +306,7 @@ struct hb_auto_trace_t } _hb_debug_msg (what, obj, func, true, plevel ? *plevel : 1, -1, - "return %s (line %d)", + "return %s (line %u)", hb_printer_t>().print (v), line); if (plevel) --*plevel; plevel = nullptr; @@ -373,6 +373,10 @@ struct hb_no_trace_t { #define HB_DEBUG_FT (HB_DEBUG+0) #endif +#ifndef HB_DEBUG_JUSTIFY +#define HB_DEBUG_JUSTIFY (HB_DEBUG+0) +#endif + #ifndef HB_DEBUG_OBJECT #define HB_DEBUG_OBJECT (HB_DEBUG+0) #endif @@ -396,7 +400,7 @@ struct hb_no_trace_t { #define TRACE_APPLY(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "idx %d gid %u lookup %d", \ + "idx %u gid %u lookup %d", \ c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) #else #define TRACE_APPLY(this) hb_no_trace_t trace @@ -454,7 +458,7 @@ struct hb_no_trace_t { #define TRACE_DISPATCH(this, format) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "format %d", (int) format) + "format %u", (unsigned) format) #else #define TRACE_DISPATCH(this, format) hb_no_trace_t trace #endif diff --git a/third_party/harfbuzz-ng/src/src/hb-deprecated.h b/third_party/harfbuzz-ng/src/src/hb-deprecated.h index 333dc3cd4c35..edacfd064c34 100644 --- a/third_party/harfbuzz-ng/src/src/hb-deprecated.h +++ b/third_party/harfbuzz-ng/src/src/hb-deprecated.h @@ -102,7 +102,8 @@ 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 HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void +HB_DEPRECATED_FOR (hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) +HB_EXTERN 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); diff --git a/third_party/harfbuzz-ng/src/src/hb-directwrite.cc b/third_party/harfbuzz-ng/src/src/hb-directwrite.cc index de05b7d871a1..42764a244b14 100644 --- a/third_party/harfbuzz-ng/src/src/hb-directwrite.cc +++ b/third_party/harfbuzz-ng/src/src/hb-directwrite.cc @@ -251,16 +251,12 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data) 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); + delete data->fontFileLoader; + delete data->fontFileStream; + hb_blob_destroy (data->faceBlob); if (data->dwrite_dll) FreeLibrary (data->dwrite_dll); - if (data) - delete data; + delete data; } diff --git a/third_party/harfbuzz-ng/src/src/hb-draw.cc b/third_party/harfbuzz-ng/src/src/hb-draw.cc index 46797e64e62d..f204f56bc7a4 100644 --- a/third_party/harfbuzz-ng/src/src/hb-draw.cc +++ b/third_party/harfbuzz-ng/src/src/hb-draw.cc @@ -35,6 +35,8 @@ * @include: hb.h * * Functions for drawing (extracting) glyph shapes. + * + * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph(). **/ static void @@ -80,6 +82,56 @@ hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UN void *user_data HB_UNUSED) {} +static bool +_hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs, + bool func_is_null, + void **user_data, + hb_destroy_func_t *destroy) +{ + if (hb_object_is_immutable (dfuncs)) + { + if (*destroy) + (*destroy) (*user_data); + return false; + } + + if (func_is_null) + { + if (*destroy) + (*destroy) (*user_data); + *destroy = nullptr; + *user_data = nullptr; + } + + return true; +} + +static bool +_hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs, + void *user_data, + hb_destroy_func_t destroy) +{ + if (user_data && !dfuncs->user_data) + { + dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); + if (unlikely (!dfuncs->user_data)) + goto fail; + } + if (destroy && !dfuncs->destroy) + { + dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); + if (unlikely (!dfuncs->destroy)) + goto fail; + } + + return true; + +fail: + if (destroy) + (destroy) (user_data); + return false; +} + #define HB_DRAW_FUNC_IMPLEMENT(name) \ \ void \ @@ -88,43 +140,24 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (dfuncs)) \ - return; \ + if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\ + return; \ \ if (dfuncs->destroy && dfuncs->destroy->name) \ dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \ \ - if (user_data && !dfuncs->user_data) \ - { \ - dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); \ - if (unlikely (!dfuncs->user_data)) \ - goto fail; \ - } \ - if (destroy && !dfuncs->destroy) \ - { \ - dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); \ - if (unlikely (!dfuncs->destroy)) \ - goto fail; \ - } \ + if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \ + return; \ \ - if (func) { \ + if (func) \ dfuncs->func.name = func; \ - if (dfuncs->user_data) \ - dfuncs->user_data->name = user_data; \ - if (dfuncs->destroy) \ - dfuncs->destroy->name = destroy; \ - } else { \ + else \ dfuncs->func.name = hb_draw_##name##_nil; \ - if (dfuncs->user_data) \ - dfuncs->user_data->name = nullptr; \ - if (dfuncs->destroy) \ - dfuncs->destroy->name = nullptr; \ - } \ - return; \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + \ + if (dfuncs->user_data) \ + dfuncs->user_data->name = user_data; \ + if (dfuncs->destroy) \ + dfuncs->destroy->name = destroy; \ } HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS @@ -167,13 +200,29 @@ DEFINE_NULL_INSTANCE (hb_draw_funcs_t) = } }; +/** + * hb_draw_funcs_get_empty: + * + * Fetches the singleton empty draw-functions structure. + * + * Return value: (transfer full): The empty draw-functions structure + * + * Since: 7.0.0 + **/ +hb_draw_funcs_t * +hb_draw_funcs_get_empty () +{ + return const_cast (&Null (hb_draw_funcs_t)); +} /** * hb_draw_funcs_reference: (skip) * @dfuncs: draw functions * - * Increases the reference count on @dfuncs by one. This prevents @buffer from - * being destroyed until a matching call to hb_draw_funcs_destroy() is made. + * Increases the reference count on @dfuncs by one. + * + * This prevents @dfuncs from being destroyed until a matching + * call to hb_draw_funcs_destroy() is made. * * Return value: (transfer full): * The referenced #hb_draw_funcs_t. @@ -215,6 +264,49 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) hb_free (dfuncs); } +/** + * hb_draw_funcs_set_user_data: (skip) + * @dfuncs: The draw-functions structure + * @key: The user-data key + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the specified draw-functions structure. + * + * Return value: `true` if success, `false` otherwise + * + * Since: 7.0.0 + **/ +hb_bool_t +hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (dfuncs, key, data, destroy, replace); +} + +/** + * hb_draw_funcs_get_user_data: (skip) + * @dfuncs: The draw-functions structure + * @key: The user-data key to query + * + * Fetches the user-data associated with the specified key, + * attached to the specified draw-functions structure. + * + * Return value: (transfer none): A pointer to the user data + * + * Since: 7.0.0 + **/ +void * +hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (dfuncs, key); +} + /** * hb_draw_funcs_make_immutable: * @dfuncs: draw functions diff --git a/third_party/harfbuzz-ng/src/src/hb-draw.h b/third_party/harfbuzz-ng/src/src/hb-draw.h index c45a53212aef..9ca0b4006e44 100644 --- a/third_party/harfbuzz-ng/src/src/hb-draw.h +++ b/third_party/harfbuzz-ng/src/src/hb-draw.h @@ -92,11 +92,11 @@ typedef struct hb_draw_funcs_t hb_draw_funcs_t; /** * hb_draw_move_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_move_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw * operation. @@ -112,11 +112,11 @@ typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data /** * hb_draw_line_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_line_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw * operation. @@ -132,13 +132,13 @@ typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data /** * hb_draw_quadratic_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @control_x: X component of control point * @control_y: Y component of control point * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_quadratic_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw * operation. @@ -155,7 +155,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw /** * hb_draw_cubic_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @control1_x: X component of first control point * @control1_y: Y component of first control point @@ -163,7 +163,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw * @control2_y: Y component of second control point * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_cubic_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw * operation. @@ -181,9 +181,9 @@ typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_dat /** * hb_draw_close_path_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func() * * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw * operation. @@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs, HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_create (void); +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_get_empty (void); + HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs); HB_EXTERN void hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs); +HB_EXTERN hb_bool_t +hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +HB_EXTERN void * +hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key); + HB_EXTERN void hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); diff --git a/third_party/harfbuzz-ng/src/src/hb-face-builder.cc b/third_party/harfbuzz-ng/src/src/hb-face-builder.cc new file mode 100644 index 000000000000..84b14d28d60b --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-face-builder.cc @@ -0,0 +1,246 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 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. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb.hh" + +#include "hb-face.hh" + +#include "hb-map.hh" +#include "hb-open-file.hh" +#include "hb-serialize.hh" + + +/* + * face-builder: A face that has add_table(). + */ + +struct face_table_info_t +{ + hb_blob_t* data; + signed order; +}; + +struct hb_face_builder_data_t +{ + hb_hashmap_t tables; +}; + +static int compare_entries (const void* pa, const void* pb) +{ + const auto& a = * (const hb_pair_t *) pa; + const auto& b = * (const hb_pair_t *) pb; + + /* Order by blob size first (smallest to largest) and then table tag */ + + if (a.second.order != b.second.order) + return a.second.order < b.second.order ? -1 : +1; + + if (a.second.data->length != b.second.data->length) + return a.second.data->length < b.second.data->length ? -1 : +1; + + return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; +} + +static hb_face_builder_data_t * +_hb_face_builder_data_create () +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_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 (auto info : data->tables.values()) + hb_blob_destroy (info.data); + + data->tables.fini (); + + hb_free (data); +} + +static hb_blob_t * +_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) +{ + + unsigned int table_count = data->tables.get_population (); + unsigned int face_length = table_count * 16 + 12; + + for (auto info : data->tables.values()) + face_length += hb_ceil_to_4 (hb_blob_get_length (info.data)); + + char *buf = (char *) hb_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 (); + + bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' ')) + || data->tables.has (HB_TAG ('C','F','F','2'))); + hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; + + // Sort the tags so that produced face is deterministic. + hb_vector_t> sorted_entries; + data->tables.iter () | hb_sink (sorted_entries); + if (unlikely (sorted_entries.in_error ())) + { + hb_free (buf); + return nullptr; + } + + sorted_entries.qsort (compare_entries); + + bool ret = f->serialize_single (&c, + sfnt_tag, + + sorted_entries.iter() + | hb_map ([&] (hb_pair_t _) { + return hb_pair_t (_.first, _.second.data); + })); + + c.end_serialize (); + + if (unlikely (!ret)) + { + hb_free (buf); + return nullptr; + } + + return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_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); + + return hb_blob_reference (data->tables[tag].data); +} + + +/** + * 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: + * @face: A face object created with hb_face_builder_create() + * @tag: The #hb_tag_t of the table to add + * @blob: The blob containing the table data to add + * + * 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; + + if (tag == HB_MAP_VALUE_INVALID) + return false; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + + hb_blob_t* previous = data->tables.get (tag).data; + if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1})) + { + hb_blob_destroy (blob); + return false; + } + + hb_blob_destroy (previous); + return true; +} + +/** + * hb_face_builder_sort_tables: + * @face: A face object created with hb_face_builder_create() + * @tags: (array zero-terminated=1): ordered list of table tags terminated by + * %HB_TAG_NONE + * + * Set the ordering of tables for serialization. Any tables not + * specified in the tags list will be ordered after the tables in + * tags, ordered by the default sort ordering. + * + * Since: 5.3.0 + **/ +void +hb_face_builder_sort_tables (hb_face_t *face, + const hb_tag_t *tags) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + + // Sort all unspecified tables after any specified tables. + for (auto& info : data->tables.values_ref()) + info.order = (unsigned) -1; + + signed order = 0; + for (const hb_tag_t* tag = tags; + *tag; + tag++) + { + face_table_info_t* info; + if (!data->tables.has (*tag, &info)) continue; + info->order = order++; + } +} diff --git a/third_party/harfbuzz-ng/src/src/hb-face.cc b/third_party/harfbuzz-ng/src/src/hb-face.cc index e7deb31dd835..e340710586c1 100644 --- a/third_party/harfbuzz-ng/src/src/hb-face.cc +++ b/third_party/harfbuzz-ng/src/src/hb-face.cc @@ -33,7 +33,6 @@ #include "hb-open-file.hh" #include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" -#include "hb-map.hh" /** @@ -48,6 +47,12 @@ * More precisely, 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. + * + * A font face can be created from a binary blob using hb_face_create(). + * The face index is used to select a face from a binary blob that contains + * multiple faces. For example, a binary blob that contains both a regular + * and a bold face can be used to create two font faces, one for each face + * index. **/ @@ -198,7 +203,7 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * a face index into that blob. * * The face index is used for blobs of file formats such as TTC and - * and DFont that can contain more than one face. Face indices within + * DFont that can contain more than one face. Face indices within * such collections are zero-based. * * Note: If the blob font format is not a collection, @index @@ -288,6 +293,7 @@ hb_face_destroy (hb_face_t *face) { if (!hb_object_destroy (face)) return; +#ifndef HB_NO_SHAPER for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) { hb_face_t::plan_node_t *next = node->next; @@ -295,6 +301,7 @@ hb_face_destroy (hb_face_t *face) hb_free (node); node = next; } +#endif face->data.fini (); face->table.fini (); @@ -470,6 +477,8 @@ hb_face_get_index (const hb_face_t *face) * * Sets the units-per-em (upem) for a face object to the specified value. * + * This API is used in rare circumstances. + * * Since: 0.9.2 **/ void @@ -486,7 +495,10 @@ hb_face_set_upem (hb_face_t *face, * hb_face_get_upem: * @face: A face object * - * Fetches the units-per-em (upem) value of the specified face object. + * Fetches the units-per-em (UPEM) value of the specified face object. + * + * Typical UPEM values for fonts are 1000, or 2048, but any value + * in between 16 and 16,384 is allowed for OpenType fonts. * * Return value: The upem value of @face * @@ -505,6 +517,8 @@ hb_face_get_upem (const hb_face_t *face) * * Sets the glyph count for a face object to the specified value. * + * This API is used in rare circumstances. + * * Since: 0.9.7 **/ void @@ -579,7 +593,7 @@ hb_face_get_table_tags (const hb_face_t *face, /** * hb_face_collect_unicodes: * @face: A face object - * @out: The set to add Unicode characters to + * @out: (out): The set to add Unicode characters to * * Collects all of the Unicode characters covered by @face and adds * them to the #hb_set_t set @out. @@ -592,10 +606,31 @@ hb_face_collect_unicodes (hb_face_t *face, { face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); } +/** + * hb_face_collect_nominal_glyph_mapping: + * @face: A face object + * @mapping: (out): The map to add Unicode-to-glyph mapping to + * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL` + * + * Collects the mapping from Unicode characters to nominal glyphs of the @face, + * and optionally all of the Unicode characters covered by @face. + * + * Since: 7.0.0 + */ +void +hb_face_collect_nominal_glyph_mapping (hb_face_t *face, + hb_map_t *mapping, + hb_set_t *unicodes) +{ + hb_set_t stack_unicodes; + if (!unicodes) + unicodes = &stack_unicodes; + face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ()); +} /** * hb_face_collect_variation_selectors: * @face: A face object - * @out: The set to add Variation Selector characters to + * @out: (out): The set to add Variation Selector characters to * * Collects all Unicode "Variation Selector" characters covered by @face and adds * them to the #hb_set_t set @out. @@ -612,7 +647,7 @@ hb_face_collect_variation_selectors (hb_face_t *face, * hb_face_collect_variation_unicodes: * @face: A face object * @variation_selector: The Variation Selector to query - * @out: The set to add Unicode characters to + * @out: (out): The set to add Unicode characters to * * Collects all Unicode characters for @variation_selector covered by @face and adds * them to the #hb_set_t set @out. @@ -627,211 +662,3 @@ hb_face_collect_variation_unicodes (hb_face_t *face, face->table.cmap->collect_variation_unicodes (variation_selector, out); } #endif - - -/* - * face-builder: A face that has add_table(). - */ - -struct face_table_info_t -{ - hb_blob_t* data; - unsigned order; -}; - -struct hb_face_builder_data_t -{ - hb_hashmap_t tables; -}; - -static int compare_entries (const void* pa, const void* pb) -{ - const auto& a = * (const hb_pair_t *) pa; - const auto& b = * (const hb_pair_t *) pb; - - /* Order by blob size first (smallest to largest) and then table tag */ - - if (a.second.order != b.second.order) - return a.second.order < b.second.order ? -1 : +1; - - if (a.second.data->length != b.second.data->length) - return a.second.data->length < b.second.data->length ? -1 : +1; - - return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; -} - -static hb_face_builder_data_t * -_hb_face_builder_data_create () -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_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 (auto info : data->tables.values()) - hb_blob_destroy (info.data); - - data->tables.fini (); - - hb_free (data); -} - -static hb_blob_t * -_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) -{ - - unsigned int table_count = data->tables.get_population (); - unsigned int face_length = table_count * 16 + 12; - - for (auto info : data->tables.values()) - face_length += hb_ceil_to_4 (hb_blob_get_length (info.data)); - - char *buf = (char *) hb_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 (); - - bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' ')) - || data->tables.has (HB_TAG ('C','F','F','2'))); - hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; - - // Sort the tags so that produced face is deterministic. - hb_vector_t> sorted_entries; - data->tables.iter () | hb_sink (sorted_entries); - if (unlikely (sorted_entries.in_error ())) - { - hb_free (buf); - return nullptr; - } - - sorted_entries.qsort (compare_entries); - - bool ret = f->serialize_single (&c, - sfnt_tag, - + sorted_entries.iter() - | hb_map ([&] (hb_pair_t _) { - return hb_pair_t (_.first, _.second.data); - })); - - c.end_serialize (); - - if (unlikely (!ret)) - { - hb_free (buf); - return nullptr; - } - - return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_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); - - return hb_blob_reference (data->tables[tag].data); -} - - -/** - * 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: - * @face: A face object created with hb_face_builder_create() - * @tag: The #hb_tag_t of the table to add - * @blob: The blob containing the table data to add - * - * 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 (tag == HB_MAP_VALUE_INVALID) - return false; - - 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_blob_t* previous = data->tables.get (tag).data; - if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0})) - { - hb_blob_destroy (blob); - return false; - } - - hb_blob_destroy (previous); - return true; -} - -/** - * hb_face_builder_sort_tables: - * @face: A face object created with hb_face_builder_create() - * @tags: (array zero-terminated=1): ordered list of table tags terminated by - * %HB_TAG_NONE - * - * Set the ordering of tables for serialization. Any tables not - * specified in the tags list will be ordered after the tables in - * tags, ordered by the default sort ordering. - * - * Since: 5.3.0 - **/ -void -hb_face_builder_sort_tables (hb_face_t *face, - const hb_tag_t *tags) -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; - - // Sort all unspecified tables after any specified tables. - for (auto& info : data->tables.values_ref()) - info.order = -1; - - unsigned order = 0; - for (const hb_tag_t* tag = tags; - *tag; - tag++) - { - face_table_info_t* info; - if (!data->tables.has (*tag, &info)) continue; - info->order = order++; - } -} diff --git a/third_party/harfbuzz-ng/src/src/hb-face.h b/third_party/harfbuzz-ng/src/src/hb-face.h index 38e7104af64b..2e54ccf13b77 100644 --- a/third_party/harfbuzz-ng/src/src/hb-face.h +++ b/third_party/harfbuzz-ng/src/src/hb-face.h @@ -33,6 +33,7 @@ #include "hb-common.h" #include "hb-blob.h" +#include "hb-map.h" #include "hb-set.h" HB_BEGIN_DECLS @@ -149,6 +150,11 @@ HB_EXTERN void hb_face_collect_unicodes (hb_face_t *face, hb_set_t *out); +HB_EXTERN void +hb_face_collect_nominal_glyph_mapping (hb_face_t *face, + hb_map_t *mapping, + hb_set_t *unicodes); + HB_EXTERN void hb_face_collect_variation_selectors (hb_face_t *face, hb_set_t *out); diff --git a/third_party/harfbuzz-ng/src/src/hb-face.hh b/third_party/harfbuzz-ng/src/src/hb-face.hh index 12e10d01e012..aff3ff0d07ce 100644 --- a/third_party/harfbuzz-ng/src/src/hb-face.hh +++ b/third_party/harfbuzz-ng/src/src/hb-face.hh @@ -65,7 +65,9 @@ struct hb_face_t hb_shape_plan_t *shape_plan; plan_node_t *next; }; +#ifndef HB_NO_SHAPER hb_atomic_ptr_t shape_plans; +#endif hb_blob_t *reference_table (hb_tag_t tag) const { @@ -74,7 +76,7 @@ struct hb_face_t if (unlikely (!reference_table_func)) return hb_blob_get_empty (); - blob = reference_table_func (/*XXX*/const_cast (this), tag, user_data); + blob = reference_table_func (/*Oh, well.*/const_cast (this), tag, user_data); if (unlikely (!blob)) return hb_blob_get_empty (); diff --git a/third_party/harfbuzz-ng/src/src/hb-fallback-shape.cc b/third_party/harfbuzz-ng/src/src/hb-fallback-shape.cc index f8524ecc8e7a..c54ad8764bcc 100644 --- a/third_party/harfbuzz-ng/src/src/hb-fallback-shape.cc +++ b/third_party/harfbuzz-ng/src/src/hb-fallback-shape.cc @@ -75,16 +75,6 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, const hb_feature_t *features HB_UNUSED, unsigned int num_features HB_UNUSED) { - /* TODO - * - * - Apply fallback kern. - * - Handle Variation Selectors? - * - Apply normalization? - * - * This will make the fallback shaper into a dumb "TrueType" - * shaper which many people unfortunately still request. - */ - hb_codepoint_t space; bool has_space = (bool) font->get_nominal_glyph (' ', &space); diff --git a/third_party/harfbuzz-ng/src/src/hb-features.h.in b/third_party/harfbuzz-ng/src/src/hb-features.h.in new file mode 100644 index 000000000000..d85749ca9ea0 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-features.h.in @@ -0,0 +1,112 @@ +/* + * Copyright © 2022 Red Hat, 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. + */ + +#ifndef HB_FEATURES_H +#define HB_FEATURES_H + +HB_BEGIN_DECLS + +/** + * SECTION: hb-features + * @title: hb-features + * @short_description: Feature detection + * @include: hb-features.h + * + * Macros for detecting optional HarfBuzz features at build time. + **/ + +/** + * HB_HAS_CAIRO: + * + * Defined if Harfbuzz has been built with cairo support. + */ +#mesondefine HB_HAS_CAIRO + +/** + * HB_HAS_CORETEXT: + * + * Defined if Harfbuzz has been built with CoreText support. + */ +#mesondefine HB_HAS_CORETEXT + +/** + * HB_HAS_DIRECTWRITE: + * + * Defined if Harfbuzz has been built with DirectWrite support. + */ +#mesondefine HB_HAS_DIRECTWRITE + +/** + * HB_HAS_FREETYPE: + * + * Defined if Harfbuzz has been built with Freetype support. + */ +#mesondefine HB_HAS_FREETYPE + +/** + * HB_HAS_GDI: + * + * Defined if Harfbuzz has been built with GDI support. + */ +#mesondefine HB_HAS_GDI + +/** + * HB_HAS_GLIB: + * + * Defined if Harfbuzz has been built with GLib support. + */ +#mesondefine HB_HAS_GLIB + +/** + * HB_HAS_GOBJECT: + * + * Defined if Harfbuzz has been built with GObject support. + */ +#mesondefine HB_HAS_GOBJECT + +/** + * HB_HAS_GRAPHITE: + * + * Defined if Harfbuzz has been built with Graphite support. + */ +#mesondefine HB_HAS_GRAPHITE + +/** + * HB_HAS_ICU: + * + * Defined if Harfbuzz has been built with ICU support. + */ +#mesondefine HB_HAS_ICU + +/** + * HB_HAS_UNISCRIBE: + * + * Defined if Harfbuzz has been built with Uniscribe support. + */ +#mesondefine HB_HAS_UNISCRIBE + + +HB_END_DECLS + +#endif /* HB_FEATURES_H */ diff --git a/third_party/harfbuzz-ng/src/src/hb-font.cc b/third_party/harfbuzz-ng/src/src/hb-font.cc index 856bbdda3280..688513112a7d 100644 --- a/third_party/harfbuzz-ng/src/src/hb-font.cc +++ b/third_party/harfbuzz-ng/src/src/hb-font.cc @@ -30,6 +30,7 @@ #include "hb-font.hh" #include "hb-draw.hh" +#include "hb-paint.hh" #include "hb-machinery.hh" #include "hb-ot.h" @@ -58,6 +59,11 @@ * * HarfBuzz provides a built-in set of lightweight default * functions for each method in #hb_font_funcs_t. + * + * The default font functions are implemented in terms of the + * #hb_font_funcs_t methods of the parent font object. This allows + * client programs to override only the methods they need to, and + * otherwise inherit the parent font's implementation, if any. **/ @@ -71,7 +77,7 @@ hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED, hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -96,7 +102,7 @@ hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED, hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -409,7 +415,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -503,22 +509,34 @@ hb_font_get_glyph_from_name_default (hb_font_t *font, } static void -hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, - void *draw_data, - void *user_data HB_UNUSED) +hb_font_draw_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) { } +static void +hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_paint_funcs_t *paint_funcs HB_UNUSED, + void *paint_data HB_UNUSED, + unsigned int palette HB_UNUSED, + hb_color_t foreground HB_UNUSED, + void *user_data HB_UNUSED) +{ +} -typedef struct hb_font_get_glyph_shape_default_adaptor_t { +typedef struct hb_font_draw_glyph_default_adaptor_t { hb_draw_funcs_t *draw_funcs; void *draw_data; float x_scale; float y_scale; -} hb_font_get_glyph_shape_default_adaptor_t; + float slant; +} hb_font_draw_glyph_default_adaptor_t; static void hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, @@ -527,12 +545,13 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st, - x_scale * to_x, y_scale * to_y); + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -541,15 +560,16 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st, - x_scale * to_x, y_scale * to_y); + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -559,16 +579,17 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st, - x_scale * control_x, y_scale * control_y, - x_scale * to_x, y_scale * to_y); + x_scale * control_x + slant * control_y, y_scale * control_y, + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -579,17 +600,18 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st, - x_scale * control1_x, y_scale * control1_y, - x_scale * control2_x, y_scale * control2_y, - x_scale * to_x, y_scale * to_y); + x_scale * control1_x + slant * control1_y, y_scale * control1_y, + x_scale * control2_x + slant * control2_y, y_scale * control2_y, + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -597,7 +619,7 @@ hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, hb_draw_state_t *st, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st); } @@ -613,25 +635,50 @@ static const hb_draw_funcs_t _hb_draw_funcs_default = { }; static void -hb_font_get_glyph_shape_default (hb_font_t *font, +hb_font_draw_glyph_default (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, hb_draw_funcs_t *draw_funcs, void *draw_data, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t adaptor = { + hb_font_draw_glyph_default_adaptor_t adaptor = { draw_funcs, draw_data, - (float) font->x_scale / (float) font->parent->x_scale, - (float) font->y_scale / (float) font->parent->y_scale + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, + font->parent->y_scale ? (font->slant - font->parent->slant) * + (float) font->x_scale / (float) font->parent->y_scale : 0.f }; - font->parent->get_glyph_shape (glyph, + font->parent->draw_glyph (glyph, const_cast (&_hb_draw_funcs_default), &adaptor); } +static void +hb_font_paint_glyph_default (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, + void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ + paint_funcs->push_transform (paint_data, + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, + font->parent->y_scale ? (font->slant - font->parent->slant) * + (float) font->x_scale / (float) font->parent->y_scale : 0.f, + 0.f, + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, + 0.f, 0.f); + + font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground); + + paint_funcs->pop_transform (paint_data); +} + DEFINE_NULL_INSTANCE (hb_font_funcs_t) = { HB_OBJECT_HEADER_STATIC, @@ -640,7 +687,7 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) = nullptr, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_nil, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -654,7 +701,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = { nullptr, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default, +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_default, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -732,7 +779,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) if (ffuncs->destroy) { -#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \ +#define HB_FONT_FUNC_IMPLEMENT(get_,name) if (ffuncs->destroy->name) \ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT @@ -822,59 +869,82 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) } -#define HB_FONT_FUNC_IMPLEMENT(name) \ +static bool +_hb_font_funcs_set_preamble (hb_font_funcs_t *ffuncs, + bool func_is_null, + void **user_data, + hb_destroy_func_t *destroy) +{ + if (hb_object_is_immutable (ffuncs)) + { + if (*destroy) + (*destroy) (*user_data); + return false; + } + + if (func_is_null) + { + if (*destroy) + (*destroy) (*user_data); + *destroy = nullptr; + *user_data = nullptr; + } + + return true; +} + +static bool +_hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs, + void *user_data, + hb_destroy_func_t destroy) +{ + if (user_data && !ffuncs->user_data) + { + ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); + if (unlikely (!ffuncs->user_data)) + goto fail; + } + if (destroy && !ffuncs->destroy) + { + ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); + if (unlikely (!ffuncs->destroy)) + goto fail; + } + + return true; + +fail: + if (destroy) + (destroy) (user_data); + return false; +} + +#define HB_FONT_FUNC_IMPLEMENT(get_,name) \ \ void \ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ - hb_font_get_##name##_func_t func, \ + hb_font_##get_##name##_func_t func, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (ffuncs)) \ - goto fail; \ - \ - if (!func) \ - { \ - if (destroy) \ - destroy (user_data); \ - destroy = nullptr; \ - user_data = nullptr; \ - } \ + if (!_hb_font_funcs_set_preamble (ffuncs, !func, &user_data, &destroy))\ + return; \ \ if (ffuncs->destroy && ffuncs->destroy->name) \ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \ \ - if (user_data && !ffuncs->user_data) \ - { \ - ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); \ - if (unlikely (!ffuncs->user_data)) \ - goto fail; \ - } \ - if (destroy && !ffuncs->destroy) \ - { \ - ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); \ - if (unlikely (!ffuncs->destroy)) \ - goto fail; \ - } \ + if (!_hb_font_funcs_set_middle (ffuncs, user_data, destroy)) \ + return; \ \ - if (func) { \ + if (func) \ ffuncs->get.f.name = func; \ - if (ffuncs->user_data) \ - ffuncs->user_data->name = user_data; \ - if (ffuncs->destroy) \ - ffuncs->destroy->name = destroy; \ - } else { \ - ffuncs->get.f.name = hb_font_get_##name##_default; \ - if (ffuncs->user_data) \ - ffuncs->user_data->name = nullptr; \ - if (ffuncs->destroy) \ - ffuncs->destroy->name = nullptr; \ - } \ - return; \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + else \ + ffuncs->get.f.name = hb_font_##get_##name##_default; \ + \ + if (ffuncs->user_data) \ + ffuncs->user_data->name = user_data; \ + if (ffuncs->destroy) \ + ffuncs->destroy->name = destroy; \ } HB_FONT_FUNCS_IMPLEMENT_CALLBACKS @@ -996,7 +1066,8 @@ hb_font_get_nominal_glyph (hb_font_t *font, * @glyph_stride: The stride between successive glyph IDs * * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph - * IDs must be returned in a #hb_codepoint_t output parameter. + * IDs must be returned in a #hb_codepoint_t output parameter. Stopes at the + * first unsupported glyph ID. * * Return value: the number of code points processed * @@ -1278,6 +1349,9 @@ hb_font_get_glyph_contour_point (hb_font_t *font, * * Fetches the glyph-name string for a glyph ID in the specified @font. * + * According to the OpenType specification, glyph names are limited to 63 + * characters and can only contain (a subset of) ASCII. + * * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 @@ -1318,22 +1392,76 @@ hb_font_get_glyph_from_name (hb_font_t *font, /** * hb_font_get_glyph_shape: * @font: #hb_font_t to work upon - * @glyph: : The glyph ID + * @glyph: The glyph ID * @dfuncs: #hb_draw_funcs_t to draw to * @draw_data: User data to pass to draw callbacks * * Fetches the glyph shape that corresponds to a glyph in the specified @font. - * The shape is returned by way of calls to the callsbacks of the @dfuncs + * The shape is returned by way of calls to the callbacks of the @dfuncs * objects, with @draw_data passed to them. * * Since: 4.0.0 - **/ + * Deprecated: 7.0.0: Use hb_font_draw_glyph() instead + */ void hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) +{ + hb_font_draw_glyph (font, glyph, dfuncs, draw_data); +} + +/** + * hb_font_draw_glyph: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @dfuncs: #hb_draw_funcs_t to draw to + * @draw_data: User data to pass to draw callbacks + * + * Draws the outline that corresponds to a glyph in the specified @font. + * + * The outline is returned by way of calls to the callbacks of the @dfuncs + * objects, with @draw_data passed to them. + * + * Since: 7.0.0 + **/ +void +hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_draw_funcs_t *dfuncs, void *draw_data) { - font->get_glyph_shape (glyph, dfuncs, draw_data); + font->draw_glyph (glyph, dfuncs, draw_data); +} + +/** + * hb_font_paint_glyph: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @pfuncs: #hb_paint_funcs_t to paint with + * @paint_data: User data to pass to paint callbacks + * @palette_index: The index of the font's color palette to use + * @foreground: The foreground color, unpremultipled + * + * Paints the glyph. + * + * The painting instructions are returned by way of calls to + * the callbacks of the @funcs object, with @paint_data passed + * to them. + * + * If the font has color palettes (see hb_ot_color_has_palettes()), + * then @palette_index selects the palette to use. If the font only + * has one palette, this will be 0. + * + * Since: 7.0.0 + */ +void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground) +{ + font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground); } /* A bit higher-level, and with fallback */ @@ -1594,6 +1722,9 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, * If the glyph ID has no name in @font, a string of the form `gidDDD` is * generated, with `DDD` being the glyph ID. * + * According to the OpenType specification, glyph names are limited to 63 + * characters and can only contain (a subset of) ASCII. + * * Since: 0.9.2 **/ void @@ -1647,8 +1778,13 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ - 0., /* slant */ - 0., /* slant_xy; */ + 0.f, /* x_embolden */ + 0.f, /* y_embolden */ + true, /* embolden_in_place */ + 0, /* x_strength */ + 0, /* y_strength */ + 0.f, /* slant */ + 0.f, /* slant_xy; */ 1.f, /* x_multf */ 1.f, /* y_multf */ 1<<16, /* x_mult */ @@ -1658,6 +1794,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 0, /* y_ppem */ 0, /* ptem */ + HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */ 0, /* num_coords */ nullptr, /* coords */ nullptr, /* design_coords */ @@ -1685,8 +1822,10 @@ _hb_font_create (hb_face_t *face) font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); font->x_scale = font->y_scale = face->get_upem (); + font->embolden_in_place = true; font->x_multf = font->y_multf = 1.f; font->x_mult = font->y_mult = 1 << 16; + font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE; return font; } @@ -1768,6 +1907,9 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; + font->x_embolden = parent->x_embolden; + font->y_embolden = parent->y_embolden; + font->embolden_in_place = parent->embolden_in_place; font->slant = parent->slant; font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; @@ -1780,8 +1922,8 @@ hb_font_create_sub_font (hb_font_t *parent) float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0])); if (likely (coords && design_coords)) { - memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); - memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); + hb_memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); + hb_memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); _hb_font_adopt_var_coords (font, coords, design_coords, num_coords); } else @@ -2157,6 +2299,31 @@ hb_font_set_funcs_data (hb_font_t *font, * * Sets the horizontal and vertical scale of a font. * + * The font scale is a number related to, but not the same as, + * font size. Typically the client establishes a scale factor + * to be used between the two. For example, 64, or 256, which + * would be the fractional-precision part of the font scale. + * This is necessary because #hb_position_t values are integer + * types and you need to leave room for fractional values + * in there. + * + * For example, to set the font size to 20, with 64 + * levels of fractional precision you would call + * `hb_font_set_scale(font, 20 * 64, 20 * 64)`. + * + * In the example above, even what font size 20 means is up to + * you. It might be 20 pixels, or 20 points, or 20 millimeters. + * HarfBuzz does not care about that. You can set the point + * size of the font using hb_font_set_ptem(), and the pixel + * size using hb_font_set_ppem(). + * + * The choice of scale is yours but needs to be consistent between + * what you set here, and what you expect out of #hb_position_t + * as well has draw / paint API output values. + * + * Fonts default to a scale equal to the UPEM value of their face. + * A font with this setting is sometimes called an "unscaled" font. + * * Since: 0.9.2 **/ void @@ -2202,7 +2369,11 @@ hb_font_get_scale (hb_font_t *font, * @x_ppem: Horizontal ppem value to assign * @y_ppem: Vertical ppem value to assign * - * Sets the horizontal and vertical pixels-per-em (ppem) of a font. + * Sets the horizontal and vertical pixels-per-em (PPEM) of a font. + * + * These values are used for pixel-size-specific adjustment to + * shaping and draw results, though for the most part they are + * unused and can be left unset. * * Since: 0.9.2 **/ @@ -2286,6 +2457,76 @@ hb_font_get_ptem (hb_font_t *font) return font->ptem; } +/** + * hb_font_set_synthetic_bold: + * @font: #hb_font_t to work upon + * @x_embolden: the amount to embolden horizontally + * @y_embolden: the amount to embolden vertically + * @in_place: whether to embolden glyphs in-place + * + * Sets the "synthetic boldness" of a font. + * + * Positive values for @x_embolden / @y_embolden make a font + * bolder, negative values thinner. Typical values are in the + * 0.01 to 0.05 range. The default value is zero. + * + * Synthetic boldness is applied by offsetting the contour + * points of the glyph shape. + * + * Synthetic boldness is applied when rendering a glyph via + * hb_font_draw_glyph(). + * + * If @in_place is `false`, then glyph advance-widths are also + * adjusted, otherwise they are not. The in-place mode is + * useful for simulating [font grading](https://fonts.google.com/knowledge/glossary/grade). + * + * + * Since: 7.0.0 + **/ +void +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, + float y_embolden, + hb_bool_t in_place) +{ + if (hb_object_is_immutable (font)) + return; + + if (font->x_embolden == x_embolden && + font->y_embolden == y_embolden && + font->embolden_in_place == (bool) in_place) + return; + + font->serial++; + + font->x_embolden = x_embolden; + font->y_embolden = y_embolden; + font->embolden_in_place = in_place; + font->mults_changed (); +} + +/** + * hb_font_get_synthetic_bold: + * @font: #hb_font_t to work upon + * @x_embolden: (out): return location for horizontal value + * @y_embolden: (out): return location for vertical value + * @in_place: (out): return location for in-place value + * + * Fetches the "synthetic boldness" parameters of a font. + * + * Since: 7.0.0 + **/ +void +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, + float *y_embolden, + hb_bool_t *in_place) +{ + if (x_embolden) *x_embolden = font->x_embolden; + if (y_embolden) *y_embolden = font->y_embolden; + if (in_place) *in_place = font->embolden_in_place; +} + /** * hb_font_set_synthetic_slant: * @font: #hb_font_t to work upon @@ -2298,9 +2539,8 @@ hb_font_get_ptem (hb_font_t *font) * HarfBuzz needs to know this value to adjust shaping results, * metrics, and style values to match the slanted rendering. * - * Note: The glyph shape fetched via the - * hb_font_get_glyph_shape() is slanted to reflect this value - * as well. + * Note: The glyph shape fetched via the hb_font_draw_glyph() + * function is slanted to reflect this value as well. * * Note: The slant value is a ratio. For example, a * 20% slant would be represented as a 0.2 value. @@ -2367,7 +2607,7 @@ hb_font_set_variations (hb_font_t *font, font->serial_coords = ++font->serial; - if (!variations_length) + if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE) { hb_font_set_var_coords_normalized (font, nullptr, 0); return; @@ -2387,9 +2627,18 @@ hb_font_set_variations (hb_font_t *font, return; } - /* Initialize design coords to default from fvar. */ + /* Initialize design coords. */ for (unsigned int i = 0; i < coords_length; i++) design_coords[i] = axes[i].get_default (); + if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE) + { + unsigned count = coords_length; + /* This may fail if index is out-of-range; + * That's why we initialize design_coords from fvar above + * unconditionally. */ + hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index, + &count, design_coords); + } for (unsigned int i = 0; i < variations_length; i++) { @@ -2397,16 +2646,87 @@ hb_font_set_variations (hb_font_t *font, const auto v = variations[i].value; for (unsigned axis_index = 0; axis_index < coords_length; axis_index++) if (axes[axis_index].axisTag == tag) - { design_coords[axis_index] = v; - normalized[axis_index] = fvar.normalize_axis_value (axis_index, v); - } } font->face->table.avar->map_coords (normalized, coords_length); + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } +/** + * hb_font_set_variation: + * @font: #hb_font_t to work upon + * @tag: The #hb_tag_t tag of the variation-axis name + * @value: The value of the variation axis + * + * Change the value of one variation axis on the font. + * + * Note: This function is expensive to be called repeatedly. + * If you want to set multiple variation axes at the same time, + * use hb_font_set_variations() instead. + * + * Since: 7.1.0 + */ +void +hb_font_set_variation (hb_font_t *font, + hb_tag_t tag, + float value) +{ + if (hb_object_is_immutable (font)) + return; + + font->serial_coords = ++font->serial; + + // TODO Share some of this code with set_variations() + + const OT::fvar &fvar = *font->face->table.fvar; + auto axes = fvar.get_axes (); + const unsigned coords_length = axes.length; + + int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr; + float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; + + if (unlikely (coords_length && !(normalized && design_coords))) + { + hb_free (normalized); + hb_free (design_coords); + return; + } + + /* Initialize design coords. */ + if (font->design_coords) + { + assert (coords_length == font->num_coords); + for (unsigned int i = 0; i < coords_length; i++) + design_coords[i] = font->design_coords[i]; + } + else + { + for (unsigned int i = 0; i < coords_length; i++) + design_coords[i] = axes[i].get_default (); + if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE) + { + unsigned count = coords_length; + /* This may fail if index is out-of-range; + * That's why we initialize design_coords from fvar above + * unconditionally. */ + hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index, + &count, design_coords); + } + } + + for (unsigned axis_index = 0; axis_index < coords_length; axis_index++) + if (axes[axis_index].axisTag == tag) + design_coords[axis_index] = value; + + font->face->table.avar->map_coords (normalized, coords_length); + + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); + _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); + +} + /** * hb_font_set_var_coords_design: * @font: #hb_font_t to work upon @@ -2443,7 +2763,7 @@ hb_font_set_var_coords_design (hb_font_t *font, } if (coords_length) - memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); + hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); @@ -2454,28 +2774,40 @@ hb_font_set_var_coords_design (hb_font_t *font, * @font: a font. * @instance_index: named instance index. * - * Sets design coords of a font from a named instance index. + * Sets design coords of a font from a named-instance index. * * Since: 2.6.0 */ void hb_font_set_var_named_instance (hb_font_t *font, - unsigned instance_index) + unsigned int instance_index) { if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + if (font->instance_index == instance_index) + return; - unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr); + font->serial_coords = ++font->serial; - float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; - if (unlikely (coords_length && !coords)) - return; + font->instance_index = instance_index; + hb_font_set_variations (font, nullptr, 0); +} - hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords); - hb_font_set_var_coords_design (font, coords, coords_length); - hb_free (coords); +/** + * hb_font_get_var_named_instance: + * @font: a font. + * + * Returns the currently-set named-instance index of the font. + * + * Return value: Named-instance index or %HB_FONT_NO_VAR_NAMED_INSTANCE. + * + * Since: 7.0.0 + **/ +unsigned int +hb_font_get_var_named_instance (hb_font_t *font) +{ + return font->instance_index; } /** @@ -2519,8 +2851,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font, if (coords_length) { - memcpy (copy, coords, coords_length * sizeof (coords[0])); - memcpy (unmapped, coords, coords_length * sizeof (coords[0])); + hb_memcpy (copy, coords, coords_length * sizeof (coords[0])); + hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0])); } /* Best effort design coords simulation */ @@ -2724,3 +3056,13 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, trampoline_destroy); } #endif + + +void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) +{ + hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); +} diff --git a/third_party/harfbuzz-ng/src/src/hb-font.h b/third_party/harfbuzz-ng/src/src/hb-font.h index e2c3df4a5acc..f3b589bd0d8d 100644 --- a/third_party/harfbuzz-ng/src/src/hb-font.h +++ b/third_party/harfbuzz-ng/src/src/hb-font.h @@ -34,18 +34,10 @@ #include "hb-common.h" #include "hb-face.h" #include "hb-draw.h" +#include "hb-paint.h" HB_BEGIN_DECLS -/** - * hb_font_t: - * - * Data type for holding fonts. - * - */ -typedef struct hb_font_t hb_font_t; - - /* * hb_font_funcs_t */ @@ -97,7 +89,7 @@ HB_EXTERN hb_bool_t hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); -/* font and glyph extents */ +/* font extents */ /** * hb_font_extents_t: @@ -126,24 +118,6 @@ typedef struct hb_font_extents_t { hb_position_t reserved1; } hb_font_extents_t; -/** - * hb_glyph_extents_t: - * @x_bearing: Distance from the x-origin to the left extremum of the glyph. - * @y_bearing: Distance from the top extremum of the glyph to the y-origin. - * @width: Distance from the left extremum of the glyph to the right extremum. - * @height: Distance from the top extremum of the glyph to the bottom extremum. - * - * Glyph extent values, measured in font units. - * - * Note that @height is negative, in coordinate systems that grow up. - **/ -typedef struct hb_glyph_extents_t { - hb_position_t x_bearing; - hb_position_t y_bearing; - hb_position_t width; - hb_position_t height; -} hb_glyph_extents_t; - /* func types */ /** @@ -523,13 +497,53 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * * Since: 4.0.0 - * + * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead **/ typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_draw_funcs_t *draw_funcs, void *draw_data, void *user_data); +/** + * hb_font_draw_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + * + **/ +typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + +/** + * hb_font_paint_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @paint_funcs: The paint functions to use + * @paint_data: The data accompanying the paint functions + * @palette_index: The color palette to use + * @foreground: The foreground color + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + */ +typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data); /* func setters */ @@ -796,15 +810,50 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, * @user_data: Data to pass to @func * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * Sets the implementation function for #hb_font_get_glyph_shape_func_t. + * Sets the implementation function for #hb_font_get_glyph_shape_func_t, + * which is the same as #hb_font_draw_glyph_func_t. * * Since: 4.0.0 + * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead **/ HB_EXTERN void hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_shape_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_font_funcs_set_draw_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_draw_glyph_func_t, + * which is the same as #hb_font_get_glyph_shape_func_t. + * + * Since: 7.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_paint_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is no longer needed + * + * Sets the implementation function for #hb_font_paint_glyph_func_t. + * + * Since: 7.0.0 + */ +HB_EXTERN void +hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_paint_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + /* func dispatch */ HB_EXTERN hb_bool_t @@ -890,6 +939,17 @@ hb_font_get_glyph_shape (hb_font_t *font, hb_codepoint_t glyph, hb_draw_funcs_t *dfuncs, void *draw_data); +HB_EXTERN void +hb_font_draw_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + +HB_EXTERN void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground); /* high-level funcs, with fallback */ @@ -1069,6 +1129,16 @@ hb_font_set_ptem (hb_font_t *font, float ptem); HB_EXTERN float hb_font_get_ptem (hb_font_t *font); +HB_EXTERN void +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, float y_embolden, + hb_bool_t in_place); + +HB_EXTERN void +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, float *y_embolden, + hb_bool_t *in_place); + HB_EXTERN void hb_font_set_synthetic_slant (hb_font_t *font, float slant); @@ -1080,6 +1150,11 @@ hb_font_set_variations (hb_font_t *font, const hb_variation_t *variations, unsigned int variations_length); +HB_EXTERN void +hb_font_set_variation (hb_font_t *font, + hb_tag_t tag, + float value); + HB_EXTERN void hb_font_set_var_coords_design (hb_font_t *font, const float *coords, @@ -1098,10 +1173,23 @@ HB_EXTERN const int * hb_font_get_var_coords_normalized (hb_font_t *font, unsigned int *length); +/** + * HB_FONT_NO_VAR_NAMED_INSTANCE: + * + * Constant signifying that a font does not have any + * named-instance index set. This is the default of + * a font. + * + * Since: 7.0.0 + */ +#define HB_FONT_NO_VAR_NAMED_INSTANCE 0xFFFFFFFF + HB_EXTERN void hb_font_set_var_named_instance (hb_font_t *font, - unsigned instance_index); + unsigned int instance_index); +HB_EXTERN unsigned int +hb_font_get_var_named_instance (hb_font_t *font); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/src/hb-font.hh b/third_party/harfbuzz-ng/src/src/hb-font.hh index bb402e23eb41..f503575c34ad 100644 --- a/third_party/harfbuzz-ng/src/src/hb-font.hh +++ b/third_party/harfbuzz-ng/src/src/hb-font.hh @@ -40,24 +40,25 @@ */ #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \ - 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_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) \ - HB_FONT_FUNC_IMPLEMENT (glyph_shape) \ + HB_FONT_FUNC_IMPLEMENT (get_,font_h_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,font_v_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyph) \ + HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyphs) \ + HB_FONT_FUNC_IMPLEMENT (get_,variation_glyph) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advance) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advance) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advances) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \ + HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \ + HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \ + HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \ /* ^--- Add new callbacks here */ struct hb_font_funcs_t @@ -65,13 +66,13 @@ struct hb_font_funcs_t hb_object_header_t header; struct { -#define HB_FONT_FUNC_IMPLEMENT(name) void *name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) void *name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } *user_data; struct { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_destroy_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } *destroy; @@ -79,12 +80,12 @@ struct hb_font_funcs_t /* Don't access these directly. Call font->get_*() instead. */ union get_t { struct get_funcs_t { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } f; void (*array[0 -#define HB_FONT_FUNC_IMPLEMENT(name) +1 +#define HB_FONT_FUNC_IMPLEMENT(get_,name) +1 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT ]) (); @@ -112,8 +113,16 @@ struct hb_font_t int32_t x_scale; int32_t y_scale; + + float x_embolden; + float y_embolden; + bool embolden_in_place; + int32_t x_strength; /* x_embolden, in scaled units. */ + int32_t y_strength; /* y_embolden, in scaled units. */ + float slant; float slant_xy; + float x_multf; float y_multf; int64_t x_mult; @@ -125,6 +134,7 @@ struct hb_font_t float ptem; /* Font variation coordinates. */ + unsigned int instance_index; unsigned int num_coords; int *coords; float *design_coords; @@ -179,6 +189,42 @@ struct hb_font_t *y = parent_scale_y_position (*y); } + void scale_glyph_extents (hb_glyph_extents_t *extents) + { + float x1 = em_fscale_x (extents->x_bearing); + float y1 = em_fscale_y (extents->y_bearing); + float x2 = em_fscale_x (extents->x_bearing + extents->width); + float y2 = em_fscale_y (extents->y_bearing + extents->height); + + /* Apply slant. */ + if (slant_xy) + { + x1 += hb_min (y1 * slant_xy, y2 * slant_xy); + x2 += hb_max (y1 * slant_xy, y2 * slant_xy); + } + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; + + if (x_strength || y_strength) + { + /* Y */ + int y_shift = y_strength; + if (y_scale < 0) y_shift = -y_shift; + extents->y_bearing += y_shift; + extents->height -= y_shift; + + /* X */ + int x_shift = x_strength; + if (x_scale < 0) x_shift = -x_shift; + if (embolden_in_place) + extents->x_bearing -= x_shift / 2; + extents->width += x_shift; + } + } + /* Public getters */ @@ -186,7 +232,7 @@ struct hb_font_t HB_INTERNAL bool has_func_set (unsigned int i); /* has_* ... */ -#define HB_FONT_FUNC_IMPLEMENT(name) \ +#define HB_FONT_FUNC_IMPLEMENT(get_,name) \ bool \ has_##name##_func () \ { \ @@ -206,14 +252,14 @@ struct hb_font_t hb_bool_t get_font_h_extents (hb_font_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.font_h_extents (this, user_data, extents, !klass->user_data ? nullptr : klass->user_data->font_h_extents); } hb_bool_t get_font_v_extents (hb_font_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.font_v_extents (this, user_data, extents, !klass->user_data ? nullptr : klass->user_data->font_v_extents); @@ -342,7 +388,7 @@ struct hb_font_t hb_bool_t get_glyph_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.glyph_extents (this, user_data, glyph, extents, @@ -380,15 +426,26 @@ struct hb_font_t !klass->user_data ? nullptr : klass->user_data->glyph_from_name); } - void get_glyph_shape (hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data) + void draw_glyph (hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data) { - klass->get.f.glyph_shape (this, user_data, - glyph, - draw_funcs, draw_data, - !klass->user_data ? nullptr : klass->user_data->glyph_shape); + klass->get.f.draw_glyph (this, user_data, + glyph, + draw_funcs, draw_data, + !klass->user_data ? nullptr : klass->user_data->draw_glyph); } + void paint_glyph (hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground) + { + klass->get.f.paint_glyph (this, user_data, + glyph, + paint_funcs, paint_data, + palette, foreground, + !klass->user_data ? nullptr : klass->user_data->paint_glyph); + } /* A bit higher-level, and with fallback */ @@ -632,12 +689,17 @@ struct hb_font_t void mults_changed () { float upem = face->get_upem (); + x_multf = x_scale / upem; y_multf = y_scale / upem; bool x_neg = x_scale < 0; x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem; bool y_neg = y_scale < 0; y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; + + x_strength = fabsf (roundf (x_scale * x_embolden)); + y_strength = fabsf (roundf (y_scale * y_embolden)); + slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; data.fini (); diff --git a/third_party/harfbuzz-ng/src/src/hb-ft-colr.hh b/third_party/harfbuzz-ng/src/src/hb-ft-colr.hh new file mode 100644 index 000000000000..fa5712f9b336 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-ft-colr.hh @@ -0,0 +1,567 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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_FT_COLR_HH +#define HB_FT_COLR_HH + +#include "hb.hh" + +#include "hb-paint-extents.hh" + +#include FT_COLOR_H + + +static hb_paint_composite_mode_t +_hb_ft_paint_composite_mode (FT_Composite_Mode mode) +{ + switch (mode) + { + case FT_COLR_COMPOSITE_CLEAR: return HB_PAINT_COMPOSITE_MODE_CLEAR; + case FT_COLR_COMPOSITE_SRC: return HB_PAINT_COMPOSITE_MODE_SRC; + case FT_COLR_COMPOSITE_DEST: return HB_PAINT_COMPOSITE_MODE_DEST; + case FT_COLR_COMPOSITE_SRC_OVER: return HB_PAINT_COMPOSITE_MODE_SRC_OVER; + case FT_COLR_COMPOSITE_DEST_OVER: return HB_PAINT_COMPOSITE_MODE_DEST_OVER; + case FT_COLR_COMPOSITE_SRC_IN: return HB_PAINT_COMPOSITE_MODE_SRC_IN; + case FT_COLR_COMPOSITE_DEST_IN: return HB_PAINT_COMPOSITE_MODE_DEST_IN; + case FT_COLR_COMPOSITE_SRC_OUT: return HB_PAINT_COMPOSITE_MODE_SRC_OUT; + case FT_COLR_COMPOSITE_DEST_OUT: return HB_PAINT_COMPOSITE_MODE_DEST_OUT; + case FT_COLR_COMPOSITE_SRC_ATOP: return HB_PAINT_COMPOSITE_MODE_SRC_ATOP; + case FT_COLR_COMPOSITE_DEST_ATOP: return HB_PAINT_COMPOSITE_MODE_DEST_ATOP; + case FT_COLR_COMPOSITE_XOR: return HB_PAINT_COMPOSITE_MODE_XOR; + case FT_COLR_COMPOSITE_PLUS: return HB_PAINT_COMPOSITE_MODE_PLUS; + case FT_COLR_COMPOSITE_SCREEN: return HB_PAINT_COMPOSITE_MODE_SCREEN; + case FT_COLR_COMPOSITE_OVERLAY: return HB_PAINT_COMPOSITE_MODE_OVERLAY; + case FT_COLR_COMPOSITE_DARKEN: return HB_PAINT_COMPOSITE_MODE_DARKEN; + case FT_COLR_COMPOSITE_LIGHTEN: return HB_PAINT_COMPOSITE_MODE_LIGHTEN; + case FT_COLR_COMPOSITE_COLOR_DODGE: return HB_PAINT_COMPOSITE_MODE_COLOR_DODGE; + case FT_COLR_COMPOSITE_COLOR_BURN: return HB_PAINT_COMPOSITE_MODE_COLOR_BURN; + case FT_COLR_COMPOSITE_HARD_LIGHT: return HB_PAINT_COMPOSITE_MODE_HARD_LIGHT; + case FT_COLR_COMPOSITE_SOFT_LIGHT: return HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT; + case FT_COLR_COMPOSITE_DIFFERENCE: return HB_PAINT_COMPOSITE_MODE_DIFFERENCE; + case FT_COLR_COMPOSITE_EXCLUSION: return HB_PAINT_COMPOSITE_MODE_EXCLUSION; + case FT_COLR_COMPOSITE_MULTIPLY: return HB_PAINT_COMPOSITE_MODE_MULTIPLY; + case FT_COLR_COMPOSITE_HSL_HUE: return HB_PAINT_COMPOSITE_MODE_HSL_HUE; + case FT_COLR_COMPOSITE_HSL_SATURATION: return HB_PAINT_COMPOSITE_MODE_HSL_SATURATION; + case FT_COLR_COMPOSITE_HSL_COLOR: return HB_PAINT_COMPOSITE_MODE_HSL_COLOR; + case FT_COLR_COMPOSITE_HSL_LUMINOSITY: return HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY; + + case FT_COLR_COMPOSITE_MAX: HB_FALLTHROUGH; + default: return HB_PAINT_COMPOSITE_MODE_CLEAR; + } +} + +typedef struct hb_ft_paint_context_t hb_ft_paint_context_t; + +static void +_hb_ft_paint (hb_ft_paint_context_t *c, + FT_OpaquePaint opaque_paint); + +struct hb_ft_paint_context_t +{ + hb_ft_paint_context_t (const hb_ft_font_t *ft_font, + hb_font_t *font, + hb_paint_funcs_t *paint_funcs, void *paint_data, + FT_Color *palette, + unsigned palette_index, + hb_color_t foreground) : + ft_font (ft_font), font(font), + funcs (paint_funcs), data (paint_data), + palette (palette), palette_index (palette_index), foreground (foreground) {} + + void recurse (FT_OpaquePaint paint) + { + if (unlikely (depth_left <= 0 || edge_count <= 0)) return; + depth_left--; + edge_count--; + _hb_ft_paint (this, paint); + depth_left++; + } + + const hb_ft_font_t *ft_font; + hb_font_t *font; + hb_paint_funcs_t *funcs; + void *data; + FT_Color *palette; + unsigned palette_index; + hb_color_t foreground; + int depth_left = HB_MAX_NESTING_LEVEL; + int edge_count = HB_COLRV1_MAX_EDGE_COUNT; +}; + +static unsigned +_hb_ft_color_line_get_color_stops (hb_color_line_t *color_line, + void *color_line_data, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + void *user_data) +{ + FT_ColorLine *cl = (FT_ColorLine *) color_line_data; + hb_ft_paint_context_t *c = (hb_ft_paint_context_t *) user_data; + + if (count) + { + FT_ColorStop stop; + unsigned wrote = 0; + FT_ColorStopIterator iter = cl->color_stop_iterator; + + if (start >= cl->color_stop_iterator.num_color_stops) + { + *count = 0; + return cl->color_stop_iterator.num_color_stops; + } + + while (cl->color_stop_iterator.current_color_stop < start) + FT_Get_Colorline_Stops(c->ft_font->ft_face, + &stop, + &cl->color_stop_iterator); + + while (count && *count && + FT_Get_Colorline_Stops(c->ft_font->ft_face, + &stop, + &cl->color_stop_iterator)) + { + // https://github.com/harfbuzz/harfbuzz/issues/4013 + if (sizeof stop.stop_offset == 2) + color_stops->offset = stop.stop_offset / 16384.f; + else + color_stops->offset = stop.stop_offset / 65536.f; + + color_stops->is_foreground = stop.color.palette_index == 0xFFFF; + if (color_stops->is_foreground) + color_stops->color = HB_COLOR (hb_color_get_blue (c->foreground), + hb_color_get_green (c->foreground), + hb_color_get_red (c->foreground), + (hb_color_get_alpha (c->foreground) * stop.color.alpha) >> 14); + else + { + hb_color_t color; + if (c->funcs->custom_palette_color (c->data, stop.color.palette_index, &color)) + { + color_stops->color = HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + (hb_color_get_alpha (color) * stop.color.alpha) >> 14); + } + else + { + FT_Color ft_color = c->palette[stop.color.palette_index]; + color_stops->color = HB_COLOR (ft_color.blue, + ft_color.green, + ft_color.red, + (ft_color.alpha * stop.color.alpha) >> 14); + } + } + + color_stops++; + wrote++; + } + + *count = wrote; + + // reset the iterator for next time + cl->color_stop_iterator = iter; + } + + return cl->color_stop_iterator.num_color_stops; +} + +static hb_paint_extend_t +_hb_ft_color_line_get_extend (hb_color_line_t *color_line, + void *color_line_data, + void *user_data) +{ + FT_ColorLine *c = (FT_ColorLine *) color_line_data; + switch (c->extend) + { + default: + case FT_COLR_PAINT_EXTEND_PAD: return HB_PAINT_EXTEND_PAD; + case FT_COLR_PAINT_EXTEND_REPEAT: return HB_PAINT_EXTEND_REPEAT; + case FT_COLR_PAINT_EXTEND_REFLECT: return HB_PAINT_EXTEND_REFLECT; + } +} + +void +_hb_ft_paint (hb_ft_paint_context_t *c, + FT_OpaquePaint opaque_paint) +{ + FT_Face ft_face = c->ft_font->ft_face; + FT_COLR_Paint paint; + if (!FT_Get_Paint (ft_face, opaque_paint, &paint)) + return; + + switch (paint.format) + { + case FT_COLR_PAINTFORMAT_COLR_LAYERS: + { + FT_OpaquePaint other_paint = {0}; + while (FT_Get_Paint_Layers (ft_face, + &paint.u.colr_layers.layer_iterator, + &other_paint)) + { + c->funcs->push_group (c->data); + c->recurse (other_paint); + c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); + } + } + break; + case FT_COLR_PAINTFORMAT_SOLID: + { + bool is_foreground = paint.u.solid.color.palette_index == 0xFFFF; + hb_color_t color; + if (is_foreground) + color = HB_COLOR (hb_color_get_blue (c->foreground), + hb_color_get_green (c->foreground), + hb_color_get_red (c->foreground), + (hb_color_get_alpha (c->foreground) * paint.u.solid.color.alpha) >> 14); + else + { + if (c->funcs->custom_palette_color (c->data, paint.u.solid.color.palette_index, &color)) + { + color = HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + (hb_color_get_alpha (color) * paint.u.solid.color.alpha) >> 14); + } + else + { + FT_Color ft_color = c->palette[paint.u.solid.color.palette_index]; + color = HB_COLOR (ft_color.blue, + ft_color.green, + ft_color.red, + (ft_color.alpha * paint.u.solid.color.alpha) >> 14); + } + } + c->funcs->color (c->data, is_foreground, color); + } + break; + case FT_COLR_PAINTFORMAT_LINEAR_GRADIENT: + { + hb_color_line_t cl = { + &paint.u.linear_gradient.colorline, + _hb_ft_color_line_get_color_stops, c, + _hb_ft_color_line_get_extend, nullptr + }; + + c->funcs->linear_gradient (c->data, &cl, + paint.u.linear_gradient.p0.x / 65536.f, + paint.u.linear_gradient.p0.y / 65536.f, + paint.u.linear_gradient.p1.x / 65536.f, + paint.u.linear_gradient.p1.y / 65536.f, + paint.u.linear_gradient.p2.x / 65536.f, + paint.u.linear_gradient.p2.y / 65536.f); + } + break; + case FT_COLR_PAINTFORMAT_RADIAL_GRADIENT: + { + hb_color_line_t cl = { + &paint.u.linear_gradient.colorline, + _hb_ft_color_line_get_color_stops, c, + _hb_ft_color_line_get_extend, nullptr + }; + + c->funcs->radial_gradient (c->data, &cl, + paint.u.radial_gradient.c0.x / 65536.f, + paint.u.radial_gradient.c0.y / 65536.f, + paint.u.radial_gradient.r0 / 65536.f, + paint.u.radial_gradient.c1.x / 65536.f, + paint.u.radial_gradient.c1.y / 65536.f, + paint.u.radial_gradient.r1 / 65536.f); + } + break; + case FT_COLR_PAINTFORMAT_SWEEP_GRADIENT: + { + hb_color_line_t cl = { + &paint.u.linear_gradient.colorline, + _hb_ft_color_line_get_color_stops, c, + _hb_ft_color_line_get_extend, nullptr + }; + + c->funcs->sweep_gradient (c->data, &cl, + paint.u.sweep_gradient.center.x / 65536.f, + paint.u.sweep_gradient.center.y / 65536.f, + (paint.u.sweep_gradient.start_angle / 65536.f + 1) * HB_PI, + (paint.u.sweep_gradient.end_angle / 65536.f + 1) * HB_PI); + } + break; + case FT_COLR_PAINTFORMAT_GLYPH: + { + c->funcs->push_inverse_root_transform (c->data, c->font); + c->ft_font->lock.unlock (); + c->funcs->push_clip_glyph (c->data, paint.u.glyph.glyphID, c->font); + c->ft_font->lock.lock (); + c->funcs->push_root_transform (c->data, c->font); + c->recurse (paint.u.glyph.paint); + c->funcs->pop_transform (c->data); + c->funcs->pop_clip (c->data); + c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_COLR_GLYPH: + { + FT_OpaquePaint other_paint = {0}; + if (FT_Get_Color_Glyph_Paint (ft_face, paint.u.colr_glyph.glyphID, + FT_COLOR_NO_ROOT_TRANSFORM, + &other_paint)) + { + bool has_clip_box; + FT_ClipBox clip_box; + has_clip_box = FT_Get_Color_Glyph_ClipBox (ft_face, paint.u.colr_glyph.glyphID, &clip_box); + + if (has_clip_box) + { + /* The FreeType ClipBox is in scaled coordinates, whereas we need + * unscaled clipbox here. Oh well... + */ + + float upem = c->font->face->get_upem (); + float xscale = upem / (c->font->x_scale ? c->font->x_scale : upem); + float yscale = upem / (c->font->y_scale ? c->font->y_scale : upem); + + c->funcs->push_clip_rectangle (c->data, + clip_box.bottom_left.x * xscale, + clip_box.bottom_left.y * yscale, + clip_box.top_right.x * xscale, + clip_box.top_right.y * yscale); + } + + c->recurse (other_paint); + + if (has_clip_box) + c->funcs->pop_clip (c->data); + } + } + break; + case FT_COLR_PAINTFORMAT_TRANSFORM: + { + c->funcs->push_transform (c->data, + paint.u.transform.affine.xx / 65536.f, + paint.u.transform.affine.yx / 65536.f, + paint.u.transform.affine.xy / 65536.f, + paint.u.transform.affine.yy / 65536.f, + paint.u.transform.affine.dx / 65536.f, + paint.u.transform.affine.dy / 65536.f); + c->recurse (paint.u.transform.paint); + c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_TRANSLATE: + { + float dx = paint.u.translate.dx / 65536.f; + float dy = paint.u.translate.dy / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, dx, dy); + c->recurse (paint.u.translate.paint); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_SCALE: + { + float dx = paint.u.scale.center_x / 65536.f; + float dy = paint.u.scale.center_y / 65536.f; + float sx = paint.u.scale.scale_x / 65536.f; + float sy = paint.u.scale.scale_y / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, +dx, +dy); + bool p2 = c->funcs->push_scale (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -dx, -dy); + c->recurse (paint.u.scale.paint); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_ROTATE: + { + float dx = paint.u.rotate.center_x / 65536.f; + float dy = paint.u.rotate.center_y / 65536.f; + float a = paint.u.rotate.angle / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, +dx, +dy); + bool p2 = c->funcs->push_rotate (c->data, a); + bool p3 = c->funcs->push_translate (c->data, -dx, -dy); + c->recurse (paint.u.rotate.paint); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_SKEW: + { + float dx = paint.u.skew.center_x / 65536.f; + float dy = paint.u.skew.center_y / 65536.f; + float sx = paint.u.skew.x_skew_angle / 65536.f; + float sy = paint.u.skew.y_skew_angle / 65536.f; + + bool p1 = c->funcs->push_translate (c->data, +dx, +dy); + bool p2 = c->funcs->push_skew (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -dx, -dy); + c->recurse (paint.u.skew.paint); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + break; + case FT_COLR_PAINTFORMAT_COMPOSITE: + { + c->recurse (paint.u.composite.backdrop_paint); + c->funcs->push_group (c->data); + c->recurse (paint.u.composite.source_paint); + c->funcs->pop_group (c->data, _hb_ft_paint_composite_mode (paint.u.composite.composite_mode)); + } + break; + + case FT_COLR_PAINT_FORMAT_MAX: break; + default: HB_FALLTHROUGH; + case FT_COLR_PAINTFORMAT_UNSUPPORTED: break; + } +} + + +static bool +hb_ft_paint_glyph_colr (hb_font_t *font, + void *font_data, + hb_codepoint_t gid, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Face ft_face = ft_font->ft_face; + + /* Face is locked. */ + + FT_Error error; + FT_Color* palette; + FT_LayerIterator iterator; + + FT_Bool have_layers; + FT_UInt layer_glyph_index; + FT_UInt layer_color_index; + + error = FT_Palette_Select(ft_face, palette_index, &palette); + if (error) + palette = NULL; + + /* COLRv1 */ + FT_OpaquePaint paint = {0}; + if (FT_Get_Color_Glyph_Paint (ft_face, gid, + FT_COLOR_NO_ROOT_TRANSFORM, + &paint)) + { + hb_ft_paint_context_t c (ft_font, font, + paint_funcs, paint_data, + palette, palette_index, foreground); + + bool is_bounded = true; + FT_ClipBox clip_box; + if (FT_Get_Color_Glyph_ClipBox (ft_face, gid, &clip_box)) + { + c.funcs->push_clip_rectangle (c.data, + clip_box.bottom_left.x + + roundf (hb_min (font->slant_xy * clip_box.bottom_left.y, + font->slant_xy * clip_box.top_left.y)), + clip_box.bottom_left.y, + clip_box.top_right.x + + roundf (hb_max (font->slant_xy * clip_box.bottom_right.y, + font->slant_xy * clip_box.top_right.y)), + clip_box.top_right.y); + } + else + { + + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + hb_ft_paint_context_t ce (ft_font, font, + extents_funcs, &extents_data, + palette, palette_index, foreground); + ce.funcs->push_root_transform (ce.data, font); + ce.recurse (paint); + ce.funcs->pop_transform (ce.data); + hb_extents_t extents = extents_data.get_extents (); + is_bounded = extents_data.is_bounded (); + + c.funcs->push_clip_rectangle (c.data, + extents.xmin, + extents.ymin, + extents.xmax, + extents.ymax); + } + + c.funcs->push_root_transform (c.data, font); + + if (is_bounded) + c.recurse (paint); + + c.funcs->pop_transform (c.data); + c.funcs->pop_clip (c.data); + + return true; + } + + /* COLRv0 */ + iterator.p = NULL; + have_layers = FT_Get_Color_Glyph_Layer(ft_face, + gid, + &layer_glyph_index, + &layer_color_index, + &iterator); + + if (palette && have_layers) + { + do + { + hb_bool_t is_foreground = true; + hb_color_t color = foreground; + + if ( layer_color_index != 0xFFFF ) + { + FT_Color layer_color = palette[layer_color_index]; + color = HB_COLOR (layer_color.blue, + layer_color.green, + layer_color.red, + layer_color.alpha); + is_foreground = false; + } + + ft_font->lock.unlock (); + paint_funcs->push_clip_glyph (paint_data, layer_glyph_index, font); + ft_font->lock.lock (); + paint_funcs->color (paint_data, is_foreground, color); + paint_funcs->pop_clip (paint_data); + + } while (FT_Get_Color_Glyph_Layer(ft_face, + gid, + &layer_glyph_index, + &layer_color_index, + &iterator)); + return true; + } + + return false; +} + + +#endif /* HB_FT_COLR_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ft.cc b/third_party/harfbuzz-ng/src/src/hb-ft.cc index 1626b9a15005..1105862fbc9f 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ft.cc +++ b/third_party/harfbuzz-ng/src/src/hb-ft.cc @@ -33,17 +33,22 @@ #include "hb-ft.h" +#include "hb-cache.hh" #include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" -#include "hb-cache.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-shaper-arabic-pua.hh" +#include "hb-paint.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_OUTLINE_H #include FT_TRUETYPE_TABLES_H +#include FT_SYNTHESIS_H +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 +#include FT_COLOR_H +#endif /** @@ -89,7 +94,7 @@ struct hb_ft_font_t bool unref; /* Whether to destroy ft_face when done. */ bool transform; /* Whether to apply FT_Face's transform. */ - mutable hb_mutex_t lock; + mutable hb_mutex_t lock; /* Protects members below. */ FT_Face ft_face; mutable unsigned cached_serial; mutable hb_ft_advance_cache_t advance_cache; @@ -125,8 +130,6 @@ _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); @@ -157,9 +160,9 @@ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { #ifdef HAVE_FT_GET_TRANSFORM /* Bitmap font, eg. bitmap color emoji. */ - /* TODO Pick largest size? */ - int x_scale = ft_face->available_sizes[0].x_ppem; - int y_scale = ft_face->available_sizes[0].y_ppem; + /* Pick largest size? */ + int x_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].x_ppem; + int y_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].y_ppem; FT_Set_Char_Size (ft_face, x_scale, y_scale, 0, 0); @@ -224,6 +227,9 @@ _hb_ft_hb_font_check_changed (hb_font_t *font, * For more information, see * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * * Since: 1.0.5 **/ void @@ -249,7 +255,10 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) * For more information, see * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * - * Return value: FT_Load_Glyph flags found + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * + * Return value: FT_Load_Glyph flags found, or 0 * * Since: 1.0.5 **/ @@ -271,6 +280,9 @@ hb_ft_font_get_load_flags (hb_font_t *font) * Fetches the FT_Face associated with the specified #hb_font_t * font object. * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * * Return value: (nullable): the FT_Face found or `NULL` * * Since: 0.9.2 @@ -290,8 +302,13 @@ hb_ft_font_get_face (hb_font_t *font) * hb_ft_font_lock_face: (skip) * @font: #hb_font_t to work upon * - * Gets the FT_Face associated with @font, This face will be kept around until - * you call hb_ft_font_unlock_face(). + * Gets the FT_Face associated with @font. + * + * This face will be kept around and access to the FT_Face object + * from other HarfBuzz API wil be blocked until you call hb_ft_font_unlock_face(). + * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). * * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL` * Since: 2.6.5 @@ -431,6 +448,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_position_t *orig_first_advance = first_advance; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; @@ -441,6 +459,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; } else #endif @@ -459,13 +478,29 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, else { FT_Get_Advance (ft_face, glyph, load_flags, &v); + /* Work around bug that FreeType seems to return negative advance + * for variable-set fonts if x_scale is negative! */ + v = abs (v); + v = (int) (v * x_mult + (1<<9)) >> 10; ft_font->advance_cache.set (glyph, v); } - *first_advance = (int) (v * x_mult + (1<<9)) >> 10; + *first_advance = v; first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + + if (font->x_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? x_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #ifndef HB_NO_VERTICAL @@ -485,6 +520,7 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, FT_Matrix matrix; FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -500,7 +536,8 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, /* 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; + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); } #endif @@ -523,7 +560,9 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -578,13 +617,16 @@ hb_ft_get_glyph_extents (hb_font_t *font, hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; float x_mult, y_mult; + float slant_xy = font->slant_xy; #ifdef HAVE_FT_GET_TRANSFORM if (ft_font->transform) { FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -596,10 +638,40 @@ hb_ft_get_glyph_extents (hb_font_t *font, if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; - extents->x_bearing = (hb_position_t) (x_mult * ft_face->glyph->metrics.horiBearingX); - extents->y_bearing = (hb_position_t) (y_mult * ft_face->glyph->metrics.horiBearingY); - extents->width = (hb_position_t) (x_mult * ft_face->glyph->metrics.width); - extents->height = (hb_position_t) (y_mult * -ft_face->glyph->metrics.height); + /* Copied from hb_font_t::scale_glyph_extents. */ + + float x1 = x_mult * ft_face->glyph->metrics.horiBearingX; + float y1 = y_mult * ft_face->glyph->metrics.horiBearingY; + float x2 = x1 + x_mult * ft_face->glyph->metrics.width; + float y2 = y1 + y_mult * -ft_face->glyph->metrics.height; + + /* Apply slant. */ + if (slant_xy) + { + x1 += hb_min (y1 * slant_xy, y2 * slant_xy); + x2 += hb_max (y1 * slant_xy, y2 * slant_xy); + } + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; + + if (font->x_strength || font->y_strength) + { + /* Y */ + int y_shift = font->y_strength; + if (font->y_scale < 0) y_shift = -y_shift; + extents->y_bearing += y_shift; + extents->height -= y_shift; + + /* X */ + int x_shift = font->x_strength; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->embolden_in_place) + extents->x_bearing -= x_shift / 2; + extents->width += x_shift; + } return true; } @@ -700,6 +772,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, FT_Matrix matrix; FT_Get_Transform (ft_face, &matrix, nullptr); y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; } else #endif @@ -721,7 +794,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); } - metrics->ascender = (hb_position_t) (y_mult * metrics->ascender); + metrics->ascender = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength)); metrics->descender = (hb_position_t) (y_mult * metrics->descender); metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); @@ -773,11 +846,11 @@ _hb_ft_cubic_to (const FT_Vector *control1, } static void -hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data HB_UNUSED) +hb_ft_draw_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + 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); @@ -801,12 +874,129 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + /* Embolden */ + if (font->x_strength || font->y_strength) + { + FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength); + + int x_shift = 0; + int y_shift = 0; + if (font->embolden_in_place) + { + /* Undo the FreeType shift. */ + x_shift = -font->x_strength / 2; + y_shift = 0; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + else + { + /* FreeType applied things in the wrong direction for negative scale; fix up. */ + if (font->x_scale < 0) x_shift = -font->x_strength; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + if (x_shift || y_shift) + { + auto &outline = ft_face->glyph->outline; + for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1)) + { + point.x += x_shift; + point.y += y_shift; + } + } + } + + FT_Outline_Decompose (&ft_face->glyph->outline, &outline_funcs, &draw_session); } #endif +#ifndef HB_NO_PAINT +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 + +#include "hb-ft-colr.hh" + +static void +hb_ft_paint_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t gid, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data) +{ + 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; + + /* We release the lock before calling into glyph callbacks, such that + * eg. draw API can call back into the face.*/ + + if (unlikely (FT_Load_Glyph (ft_face, gid, + ft_font->load_flags | FT_LOAD_COLOR))) + return; + + if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + if (hb_ft_paint_glyph_colr (font, font_data, gid, + paint_funcs, paint_data, + palette_index, foreground, + user_data)) + return; + + /* Simple outline. */ + ft_font->lock.unlock (); + paint_funcs->push_clip_glyph (paint_data, gid, font); + ft_font->lock.lock (); + paint_funcs->color (paint_data, true, foreground); + paint_funcs->pop_clip (paint_data); + + return; + } + + auto *glyph = ft_face->glyph; + if (glyph->format == FT_GLYPH_FORMAT_BITMAP) + { + auto &bitmap = glyph->bitmap; + if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + if (bitmap.pitch != (signed) bitmap.width * 4) + return; + + ft_font->lock.unlock (); + + hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer, + bitmap.pitch * bitmap.rows, + HB_MEMORY_MODE_DUPLICATE, + nullptr, nullptr); + + hb_glyph_extents_t extents; + if (!hb_font_get_glyph_extents (font, gid, &extents)) + goto out; + + if (!paint_funcs->image (paint_data, + blob, + bitmap.width, + bitmap.rows, + HB_PAINT_IMAGE_FORMAT_BGRA, + font->slant_xy, + &extents)) + { + /* TODO Try a forced outline load and paint? */ + } + + out: + hb_blob_destroy (blob); + ft_font->lock.lock (); + } + + return; + } +} +#endif +#endif + static inline void free_static_ft_funcs (); @@ -840,7 +1030,13 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t= 21300 + hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr); +#endif #endif hb_font_funcs_make_immutable (funcs); @@ -915,6 +1111,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This variant of the function does not provide any life-cycle management. * * Most client programs should use hb_ft_face_create_referenced() @@ -959,6 +1159,10 @@ hb_ft_face_create (FT_Face ft_face, * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This is the preferred variant of the hb_ft_face_create* * function family, because it calls FT_Reference_Face() on @ft_face, * ensuring that @ft_face remains alive as long as the resulting @@ -991,6 +1195,10 @@ hb_ft_face_finalize (void *arg) * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This variant of the function caches the newly created #hb_face_t * face object, using the @generic pointer of @ft_face. Subsequent function * calls that are passed the same @ft_face parameter will have the same @@ -1241,10 +1449,14 @@ _release_blob (void *arg) * created with hb_face_create(), and therefore was not * initially configured to use FreeType font functions. * - * An #hb_face_t face object created with hb_ft_face_create() + * An #hb_font_t object created with hb_ft_font_create() * is preconfigured for FreeType font functions and does not * require this function to be used. * + * Note that if you modify the underlying #hb_font_t after + * calling this function, you need to call hb_ft_hb_font_changed() + * to update the underlying FT_Face. + * * Note: Internally, this function creates an FT_Face. * * @@ -1285,5 +1497,4 @@ hb_ft_font_set_funcs (hb_font_t *font) _hb_ft_hb_font_changed (font, ft_face); } - #endif diff --git a/third_party/harfbuzz-ng/src/src/hb-glib.cc b/third_party/harfbuzz-ng/src/src/hb-glib.cc index 8ddc7ebad8fe..1da81696e75d 100644 --- a/third_party/harfbuzz-ng/src/src/hb-glib.cc +++ b/third_party/harfbuzz-ng/src/src/hb-glib.cc @@ -129,32 +129,9 @@ hb_glib_unicode_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if GLIB_CHECK_VERSION(2,29,12) return g_unichar_compose (a, b, ab); +#else + return false; #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 @@ -166,55 +143,9 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, { #if GLIB_CHECK_VERSION(2,29,12) return g_unichar_decompose (ab, a, b); +#else + return false; #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; } diff --git a/third_party/harfbuzz-ng/src/src/hb-gobject-structs.cc b/third_party/harfbuzz-ng/src/src/hb-gobject-structs.cc index ef13f1e966d2..332cc84888dd 100644 --- a/third_party/harfbuzz-ng/src/src/hb-gobject-structs.cc +++ b/third_party/harfbuzz-ng/src/src/hb-gobject-structs.cc @@ -91,6 +91,7 @@ hb_gobject_##name##_get_type () \ HB_DEFINE_OBJECT_TYPE (buffer) HB_DEFINE_OBJECT_TYPE (blob) HB_DEFINE_OBJECT_TYPE (draw_funcs) +HB_DEFINE_OBJECT_TYPE (paint_funcs) HB_DEFINE_OBJECT_TYPE (face) HB_DEFINE_OBJECT_TYPE (font) HB_DEFINE_OBJECT_TYPE (font_funcs) @@ -102,8 +103,12 @@ 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 (draw_state) +HB_DEFINE_VALUE_TYPE (color_stop) +HB_DEFINE_VALUE_TYPE (color_line) HB_DEFINE_VALUE_TYPE (user_data_key) +HB_DEFINE_VALUE_TYPE (ot_var_axis_info) HB_DEFINE_VALUE_TYPE (ot_math_glyph_variant) HB_DEFINE_VALUE_TYPE (ot_math_glyph_part) diff --git a/third_party/harfbuzz-ng/src/src/hb-gobject-structs.h b/third_party/harfbuzz-ng/src/src/hb-gobject-structs.h index 3914a2431aed..b7b5f55ce671 100644 --- a/third_party/harfbuzz-ng/src/src/hb-gobject-structs.h +++ b/third_party/harfbuzz-ng/src/src/hb-gobject-structs.h @@ -52,6 +52,10 @@ HB_EXTERN GType hb_gobject_draw_funcs_get_type (void); #define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ()) +HB_EXTERN GType +hb_gobject_paint_funcs_get_type (void); +#define HB_GOBJECT_TYPE_PAINT_FUNCS (hb_gobject_paint_funcs_get_type ()) + HB_EXTERN GType hb_gobject_face_get_type (void); #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ()) @@ -98,10 +102,26 @@ 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_draw_state_get_type (void); +#define HB_GOBJECT_TYPE_DRAW_STATE (hb_gobject_draw_state_get_type ()) + +HB_EXTERN GType +hb_gobject_color_stop_get_type (void); +#define HB_GOBJECT_TYPE_COLOR_STOP (hb_gobject_color_stop_get_type ()) + +HB_EXTERN GType +hb_gobject_color_line_get_type (void); +#define HB_GOBJECT_TYPE_COLOR_LINE (hb_gobject_color_line_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_var_axis_info_get_type (void); +#define HB_GOBJECT_TYPE_OT_VAR_AXIS_INFO (hb_gobject_ot_var_axis_info_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 ()) diff --git a/third_party/harfbuzz-ng/src/src/hb-graphite2.cc b/third_party/harfbuzz-ng/src/src/hb-graphite2.cc index 4d0e687c7553..9e068f8d84d2 100644 --- a/third_party/harfbuzz-ng/src/src/hb-graphite2.cc +++ b/third_party/harfbuzz-ng/src/src/hb-graphite2.cc @@ -318,7 +318,7 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, #undef ALLOCATE_ARRAY - memset (clusters, 0, sizeof (clusters[0]) * buffer->len); + hb_memset (clusters, 0, sizeof (clusters[0]) * buffer->len); hb_codepoint_t *pg = gids; clusters[0].cluster = buffer->info[0].cluster; diff --git a/third_party/harfbuzz-ng/src/src/hb-graphite2.h b/third_party/harfbuzz-ng/src/src/hb-graphite2.h index f299da9f71c9..ee9229b8b004 100644 --- a/third_party/harfbuzz-ng/src/src/hb-graphite2.h +++ b/third_party/harfbuzz-ng/src/src/hb-graphite2.h @@ -49,7 +49,8 @@ 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_DEPRECATED_FOR (hb_graphite2_face_get_gr_face) +HB_EXTERN gr_font * hb_graphite2_font_get_gr_font (hb_font_t *font); #endif diff --git a/third_party/harfbuzz-ng/src/src/hb-iter.hh b/third_party/harfbuzz-ng/src/src/hb-iter.hh index 1a3ab43de03e..b123b2f27cf9 100644 --- a/third_party/harfbuzz-ng/src/src/hb-iter.hh +++ b/third_party/harfbuzz-ng/src/src/hb-iter.hh @@ -73,8 +73,10 @@ struct hb_iter_t /* 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__ (); } + iter_t _begin () const { return *thiz(); } + iter_t begin () const { return _begin (); } + iter_t _end () const { return thiz()->__end__ (); } + iter_t end () const { return _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 @@ -118,7 +120,9 @@ struct hb_iter_t #define HB_ITER_USING(Name) \ using item_t = typename Name::item_t; \ + using Name::_begin; \ using Name::begin; \ + using Name::_end; \ using Name::end; \ using Name::get_item_size; \ using Name::is_iterator; \ @@ -168,10 +172,16 @@ struct HB_FUNCOBJ (hb_iter); struct { - template unsigned - operator () (T&& c) const - { return c.len (); } + template auto + impl (T&& c, hb_priority<1>) const HB_RETURN (unsigned, c.len ()) + + template auto + impl (T&& c, hb_priority<0>) const HB_RETURN (unsigned, c.len) + + public: + template auto + operator () (T&& c) const HB_RETURN (unsigned, impl (std::forward (c), hb_prioritize)) } HB_FUNCOBJ (hb_len); @@ -377,7 +387,7 @@ struct hb_map_iter_t : 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); } + 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; } @@ -440,7 +450,7 @@ struct hb_filter_iter_t : 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); } + 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; } @@ -553,7 +563,7 @@ struct hb_zip_iter_t : 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 ()); } + 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 @@ -637,7 +647,7 @@ struct hb_concat_iter_t : } } - hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); } + hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a._end (), b._end ()); } bool operator != (const hb_concat_iter_t& o) const { return a != o.a diff --git a/third_party/harfbuzz-ng/src/src/hb-limits.hh b/third_party/harfbuzz-ng/src/src/hb-limits.hh new file mode 100644 index 000000000000..0f60e9e21013 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-limits.hh @@ -0,0 +1,109 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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_LIMITS_HH +#define HB_LIMITS_HH + +#include "hb.hh" + + +#ifndef HB_BUFFER_MAX_LEN_FACTOR +#define HB_BUFFER_MAX_LEN_FACTOR 64 +#endif +#ifndef HB_BUFFER_MAX_LEN_MIN +#define HB_BUFFER_MAX_LEN_MIN 16384 +#endif +#ifndef HB_BUFFER_MAX_LEN_DEFAULT +#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ +#endif + +#ifndef HB_BUFFER_MAX_OPS_FACTOR +#define HB_BUFFER_MAX_OPS_FACTOR 1024 +#endif +#ifndef HB_BUFFER_MAX_OPS_MIN +#define HB_BUFFER_MAX_OPS_MIN 16384 +#endif +#ifndef HB_BUFFER_MAX_OPS_DEFAULT +#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ +#endif + + +#ifndef HB_MAX_NESTING_LEVEL +#define HB_MAX_NESTING_LEVEL 64 +#endif + + +#ifndef HB_MAX_CONTEXT_LENGTH +#define HB_MAX_CONTEXT_LENGTH 64 +#endif + +#ifndef HB_CLOSURE_MAX_STAGES +/* + * The maximum number of times a lookup can be applied during shaping. + * Used to limit the number of iterations of the closure algorithm. + * This must be larger than the number of times add_gsub_pause() is + * called in a collect_features call of any shaper. + */ +#define HB_CLOSURE_MAX_STAGES 12 +#endif + +#ifndef HB_MAX_SCRIPTS +#define HB_MAX_SCRIPTS 500 +#endif + +#ifndef HB_MAX_LANGSYS +#define HB_MAX_LANGSYS 2000 +#endif + +#ifndef HB_MAX_LANGSYS_FEATURE_COUNT +#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 +#endif + +#ifndef HB_MAX_FEATURE_INDICES +#define HB_MAX_FEATURE_INDICES 1500 +#endif + +#ifndef HB_MAX_LOOKUP_VISIT_COUNT +#define HB_MAX_LOOKUP_VISIT_COUNT 35000 +#endif + + +#ifndef HB_GLYF_MAX_POINTS +#define HB_GLYF_MAX_POINTS 20000 +#endif + +#ifndef HB_GLYF_MAX_EDGE_COUNT +#define HB_GLYF_MAX_EDGE_COUNT 1024 +#endif + +#ifndef HB_CFF_MAX_OPS +#define HB_CFF_MAX_OPS 10000 +#endif + +#ifndef HB_COLRV1_MAX_EDGE_COUNT +#define HB_COLRV1_MAX_EDGE_COUNT 1024 +#endif + + +#endif /* HB_LIMITS_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-machinery.hh b/third_party/harfbuzz-ng/src/src/hb-machinery.hh index 2571f22e154f..1084725af2ad 100644 --- a/third_party/harfbuzz-ng/src/src/hb-machinery.hh +++ b/third_party/harfbuzz-ng/src/src/hb-machinery.hh @@ -34,7 +34,6 @@ #include "hb-dispatch.hh" #include "hb-sanitize.hh" -#include "hb-serialize.hh" /* @@ -136,6 +135,13 @@ static inline Type& StructAfter(TObject &X) /* * Lazy loaders. + * + * The lazy-loaders are thread-safe pointer-like objects that create their + * instead on-demand. They also support access to a "data" object that is + * necessary for creating their instance. The data object, if specified, + * is accessed via pointer math, located at a location before the position + * of the loader itself. This avoids having to store a pointer to data + * for every lazy-loader. Multiple lazy-loaders can access the same data. */ template @@ -228,7 +234,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t bool cmpexch (Stored *current, Stored *value) const { - /* This *must* be called when there are no other threads accessing. */ + /* This function can only be safely called directly if no + * other thread is accessing. */ return this->instance.cmpexch (current, value); } @@ -261,7 +268,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t hb_free (p); } -// private: + private: /* Must only have one pointer. */ hb_atomic_ptr_t instance; }; @@ -283,7 +290,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t (face); } static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } @@ -297,22 +304,22 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_tget_stored (); } }; -template -struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t -{ - 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 -struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t -{ - 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 (); } -}; +#define HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T(Type) \ + template \ + struct hb_##Type##_funcs_lazy_loader_t : hb_lazy_loader_t \ + { \ + static void destroy (hb_##Type##_funcs_t *p) \ + { hb_##Type##_funcs_destroy (p); } \ + static const hb_##Type##_funcs_t *get_null () \ + { return hb_##Type##_funcs_get_empty (); } \ + } + +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (font); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (unicode); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (draw); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (paint); + +#undef HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T #endif /* HB_MACHINERY_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-map.cc b/third_party/harfbuzz-ng/src/src/hb-map.cc index 5c5f5de59e93..5d67cd9a12d7 100644 --- a/third_party/harfbuzz-ng/src/src/hb-map.cc +++ b/third_party/harfbuzz-ng/src/src/hb-map.cc @@ -174,7 +174,7 @@ hb_map_allocation_successful (const hb_map_t *map) * * Allocate a copy of @map. * - * Return value: Newly-allocated map. + * Return value: (transfer full): Newly-allocated map. * * Since: 4.4.0 **/ @@ -182,9 +182,10 @@ hb_map_t * hb_map_copy (const hb_map_t *map) { hb_map_t *copy = hb_map_create (); - if (unlikely (!copy)) return nullptr; - copy->resize (map->population); - hb_copy (*map, *copy); + if (unlikely (copy->in_error ())) + return hb_map_get_empty (); + + *copy = *map; return copy; } @@ -335,9 +336,84 @@ hb_map_is_equal (const hb_map_t *map, * * Since: 4.4.0 **/ -HB_EXTERN unsigned int +unsigned int hb_map_hash (const hb_map_t *map) { return map->hash (); } +/** + * hb_map_update: + * @map: A map + * @other: Another map + * + * Add the contents of @other to @map. + * + * Since: 7.0.0 + **/ +HB_EXTERN void +hb_map_update (hb_map_t *map, + const hb_map_t *other) +{ + map->update (*other); +} + +/** + * hb_map_next: + * @map: A map + * @idx: (inout): Iterator internal state + * @key: (out): Key retrieved + * @value: (out): Value retrieved + * + * Fetches the next key/value paire in @map. + * + * Set @idx to -1 to get started. + * + * If the map is modified during iteration, the behavior is undefined. + * + * The order in which the key/values are returned is undefined. + * + * Return value: `true` if there was a next value, `false` otherwise + * + * Since: 7.0.0 + **/ +hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value) +{ + return map->next (idx, key, value); +} + +/** + * hb_map_keys: + * @map: A map + * @keys: A set + * + * Add the keys of @map to @keys. + * + * Since: 7.0.0 + **/ +void +hb_map_keys (const hb_map_t *map, + hb_set_t *keys) +{ + hb_copy (map->keys() , *keys); +} + +/** + * hb_map_values: + * @map: A map + * @values: A set + * + * Add the values of @map to @values. + * + * Since: 7.0.0 + **/ +void +hb_map_values (const hb_map_t *map, + hb_set_t *values) +{ + hb_copy (map->values() , *values); +} diff --git a/third_party/harfbuzz-ng/src/src/hb-map.h b/third_party/harfbuzz-ng/src/src/hb-map.h index 3a067c5c73b0..e928628fa7a2 100644 --- a/third_party/harfbuzz-ng/src/src/hb-map.h +++ b/third_party/harfbuzz-ng/src/src/hb-map.h @@ -32,6 +32,7 @@ #define HB_MAP_H #include "hb-common.h" +#include "hb-set.h" HB_BEGIN_DECLS @@ -118,6 +119,24 @@ HB_EXTERN hb_bool_t hb_map_has (const hb_map_t *map, hb_codepoint_t key); +HB_EXTERN void +hb_map_update (hb_map_t *map, + const hb_map_t *other); + +/* Pass -1 in for idx to get started. */ +HB_EXTERN hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value); + +HB_EXTERN void +hb_map_keys (const hb_map_t *map, + hb_set_t *keys); + +HB_EXTERN void +hb_map_values (const hb_map_t *map, + hb_set_t *values); HB_END_DECLS diff --git a/third_party/harfbuzz-ng/src/src/hb-map.hh b/third_party/harfbuzz-ng/src/src/hb-map.hh index 30a8e627d22c..041b8829afbf 100644 --- a/third_party/harfbuzz-ng/src/src/hb-map.hh +++ b/third_party/harfbuzz-ng/src/src/hb-map.hh @@ -29,6 +29,8 @@ #include "hb.hh" +#include "hb-set.hh" + /* * hb_hashmap_t @@ -43,9 +45,9 @@ struct hb_hashmap_t hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); } + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); } hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; } + hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list> lst) : hb_hashmap_t () @@ -71,6 +73,11 @@ struct hb_hashmap_t uint32_t is_tombstone_ : 1; V value; + item_t () : key (), + hash (0), + is_used_ (false), is_tombstone_ (false), + value () {} + bool is_used () const { return is_used_; } void set_used (bool is_used) { is_used_ = is_used; } bool is_tombstone () const { return is_tombstone_; } @@ -88,17 +95,8 @@ struct hb_hashmap_t return minus_1; }; - void clear () - { - new (std::addressof (key)) K (); - new (std::addressof (value)) V (); - hash = 0; - is_used_ = false; - is_tombstone_ = false; - } - - bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } - bool operator == (const item_t &o) { return *this == o.key; } + bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); } + bool operator == (const item_t &o) const { return *this == o.key; } hb_pair_t get_pair() const { return hb_pair_t (key, value); } hb_pair_t get_pair_ref() const { return hb_pair_t (key, value); } @@ -107,8 +105,8 @@ struct hb_hashmap_t }; hb_object_header_t header; - bool successful; /* Allocations successful */ - unsigned int population; /* Not including tombstones. */ + unsigned int successful : 1; /* Allocations successful */ + unsigned int population : 31; /* Not including tombstones. */ unsigned int occupancy; /* Including tombstones. */ unsigned int mask; unsigned int prime; @@ -118,7 +116,10 @@ struct hb_hashmap_t { if (unlikely (!a.successful || !b.successful)) return; - hb_swap (a.population, b.population); + unsigned tmp = a.population; + a.population = b.population; + b.population = tmp; + //hb_swap (a.population, b.population); hb_swap (a.occupancy, b.occupancy); hb_swap (a.mask, b.mask); hb_swap (a.prime, b.prime); @@ -160,7 +161,9 @@ struct hb_hashmap_t { if (unlikely (!successful)) return false; - unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8); + if (new_population != 0 && (new_population + new_population / 2) < mask) return true; + + unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -169,9 +172,9 @@ struct hb_hashmap_t return false; } for (auto &_ : hb_iter (new_items, new_size)) - _.clear (); + new (&_) item_t (); - unsigned int old_size = mask + 1; + unsigned int old_size = size (); item_t *old_items = items; /* Switch to new, empty, array. */ @@ -181,47 +184,82 @@ struct hb_hashmap_t items = new_items; /* Insert back old items. */ - if (old_items) - for (unsigned int i = 0; i < old_size; i++) + for (unsigned int i = 0; i < old_size; i++) + { + if (old_items[i].is_real ()) { - if (old_items[i].is_real ()) - { - set_with_hash (old_items[i].key, - old_items[i].hash, - std::move (old_items[i].value)); - } - old_items[i].~item_t (); + set_with_hash (std::move (old_items[i].key), + old_items[i].hash, + std::move (old_items[i].value)); } + old_items[i].~item_t (); + } hb_free (old_items); return true; } + template + bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false) + { + if (unlikely (!successful)) return false; + if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; + item_t &item = item_for_hash (key, hash); + + if (is_delete && !(item == key)) + return true; /* Trying to delete non-existent key. */ + + if (item.is_used ()) + { + occupancy--; + if (!item.is_tombstone ()) + population--; + } + + item.key = std::forward (key); + item.value = std::forward (value); + item.hash = hash; + item.set_used (true); + item.set_tombstone (is_delete); + + occupancy++; + if (!is_delete) + population++; + + return true; + } + template - bool set (K key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward (value)); } + bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward (value)); } + template + bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward (value)); } - const V& get (K key) const + const V& get_with_hash (const K &key, uint32_t hash) const + { + if (unlikely (!items)) return item_t::default_value (); + auto &item = item_for_hash (key, hash); + return item.is_real () && item == key ? item.value : item_t::default_value (); + } + const V& get (const K &key) const { if (unlikely (!items)) return item_t::default_value (); - unsigned int i = bucket_for (key); - return items[i].is_real () && items[i] == key ? items[i].value : item_t::default_value (); + return get_with_hash (key, hb_hash (key)); } - void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } + void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } /* Has interface. */ - typedef const V& value_t; - value_t operator [] (K k) const { return get (k); } + const V& operator [] (K k) const { return get (k); } template bool has (K key, VV **vp = nullptr) const { if (unlikely (!items)) return false; - unsigned int i = bucket_for (key); - if (items[i].is_real () && items[i] == key) + auto &item = item_for_hash (key, hb_hash (key)); + if (item.is_real () && item == key) { - if (vp) *vp = std::addressof (items[i].value); + if (vp) *vp = std::addressof (item.value); return true; } else @@ -230,13 +268,18 @@ struct hb_hashmap_t /* Projection. */ V operator () (K k) const { return get (k); } + unsigned size () const { return mask ? mask + 1 : 0; } + void clear () { if (unlikely (!successful)) return; - if (items) - for (auto &_ : hb_iter (items, mask + 1)) - _.clear (); + for (auto &_ : hb_iter (items, size ())) + { + /* Reconstruct items. */ + _.~item_t (); + new (&_) item_t (); + } population = occupancy = 0; } @@ -246,11 +289,10 @@ struct hb_hashmap_t uint32_t hash () const { - uint32_t h = 0; - for (const auto &item : + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real)) - h ^= item.total_hash (); - return h; + return + + iter_items () + | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u) + ; } bool is_equal (const hb_hashmap_t &other) const @@ -258,7 +300,7 @@ struct hb_hashmap_t if (population != other.population) return false; for (auto pair : iter ()) - if (get (pair.first) != pair.second) + if (other.get (pair.first) != pair.second) return false; return true; @@ -268,90 +310,90 @@ struct hb_hashmap_t unsigned int get_population () const { return population; } + void update (const hb_hashmap_t &other) + { + if (unlikely (!successful)) return; + + hb_copy (other, *this); + } + /* * Iterator */ - auto iter () const HB_AUTO_RETURN + + auto iter_items () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) + + hb_iter (items, size ()) | hb_filter (&item_t::is_real) - | hb_map (&item_t::get_pair) ) auto iter_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + iter_items () | hb_map (&item_t::get_pair_ref) ) - auto keys () const HB_AUTO_RETURN + auto iter () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) - | hb_map (&item_t::key) - | hb_map (hb_ridentity) + + iter_items () + | hb_map (&item_t::get_pair) ) auto keys_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + iter_items () | hb_map (&item_t::key) ) - auto values () const HB_AUTO_RETURN + auto keys () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) - | hb_map (&item_t::value) + + iter_items () + | hb_map (&item_t::key) | hb_map (hb_ridentity) ) auto values_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + iter_items () | hb_map (&item_t::value) ) + auto values () const HB_AUTO_RETURN + ( + + iter_items () + | hb_map (&item_t::value) + | hb_map (hb_ridentity) + ) - /* Sink interface. */ - hb_hashmap_t& operator << (const hb_pair_t& v) - { set (v.first, v.second); return *this; } - - protected: - - template - bool set_with_hash (K key, uint32_t hash, VV&& value, bool is_delete=false) + /* C iterator. */ + bool next (int *idx, + K *key, + V *value) const { - if (unlikely (!successful)) return false; - if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; - unsigned int i = bucket_for_hash (key, hash); + unsigned i = (unsigned) (*idx + 1); - if (is_delete && items[i].key != key) - return true; /* Trying to delete non-existent key. */ + unsigned count = size (); + while (i < count && !items[i].is_real ()) + i++; - if (items[i].is_used ()) + if (i >= count) { - occupancy--; - if (!items[i].is_tombstone ()) - population--; + *idx = -1; + return false; } - items[i].key = key; - items[i].value = std::forward (value); - items[i].hash = hash; - items[i].set_used (true); - items[i].set_tombstone (is_delete); - - occupancy++; - if (!is_delete) - population++; + *key = items[i].key; + *value = items[i].value; + *idx = (signed) i; return true; } - unsigned int bucket_for (const K &key) const - { - return bucket_for_hash (key, hb_hash (key)); - } - - unsigned int bucket_for_hash (const K &key, uint32_t hash) const + /* Sink interface. */ + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, v.second); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, std::move (v.second)); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (std::move (v.first), v.second); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (std::move (v.first), std::move (v.second)); return *this; } + + item_t& item_for_hash (const K &key, uint32_t hash) const { hash &= 0x3FFFFFFF; // We only store lower 30bit of hash unsigned int i = hash % prime; @@ -360,12 +402,12 @@ struct hb_hashmap_t while (items[i].is_used ()) { if (items[i].hash == hash && items[i] == key) - return i; + return items[i]; if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) tombstone = i; i = (i + ++step) & mask; } - return tombstone == (unsigned) -1 ? i : tombstone; + return items[tombstone == (unsigned) -1 ? i : tombstone]; } static unsigned int prime_for (unsigned int shift) @@ -444,37 +486,5 @@ struct hb_map_t : hb_hashmap_t -static inline -hb_hashmap_t* hb_hashmap_create () -{ - using hashmap = hb_hashmap_t; - hashmap* map; - if (!(map = hb_object_create ())) - return nullptr; - - return map; -} - -template -static inline -void hb_hashmap_destroy (hb_hashmap_t* map) -{ - if (!hb_object_destroy (map)) - return; - - hb_free (map); -} - -namespace hb { - -template -struct vtable> -{ - static constexpr auto destroy = hb_hashmap_destroy; -}; - -} - #endif /* HB_MAP_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-meta.hh b/third_party/harfbuzz-ng/src/src/hb-meta.hh index 52a6791e3130..31aa7fa6f16b 100644 --- a/third_party/harfbuzz-ng/src/src/hb-meta.hh +++ b/third_party/harfbuzz-ng/src/src/hb-meta.hh @@ -112,8 +112,7 @@ template auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_ident template using hb_add_pointer = decltype (_hb_try_add_pointer (hb_prioritize)); -/* TODO Add feature-parity to std::decay. */ -template using hb_decay = hb_remove_const>; +template using hb_decay = typename std::decay::type; #define hb_is_convertible(From,To) std::is_convertible::value diff --git a/third_party/harfbuzz-ng/src/src/hb-ms-feature-ranges.hh b/third_party/harfbuzz-ng/src/src/hb-ms-feature-ranges.hh index d40fdeaa8247..f7649ab76e4f 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ms-feature-ranges.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ms-feature-ranges.hh @@ -30,6 +30,9 @@ #include "hb.hh" +/* Variations of this code exist in hb-coretext.cc as well + * as hb-aat-map.cc... */ + typedef struct hb_ms_feature_t { uint32_t tag_le; uint32_t value; @@ -166,7 +169,7 @@ hb_ms_setup_features (const hb_feature_t *features, { auto *feature = active_features.lsearch (event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ); + active_features.remove_ordered (feature - active_features.arrayZ); } } diff --git a/third_party/harfbuzz-ng/src/src/hb-multimap.hh b/third_party/harfbuzz-ng/src/src/hb-multimap.hh new file mode 100644 index 000000000000..b4a8cc62a3e3 --- /dev/null +++ b/third_party/harfbuzz-ng/src/src/hb-multimap.hh @@ -0,0 +1,92 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * 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_MULTIMAP_HH +#define HB_MULTIMAP_HH + +#include "hb.hh" +#include "hb-map.hh" +#include "hb-vector.hh" + + +/* + * hb_multimap_t + */ + +struct hb_multimap_t +{ + void add (hb_codepoint_t k, hb_codepoint_t v) + { + hb_codepoint_t *i; + if (multiples_indices.has (k, &i)) + { + multiples_values[*i].push (v); + return; + } + + hb_codepoint_t *old_v; + if (singulars.has (k, &old_v)) + { + hb_codepoint_t old = *old_v; + singulars.del (k); + + multiples_indices.set (k, multiples_values.length); + auto *vec = multiples_values.push (); + + vec->push (old); + vec->push (v); + + return; + } + + singulars.set (k, v); + } + + hb_array_t get (hb_codepoint_t k) const + { + const hb_codepoint_t *v; + if (singulars.has (k, &v)) + return hb_array (v, 1); + + hb_codepoint_t *i; + if (multiples_indices.has (k, &i)) + return multiples_values[*i].as_array (); + + return hb_array_t (); + } + + bool in_error () const + { + return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error (); + } + + protected: + hb_map_t singulars; + hb_map_t multiples_indices; + hb_vector_t> multiples_values; +}; + + + +#endif /* HB_MULTIMAP_HH */ diff --git a/third_party/harfbuzz-ng/src/src/hb-mutex.hh b/third_party/harfbuzz-ng/src/src/hb-mutex.hh index 6914b2245029..e329d9864f1c 100644 --- a/third_party/harfbuzz-ng/src/src/hb-mutex.hh +++ b/third_party/harfbuzz-ng/src/src/hb-mutex.hh @@ -60,7 +60,7 @@ typedef pthread_mutex_t hb_mutex_impl_t; #elif !defined(HB_NO_MT) && !defined(HB_MUTEX_IMPL_STD_MUTEX) && defined(_WIN32) typedef CRITICAL_SECTION hb_mutex_impl_t; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) #else #define hb_mutex_impl_init(M) InitializeCriticalSection (M) @@ -97,6 +97,9 @@ struct hb_mutex_t /* Create space for, but do not initialize m. */ alignas(hb_mutex_impl_t) char m[sizeof (hb_mutex_impl_t)]; + hb_mutex_t () { init (); } + ~hb_mutex_t () { fini (); } + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" void init () { hb_mutex_impl_init ((hb_mutex_impl_t *) m); } @@ -108,10 +111,11 @@ struct hb_mutex_t struct hb_lock_t { - hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); } - ~hb_lock_t () { mutex.unlock (); } + hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); } + hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); } + ~hb_lock_t () { if (mutex) mutex->unlock (); } private: - hb_mutex_t &mutex; + hb_mutex_t *mutex; }; diff --git a/third_party/harfbuzz-ng/src/src/hb-number-parser.hh b/third_party/harfbuzz-ng/src/src/hb-number-parser.hh index 1a9dbba6dd3d..ec68c3a7281a 100644 --- a/third_party/harfbuzz-ng/src/src/hb-number-parser.hh +++ b/third_party/harfbuzz-ng/src/src/hb-number-parser.hh @@ -31,7 +31,7 @@ #include "hb.hh" -#line 35 "hb-number-parser.hh" +#line 32 "hb-number-parser.hh" static const unsigned char _double_parser_trans_keys[] = { 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0 @@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) int cs; -#line 139 "hb-number-parser.hh" +#line 132 "hb-number-parser.hh" { cs = double_parser_start; } -#line 144 "hb-number-parser.hh" +#line 135 "hb-number-parser.hh" { int _slen; int _trans; @@ -198,7 +198,7 @@ _resume: exp_overflow = true; } break; -#line 202 "hb-number-parser.hh" +#line 187 "hb-number-parser.hh" } _again: diff --git a/third_party/harfbuzz-ng/src/src/hb-number.cc b/third_party/harfbuzz-ng/src/src/hb-number.cc index 6e4f3f7ebd0a..c52b284e1d21 100644 --- a/third_party/harfbuzz-ng/src/src/hb-number.cc +++ b/third_party/harfbuzz-ng/src/src/hb-number.cc @@ -24,7 +24,6 @@ */ #include "hb.hh" -#include "hb-machinery.hh" #include "hb-number.hh" #include "hb-number-parser.hh" diff --git a/third_party/harfbuzz-ng/src/src/hb-object.hh b/third_party/harfbuzz-ng/src/src/hb-object.hh index 9876c2923cff..e2c2c3394cb0 100644 --- a/third_party/harfbuzz-ng/src/src/hb-object.hh +++ b/third_party/harfbuzz-ng/src/src/hb-object.hh @@ -69,7 +69,7 @@ struct hb_lockable_set_t item = items.push (v); l.unlock (); } - return item; + return items.in_error () ? nullptr : item; } template @@ -80,7 +80,7 @@ struct hb_lockable_set_t if (item) { item_t old = *item; - *item = items[items.length - 1]; + *item = std::move (items.tail ()); items.pop (); l.unlock (); old.fini (); @@ -123,7 +123,7 @@ struct hb_lockable_set_t l.lock (); while (items.length) { - item_t old = items[items.length - 1]; + item_t old = items.tail (); items.pop (); l.unlock (); old.fini (); @@ -175,14 +175,34 @@ struct hb_user_data_array_t void init () { lock.init (); items.init (); } - HB_INTERNAL bool set (hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, - hb_bool_t replace); + void fini () { items.fini (lock); lock.fini (); } - HB_INTERNAL void *get (hb_user_data_key_t *key); + bool set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) + { + if (!key) + return false; - void fini () { items.fini (lock); lock.fini (); } + if (replace) { + if (!data && !destroy) { + items.remove (key, lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, lock, (bool) replace); + + return ret; + } + + void *get (hb_user_data_key_t *key) + { + hb_user_data_item_t item = {nullptr, nullptr, nullptr}; + + return items.find (key, &item, lock) ? item.data : nullptr; + } }; diff --git a/third_party/harfbuzz-ng/src/src/hb-open-file.hh b/third_party/harfbuzz-ng/src/src/hb-open-file.hh index 6eee5827c18a..13570a46e0ce 100644 --- a/third_party/harfbuzz-ng/src/src/hb-open-file.hh +++ b/third_party/harfbuzz-ng/src/src/hb-open-file.hh @@ -90,7 +90,7 @@ typedef struct OpenTypeOffsetTable { if (table_count) { - + tables.sub_array (start_offset, table_count) + + tables.as_array ().sub_array (start_offset, table_count) | hb_map (&TableRecord::tag) | hb_sink (hb_array (table_tags, *table_count)) ; @@ -158,7 +158,7 @@ typedef struct OpenTypeOffsetTable return_trace (false); if (likely (len)) - memcpy (start, blob->data, len); + hb_memcpy (start, blob->data, len); /* 4-byte alignment. */ c->align (4); diff --git a/third_party/harfbuzz-ng/src/src/hb-open-type.hh b/third_party/harfbuzz-ng/src/src/hb-open-type.hh index e66f45182079..4c9bfebcec15 100644 --- a/third_party/harfbuzz-ng/src/src/hb-open-type.hh +++ b/third_party/harfbuzz-ng/src/src/hb-open-type.hh @@ -147,8 +147,11 @@ struct HBFixed : Type static constexpr float shift = (float) (1 << fraction_bits); static_assert (Type::static_size * 8 > fraction_bits, ""); - HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; } - float to_float () const { return ((int32_t) Type::v) / shift; } + operator signed () const = delete; + operator unsigned () const = delete; + typename Type::type to_int () const { return Type::v; } + void set_int (typename Type::type i ) { Type::v = i; } + float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } void set_float (float f) { Type::v = roundf (f * shift); } public: DEFINE_SIZE_STATIC (Type::static_size); @@ -156,6 +159,8 @@ struct HBFixed : Type /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ using F2DOT14 = HBFixed; +using F4DOT12 = HBFixed; +using F6DOT10 = HBFixed; /* 32-bit signed fixed-point number (16.16). */ using F16DOT16 = HBFixed; @@ -209,6 +214,12 @@ typedef Index NameID; struct VarIdx : HBUINT32 { static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; + static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); + static uint32_t add (uint32_t i, unsigned short v) + { + if (i == NO_VARIATION) return i; + return i + v; + } VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } }; DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); @@ -493,10 +504,10 @@ struct UnsizedArrayOf void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array (len).qsort (start, end); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend (this, items_len))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false); return_trace (true); } template sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + len; } template Type &lsearch (const T &x, Type ¬_found = Crap (Type)) @@ -667,15 +673,15 @@ struct ArrayOf unsigned int to_store = (unsigned int) -1) const { return as_array ().lfind (x, i, not_found, to_store); } - void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) - { as_array ().qsort (start, end); } + void qsort () + { as_array ().qsort (); } - HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); - if (unlikely (!c->extend (this))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template extend_min (this))) return_trace (false); c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); - if (unlikely (!c->extend (this))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template - bool serialize (hb_serialize_context_t *c, Iterator items) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - unsigned count = items.len (); - if (unlikely (!serialize (c, count))) return_trace (false); + unsigned count = hb_len (items); + if (unlikely (!serialize (c, count, false))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ for (unsigned i = 0; i < count; i++, ++items) @@ -944,14 +954,9 @@ struct SortedArrayOf : ArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return this->arrayZ; } + const Type *end () const { return this->arrayZ + this->len; } bool serialize (hb_serialize_context_t *c, unsigned int items_len) { diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-cff-common.hh b/third_party/harfbuzz-ng/src/src/hb-ot-cff-common.hh index ae3b83a25636..f22824fc6991 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-cff-common.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-cff-common.hh @@ -66,95 +66,25 @@ struct CFFIndex { TRACE_SERIALIZE (this); unsigned int size = get_size (); - CFFIndex *out = c->allocate_size (size); + CFFIndex *out = c->allocate_size (size, false); if (likely (out)) - memcpy (out, this, size); + hb_memcpy (out, this, size); return_trace (out); } + template bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const byte_str_array_t &byteArray) + const Iterable &iterable) { TRACE_SERIALIZE (this); - - if (byteArray.length == 0) - { - COUNT *dest = c->allocate_min (); - if (unlikely (!dest)) return_trace (false); - *dest = 0; - return_trace (true); - } - - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = byteArray.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (byteArray.length + 1)))) - return_trace (false); - - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < byteArray.length; i++) - { - set_offset_at (i, offset); - offset += byteArray[i].get_size (); - } - set_offset_at (i, offset); - - /* serialize data */ - for (unsigned int i = 0; i < byteArray.length; i++) - { - const hb_ubytes_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size (bs.length); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &bs[0], bs.length); - } - - return_trace (true); - } - - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const str_buff_vec_t &buffArray) - { - byte_str_array_t byteArray; - byteArray.init (); - byteArray.resize (buffArray.length); - for (unsigned int i = 0; i < byteArray.length; i++) - byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length); - bool result = this->serialize (c, offSize_, byteArray); - byteArray.fini (); - return result; - } - - template - bool serialize (hb_serialize_context_t *c, - Iterator it) - { - TRACE_SERIALIZE (this); - serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; })); + auto it = hb_iter (iterable); + serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len)); for (const auto &_ : +it) - _.copy (c); + hb_iter (_).copy (c); return_trace (true); } - bool serialize (hb_serialize_context_t *c, - const byte_str_array_t &byteArray) - { return serialize (c, + hb_iter (byteArray)); } - - bool serialize (hb_serialize_context_t *c, - const str_buff_vec_t &buffArray) - { - auto it = - + hb_iter (buffArray) - | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); }) - ; - return serialize (c, it); - } - template bool serialize_header (hb_serialize_context_t *c, @@ -171,7 +101,7 @@ struct CFFIndex if (!this->count) return_trace (true); if (unlikely (!c->extend (this->offSize))) return_trace (false); this->offSize = off_size; - if (unlikely (!c->allocate_size (off_size * (this->count + 1)))) + if (unlikely (!c->allocate_size (off_size * (this->count + 1), false))) return_trace (false); /* serialize indices */ @@ -179,14 +109,27 @@ struct CFFIndex unsigned int i = 0; for (unsigned _ : +it) { - CFFIndex::set_offset_at (i++, offset); + set_offset_at (i++, offset); offset += _; } - CFFIndex::set_offset_at (i, offset); + set_offset_at (i, offset); return_trace (true); } + template + static unsigned total_size (const Iterable &iterable) + { + auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len); + if (!it) return 0; + + unsigned total = + it | hb_reduce (hb_add, 0); + unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; + + return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total; + } + void set_offset_at (unsigned int index, unsigned int offset) { assert (index <= count); @@ -207,10 +150,14 @@ struct CFFIndex unsigned int size = offSize; const HBUINT8 *p = offsets + size * index; - unsigned int offset = 0; - for (; size; size--) - offset = (offset << 8) + *p++; - return offset; + switch (size) + { + case 1: return * (HBUINT8 *) p; + case 2: return * (HBUINT16 *) p; + case 3: return * (HBUINT24 *) p; + case 4: return * (HBUINT32 *) p; + default: return 0; + } } unsigned int length_at (unsigned int index) const @@ -229,6 +176,7 @@ struct CFFIndex hb_ubytes_t operator [] (unsigned int index) const { if (unlikely (index >= count)) return hb_ubytes_t (); + _hb_compiler_memory_r_barrier (); unsigned length = length_at (index); if (unlikely (!length)) return hb_ubytes_t (); return hb_ubytes_t (data_base () + offset_at (index) - 1, length); @@ -280,7 +228,7 @@ struct CFFIndexOf : CFFIndex if (unlikely (!c->extend_min (this))) return_trace (false); this->count = dataArrayLen; this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1)))) + if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1), false))) return_trace (false); /* serialize indices */ @@ -288,10 +236,10 @@ struct CFFIndexOf : CFFIndex unsigned int i = 0; for (; i < dataArrayLen; i++) { - CFFIndex::set_offset_at (i, offset); + this->set_offset_at (i, offset); offset += dataSizeArray[i]; } - CFFIndex::set_offset_at (i, offset); + this->set_offset_at (i, offset); /* serialize data */ for (unsigned int i = 0; i < dataArrayLen; i++) @@ -324,13 +272,12 @@ struct Dict : UnsizedByteStr template static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp) { - // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation - if (/*unlikely*/ (!serialize_int (c, intOp, value))) + if (unlikely ((!serialize_int (c, intOp, value)))) return false; TRACE_SERIALIZE (this); /* serialize the opcode */ - HBUINT8 *p = c->allocate_size (OpCode_Size (op)); + HBUINT8 *p = c->allocate_size (OpCode_Size (op), false); if (unlikely (!p)) return_trace (false); if (Is_OpCode_ESC (op)) { @@ -415,9 +362,8 @@ struct FDSelect0 { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this)))) return_trace (false); - for (unsigned int i = 0; i < c->get_num_glyphs (); i++) - if (unlikely (!fds[i].sanitize (c))) - return_trace (false); + if (unlikely (!c->check_array (fds, c->get_num_glyphs ()))) + return_trace (false); return_trace (true); } @@ -471,14 +417,20 @@ struct FDSelect3_4 return_trace (true); } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const + static int _cmp_range (const void *_key, const void *_item) { - unsigned int i; - for (i = 1; i < nRanges (); i++) - if (glyph < ranges[i].first) - break; + hb_codepoint_t glyph = * (hb_codepoint_t *) _key; + FDSelect3_4_Range *range = (FDSelect3_4_Range *) _item; - return (hb_codepoint_t) ranges[i - 1].fd; + if (glyph < range[0].first) return -1; + if (glyph < range[1].first) return 0; + return +1; + } + + hb_codepoint_t get_fd (hb_codepoint_t glyph) const + { + auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range); + return range ? range->fd : ranges[nRanges () - 1].fd; } GID_TYPE &nRanges () { return ranges.len; } @@ -501,9 +453,9 @@ struct FDSelect { TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); - FDSelect *dest = c->allocate_size (size); + FDSelect *dest = c->allocate_size (size, false); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.cc b/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.cc index bd9fe5d6d408..5040c746234c 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.cc +++ b/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.cc @@ -422,8 +422,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); - extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing; + extents->x_bearing = roundf (bounds.min.x.to_real ()); + extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing); } if (bounds.min.y >= bounds.max.y) { @@ -432,10 +432,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); - extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing; + extents->y_bearing = roundf (bounds.max.y.to_real ()); + extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing); } + font->scale_glyph_extents (extents); + return true; } @@ -551,6 +553,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } +bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const +{ + funcs->push_clip_glyph (data, glyph, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; +} + bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.hh b/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.hh index 17b02966168b..f461a230449a 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-cff1-table.hh @@ -30,6 +30,7 @@ #include "hb-ot-cff-common.hh" #include "hb-subset-cff1.hh" #include "hb-draw.hh" +#include "hb-paint.hh" #define HB_STRING_ARRAY_NAME cff1_std_strings #define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh" @@ -175,7 +176,7 @@ struct Encoding unsigned int size = src.get_size (); Encoding *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -471,7 +472,7 @@ struct Charset unsigned int size = src.get_size (num_glyphs); Charset *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -617,7 +618,6 @@ struct CFF1StringIndex : CFF1Index } byte_str_array_t bytesArray; - bytesArray.init (); if (!bytesArray.resize (sidmap.get_population ())) return_trace (false); for (unsigned int i = 0; i < strings.count; i++) @@ -628,7 +628,6 @@ struct CFF1StringIndex : CFF1Index } bool result = CFF1Index::serialize (c, bytesArray); - bytesArray.fini (); return_trace (result); } }; @@ -813,7 +812,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t break; default: - env.last_offset = env.str_ref.offset; + env.last_offset = env.str_ref.get_offset (); top_dict_opset_t::process_op (op, env, dictval); /* Record this operand below if stack is empty, otherwise done */ if (!env.argStack.is_empty ()) return; @@ -903,8 +902,6 @@ struct cff1_private_dict_opset_t : dict_opset_t case OpCode_FamilyOtherBlues: case OpCode_StemSnapH: case OpCode_StemSnapV: - env.clear_args (); - break; case OpCode_StdHW: case OpCode_StdVW: case OpCode_BlueScale: @@ -916,7 +913,6 @@ struct cff1_private_dict_opset_t : dict_opset_t case OpCode_initialRandomSeed: case OpCode_defaultWidthX: case OpCode_nominalWidthX: - val.single_val = env.argStack.pop_num (); env.clear_args (); break; case OpCode_Subrs: @@ -1295,10 +1291,10 @@ struct cff1 } protected: - hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: + hb_blob_t *blob = nullptr; const Encoding *encoding = nullptr; const Charset *charset = nullptr; const CFF1NameIndex *nameIndex = nullptr; @@ -1345,6 +1341,7 @@ struct cff1 bool get_glyph_name (hb_codepoint_t glyph, char *buf, unsigned int buf_len) const { + if (unlikely (glyph >= num_glyphs)) return false; if (unlikely (!is_valid ())) return false; if (is_CID()) return false; if (unlikely (!buf_len)) return true; @@ -1428,6 +1425,7 @@ struct cff1 } HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.cc b/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.cc index 50c76daf93e7..79555655519e 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.cc +++ b/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.cc @@ -124,8 +124,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); - extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing; + extents->x_bearing = roundf (param.min_x.to_real ()); + extents->width = roundf (param.max_x.to_real () - extents->x_bearing); } if (param.min_y >= param.max_y) { @@ -134,10 +134,21 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); - extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing; + extents->y_bearing = roundf (param.max_y.to_real ()); + extents->height = roundf (param.min_y.to_real () - extents->y_bearing); } + font->scale_glyph_extents (extents); + + return true; +} + +bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const +{ + funcs->push_clip_glyph (data, glyph, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + return true; } diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.hh b/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.hh index 746160dc8e43..b9a8819ab85a 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-cff2-table.hh @@ -30,6 +30,7 @@ #include "hb-ot-cff-common.hh" #include "hb-subset-cff2.hh" #include "hb-draw.hh" +#include "hb-paint.hh" namespace CFF { @@ -56,7 +57,7 @@ struct CFF2FDSelect unsigned int size = src.get_size (num_glyphs); CFF2FDSelect *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -124,7 +125,7 @@ struct CFF2VariationStore unsigned int size_ = varStore->get_size (); CFF2VariationStore *dest = c->allocate_size (size_); if (unlikely (!dest)) return_trace (false); - memcpy (dest, varStore, size_); + hb_memcpy (dest, varStore, size_); return_trace (true); } @@ -282,9 +283,6 @@ struct cff2_private_dict_opset_t : dict_opset_t case OpCode_BlueFuzz: case OpCode_ExpansionFactor: case OpCode_LanguageGroup: - val.single_val = env.argStack.pop_num (); - env.clear_args (); - break; case OpCode_BlueValues: case OpCode_OtherBlues: case OpCode_FamilyBlues: @@ -483,13 +481,18 @@ struct cff2 blob = nullptr; } + hb_map_t *create_glyph_to_sid_map () const + { + return nullptr; + } + bool is_valid () const { return blob; } protected: - hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: + hb_blob_t *blob = nullptr; cff2_top_dict_values_t topDict; const CFF2Subrs *globalSubrs = nullptr; const CFF2VariationStore *varStore = nullptr; @@ -511,6 +514,7 @@ struct cff2 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; }; diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-cmap-table.hh b/third_party/harfbuzz-ng/src/src/hb-ot-cmap-table.hh index 09c9fe93f32e..f5a03d2b00eb 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-cmap-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-cmap-table.hh @@ -31,6 +31,7 @@ #include "hb-ot-shaper-arabic-pua.hh" #include "hb-open-type.hh" #include "hb-set.hh" +#include "hb-cache.hh" /* * cmap -- Character to Glyph Index Mapping @@ -909,7 +910,7 @@ struct DefaultUVS : SortedArray32Of hb_codepoint_t first = arrayZ[i].startUnicodeValue; hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), (hb_codepoint_t) HB_UNICODE_MAX); - out->add_range (first, hb_min (last, 0x10FFFFu)); + out->add_range (first, last); } } @@ -925,37 +926,75 @@ struct DefaultUVS : SortedArray32Of if (unlikely (!c->copy (len))) return nullptr; unsigned init_len = c->length (); - hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID; - int count = -1; - - for (const UnicodeValueRange& _ : as_array ()) + if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len)) { - for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1)) + hb_codepoint_t start = HB_SET_VALUE_INVALID; + hb_codepoint_t end = HB_SET_VALUE_INVALID; + + for (hb_codepoint_t u = HB_SET_VALUE_INVALID; + unicodes->next (&u);) { - unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt; - if (!unicodes->has (curEntry)) continue; - count += 1; - if (lastCode == HB_MAP_VALUE_INVALID) - lastCode = curEntry; - else if (lastCode + count != curEntry) + if (!as_array ().bsearch (u)) + continue; + if (start == HB_SET_VALUE_INVALID) { + start = u; + end = start - 1; + } + if (end + 1 != u || end - start == 255) + { UnicodeValueRange rec; - rec.startUnicodeValue = lastCode; - rec.additionalCount = count - 1; + rec.startUnicodeValue = start; + rec.additionalCount = end - start; c->copy (rec); - - lastCode = curEntry; - count = 0; + start = u; } + end = u; + } + if (start != HB_SET_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = start; + rec.additionalCount = end - start; + c->copy (rec); } - } - if (lastCode != HB_MAP_VALUE_INVALID) + } + else { - UnicodeValueRange rec; - rec.startUnicodeValue = lastCode; - rec.additionalCount = count; - c->copy (rec); + hb_codepoint_t lastCode = HB_SET_VALUE_INVALID; + int count = -1; + + for (const UnicodeValueRange& _ : *this) + { + hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1); + hb_codepoint_t end = curEntry + _.additionalCount + 2; + + for (; unicodes->next (&curEntry) && curEntry < end;) + { + count += 1; + if (lastCode == HB_SET_VALUE_INVALID) + lastCode = curEntry; + else if (lastCode + count != curEntry) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count - 1; + c->copy (rec); + + lastCode = curEntry; + count = 0; + } + } + } + + if (lastCode != HB_MAP_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count; + c->copy (rec); + } } if (c->length () - init_len == 0) @@ -1376,7 +1415,7 @@ struct CmapSubtable switch (format) { case 4: return u.format4.serialize (c, it); case 12: return u.format12.serialize (c, it); - case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base); + case 14: return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base); default: return; } } @@ -1474,32 +1513,80 @@ struct EncodingRecord DEFINE_SIZE_STATIC (8); }; +struct cmap; + struct SubtableUnicodesCache { private: - const void* base; - hb_hashmap_t> cached_unicodes; + hb_blob_ptr_t base_blob; + const char* base; + hb_hashmap_t> cached_unicodes; public: + + static SubtableUnicodesCache* create (hb_blob_ptr_t source_table) + { + SubtableUnicodesCache* cache = + (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache)); + new (cache) SubtableUnicodesCache (source_table); + return cache; + } + + static void destroy (void* value) { + if (!value) return; + + SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value; + cache->~SubtableUnicodesCache (); + hb_free (cache); + } + SubtableUnicodesCache(const void* cmap_base) - : base(cmap_base), cached_unicodes() {} + : base_blob(), + base ((const char*) cmap_base), + cached_unicodes () + {} + + SubtableUnicodesCache(hb_blob_ptr_t base_blob_) + : base_blob(base_blob_), + base ((const char *) base_blob.get()), + cached_unicodes () + {} + + ~SubtableUnicodesCache() + { + base_blob.destroy (); + } + + bool same_base(const void* other) const + { + return other == (const void*) base; + } - hb_set_t* set_for (const EncodingRecord* record) + const hb_set_t* set_for (const EncodingRecord* record, + SubtableUnicodesCache& mutable_cache) const { - if (!cached_unicodes.has ((intptr_t) record)) + if (cached_unicodes.has ((unsigned) ((const char *) record - base))) + return cached_unicodes.get ((unsigned) ((const char *) record - base)); + + return mutable_cache.set_for (record); + } + + const hb_set_t* set_for (const EncodingRecord* record) + { + if (!cached_unicodes.has ((unsigned) ((const char *) record - base))) { hb_set_t *s = hb_set_create (); if (unlikely (s->in_error ())) return hb_set_get_empty (); - + (base+record->subtable).collect_unicodes (s); - if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr {s}))) + if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr {s}))) return hb_set_get_empty (); return s; } - return cached_unicodes.get ((intptr_t) record); + return cached_unicodes.get ((unsigned) ((const char *) record - base)); } }; @@ -1523,13 +1610,30 @@ struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; + + static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t source_table) { + const cmap* cmap = source_table.get(); + auto it = + + hb_iter (cmap->encodingRecord) + | hb_filter ([&](const EncodingRecord& _) { + return cmap::filter_encoding_records_for_subset (cmap, _); + }) + ; + + SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table); + for (const EncodingRecord& _ : it) + cache->set_for(&_); // populate the cache for this encoding record. + + return cache; + } + template bool serialize (hb_serialize_context_t *c, Iterator it, EncodingRecIter encodingrec_iter, const void *base, - const hb_subset_plan_t *plan, + hb_subset_plan_t *plan, bool drop_format_4 = false) { if (unlikely (!c->extend_min ((*this)))) return false; @@ -1538,7 +1642,14 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); - SubtableUnicodesCache unicodes_cache (base); + SubtableUnicodesCache local_unicodes_cache (base); + const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache; + + if (plan->accelerator && + plan->accelerator->cmap_cache && + plan->accelerator->cmap_cache->same_base (base)) + unicodes_cache = plan->accelerator->cmap_cache; + for (const EncodingRecord& _ : encodingrec_iter) { if (c->in_error ()) @@ -1547,7 +1658,7 @@ struct cmap unsigned format = (base+_.subtable).u.format; if (format != 4 && format != 12 && format != 14) continue; - hb_set_t* unicodes_set = unicodes_cache.set_for (&_); + const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache); if (!drop_format_4 && format == 4) { @@ -1566,7 +1677,13 @@ struct cmap else if (format == 12) { - if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue; + if (_can_drop (_, + *unicodes_set, + base, + *unicodes_cache, + local_unicodes_cache, + + it | hb_map (hb_first), encodingrec_iter)) + continue; c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); @@ -1585,7 +1702,8 @@ struct cmap bool _can_drop (const EncodingRecord& cmap12, const hb_set_t& cmap12_unicodes, const void* base, - SubtableUnicodesCache& unicodes_cache, + const SubtableUnicodesCache& unicodes_cache, + SubtableUnicodesCache& local_unicodes_cache, Iterator subset_unicodes, EncodingRecordIterator encoding_records) { @@ -1616,7 +1734,7 @@ struct cmap || (base+_.subtable).get_language() != target_language) continue; - hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_); + const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache); auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes); auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes); @@ -1653,17 +1771,9 @@ struct cmap auto encodingrec_iter = + hb_iter (encodingRecord) - | hb_filter ([&] (const EncodingRecord& _) - { - if ((_.platformID == 0 && _.encodingID == 3) || - (_.platformID == 0 && _.encodingID == 4) || - (_.platformID == 3 && _.encodingID == 1) || - (_.platformID == 3 && _.encodingID == 10) || - (this + _.subtable).u.format == 14) - return true; - - return false; - }) + | hb_filter ([&](const EncodingRecord& _) { + return cmap::filter_encoding_records_for_subset (this, _); + }) ; if (unlikely (!encodingrec_iter.len ())) return_trace (false); @@ -1692,7 +1802,11 @@ struct cmap { return (_.second != HB_MAP_VALUE_INVALID); }) ; - return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan)); + return_trace (cmap_prime->serialize (c->serializer, + it, + encodingrec_iter, + this, + c->plan)); } const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const @@ -1728,6 +1842,8 @@ struct cmap struct accelerator_t { + using cache_t = hb_cache_t<21, 16, 8, true>; + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table (face); @@ -1782,26 +1898,43 @@ struct cmap } ~accelerator_t () { this->table.destroy (); } + inline bool _cached_get (hb_codepoint_t unicode, + hb_codepoint_t *glyph, + cache_t *cache) const + { + unsigned v; + if (cache && cache->get (unicode, &v)) + { + *glyph = v; + return true; + } + bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); + + if (cache && ret) + cache->set (unicode, *glyph); + return ret; + } + bool get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + cache_t *cache = nullptr) const { - if (unlikely (!this->get_glyph_funcZ)) return false; - return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); + if (unlikely (!this->get_glyph_funcZ)) return 0; + return _cached_get (unicode, glyph, cache); } + 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) const + unsigned int glyph_stride, + cache_t *cache = nullptr) const { if (unlikely (!this->get_glyph_funcZ)) return 0; - hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; - const void *get_glyph_data = this->get_glyph_data; - unsigned int done; for (done = 0; - done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); + done < count && _cached_get (*first_unicode, first_glyph, cache); done++) { first_unicode = &StructAtOffsetUnaligned (first_unicode, unicode_stride); @@ -1812,7 +1945,8 @@ struct cmap bool get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + cache_t *cache = nullptr) const { switch (this->subtable_uvs->get_glyph_variant (unicode, variation_selector, @@ -1823,7 +1957,7 @@ struct cmap case GLYPH_VARIANT_USE_DEFAULT: break; } - return get_nominal_glyph (unicode, glyph); + return get_nominal_glyph (unicode, glyph, cache); } void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const @@ -1928,6 +2062,19 @@ struct cmap encodingRecord.sanitize (c, this)); } + private: + + static bool filter_encoding_records_for_subset(const cmap* cmap, + const EncodingRecord& _) + { + return + (_.platformID == 0 && _.encodingID == 3) || + (_.platformID == 0 && _.encodingID == 4) || + (_.platformID == 3 && _.encodingID == 1) || + (_.platformID == 3 && _.encodingID == 10) || + (cmap + _.subtable).u.format == 14; + } + protected: HBUINT16 version; /* Table version number (0). */ SortedArray16Of diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color.cc b/third_party/harfbuzz-ng/src/src/hb-ot-color.cc index 696ca3e17f7e..37d42e08d94e 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color.cc +++ b/third_party/harfbuzz-ng/src/src/hb-ot-color.cc @@ -31,11 +31,11 @@ #include "hb-ot.h" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-colr-table.hh" -#include "hb-ot-color-cpal-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/CPAL/CPAL.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" /** @@ -167,6 +167,10 @@ hb_ot_color_palette_get_flags (hb_face_t *face, * for allocating a buffer of suitable size before calling * hb_ot_color_palette_get_colors() a second time. * + * The RGBA values in the palette are unpremultiplied. See the + * OpenType spec [CPAL](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal) + * section for details. + * * Return value: the total number of colors in the palette * * Since: 2.1.0 @@ -190,7 +194,8 @@ hb_ot_color_palette_get_colors (hb_face_t *face, * hb_ot_color_has_layers: * @face: #hb_face_t to work upon * - * Tests whether a face includes any `COLR` color layers. + * Tests whether a face includes a `COLR` table + * with data according to COLRv0. * * Return value: `true` if data found, `false` otherwise * @@ -199,7 +204,43 @@ hb_ot_color_palette_get_colors (hb_face_t *face, hb_bool_t hb_ot_color_has_layers (hb_face_t *face) { - return face->table.COLR->has_data (); + return face->table.COLR->has_v0_data (); +} + +/** + * hb_ot_color_has_paint: + * @face: #hb_face_t to work upon + * + * Tests where a face includes a `COLR` table + * with data according to COLRv1. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 7.0.0 + */ +hb_bool_t +hb_ot_color_has_paint (hb_face_t *face) +{ + return face->table.COLR->has_v1_data (); +} + +/** + * hb_ot_color_glyph_has_paint: + * @face: #hb_face_t to work upon + * @glyph: The glyph index to query + * + * Tests where a face includes COLRv1 paint + * data for @glyph. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 7.0.0 + */ +hb_bool_t +hb_ot_color_glyph_has_paint (hb_face_t *face, + hb_codepoint_t glyph) +{ + return face->table.COLR->has_paint_for_glyph (glyph); } /** diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-color.h b/third_party/harfbuzz-ng/src/src/hb-ot-color.h index d11e07e2309a..22ee497e388b 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-color.h +++ b/third_party/harfbuzz-ng/src/src/hb-ot-color.h @@ -120,6 +120,15 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, unsigned int *layer_count, /* IN/OUT. May be NULL. */ hb_ot_color_layer_t *layers /* OUT. May be NULL. */); +/* COLRv1 */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_paint (hb_face_t *face); + +HB_EXTERN hb_bool_t +hb_ot_color_glyph_has_paint (hb_face_t *face, + hb_codepoint_t glyph); + /* * SVG */ diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-deprecated.h b/third_party/harfbuzz-ng/src/src/hb-ot-deprecated.h index 5192ff73e393..60672ab1283a 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-deprecated.h +++ b/third_party/harfbuzz-ng/src/src/hb-ot-deprecated.h @@ -67,26 +67,30 @@ HB_BEGIN_DECLS /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) +HB_EXTERN hb_bool_t hb_ot_layout_table_choose_script (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *script_tags, unsigned int *script_index, hb_tag_t *chosen_script); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) +HB_EXTERN hb_bool_t hb_ot_layout_script_find_language (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, hb_tag_t language_tag, unsigned int *language_index); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void +HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) +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_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t +HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) +HB_EXTERN hb_tag_t hb_ot_tag_from_language (hb_language_t language); @@ -121,13 +125,15 @@ typedef struct hb_ot_var_axis_t { float max_value; } hb_ot_var_axis_t; -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) unsigned int +HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) +HB_EXTERN unsigned int hb_ot_var_get_axes (hb_face_t *face, unsigned int start_offset, unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_t *axes_array /* OUT */); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) +HB_EXTERN hb_bool_t hb_ot_var_find_axis (hb_face_t *face, hb_tag_t axis_tag, unsigned int *axis_index, diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-face-table-list.hh b/third_party/harfbuzz-ng/src/src/hb-ot-face-table-list.hh index c05034b3bb5a..b552dfdd9dae 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-face-table-list.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-face-table-list.hh @@ -56,9 +56,9 @@ HB_OT_CORE_TABLE (OT, maxp) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif -HB_OT_TABLE (OT, hhea) +HB_OT_CORE_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) -HB_OT_TABLE (OT, OS2) +HB_OT_CORE_TABLE (OT, OS2) #if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE) HB_OT_ACCELERATOR (OT, post) #endif @@ -66,7 +66,7 @@ HB_OT_ACCELERATOR (OT, post) HB_OT_ACCELERATOR (OT, name) #endif #ifndef HB_NO_STYLE -HB_OT_TABLE (OT, STAT) +HB_OT_CORE_TABLE (OT, STAT) #endif #ifndef HB_NO_META HB_OT_ACCELERATOR (OT, meta) @@ -74,9 +74,9 @@ HB_OT_ACCELERATOR (OT, meta) /* Vertical layout. */ #ifndef HB_NO_VERTICAL -HB_OT_TABLE (OT, vhea) +HB_OT_CORE_TABLE (OT, vhea) HB_OT_ACCELERATOR (OT, vmtx) -HB_OT_TABLE (OT, VORG) +HB_OT_CORE_TABLE (OT, VORG) #endif /* TrueType outlines. */ @@ -91,15 +91,16 @@ HB_OT_ACCELERATOR (OT, cff2) /* OpenType variations. */ #ifndef HB_NO_VAR -HB_OT_TABLE (OT, fvar) -HB_OT_TABLE (OT, avar) +HB_OT_CORE_TABLE (OT, fvar) +HB_OT_CORE_TABLE (OT, avar) +HB_OT_CORE_TABLE (OT, cvar) HB_OT_ACCELERATOR (OT, gvar) -HB_OT_TABLE (OT, MVAR) +HB_OT_CORE_TABLE (OT, MVAR) #endif /* Legacy kern. */ #ifndef HB_NO_OT_KERN -HB_OT_TABLE (OT, kern) +HB_OT_CORE_TABLE (OT, kern) #endif /* OpenType shaping. */ @@ -107,12 +108,12 @@ HB_OT_TABLE (OT, kern) HB_OT_ACCELERATOR (OT, GDEF) HB_OT_ACCELERATOR (OT, GSUB) HB_OT_ACCELERATOR (OT, GPOS) -//HB_OT_TABLE (OT, JSTF) +//HB_OT_CORE_TABLE (OT, JSTF) #endif /* OpenType baseline. */ #ifndef HB_NO_BASE -HB_OT_TABLE (OT, BASE) +HB_OT_CORE_TABLE (OT, BASE) #endif /* AAT shaping. */ @@ -129,8 +130,8 @@ HB_OT_TABLE (AAT, feat) /* OpenType color fonts. */ #ifndef HB_NO_COLOR -HB_OT_TABLE (OT, COLR) -HB_OT_TABLE (OT, CPAL) +HB_OT_CORE_TABLE (OT, COLR) +HB_OT_CORE_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) HB_OT_ACCELERATOR (OT, SVG) @@ -138,7 +139,7 @@ HB_OT_ACCELERATOR (OT, SVG) /* OpenType math. */ #ifndef HB_NO_MATH -HB_OT_TABLE (OT, MATH) +HB_OT_CORE_TABLE (OT, MATH) #endif diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-face.cc b/third_party/harfbuzz-ng/src/src/hb-ot-face.cc index 5ef8df43ce7c..2243ee028741 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-face.cc +++ b/third_party/harfbuzz-ng/src/src/hb-ot-face.cc @@ -35,9 +35,9 @@ #include "hb-ot-meta-table.hh" #include "hb-ot-name-table.hh" #include "hb-ot-post-table.hh" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-font.cc b/third_party/harfbuzz-ng/src/src/hb-ot-font.cc index 825b30853c85..06f7092a59d1 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-font.cc +++ b/third_party/harfbuzz-ng/src/src/hb-ot-font.cc @@ -34,6 +34,7 @@ #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-ot-face.hh" +#include "hb-outline.hh" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" @@ -43,8 +44,10 @@ #include "hb-ot-post-table.hh" #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-vorg-table.hh" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-sbix-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" /** @@ -58,12 +61,17 @@ * never need to call these functions directly. **/ +using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>; using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; +static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key; + struct hb_ot_font_t { const hb_ot_face_t *ot_face; + hb_ot_font_cmap_cache_t *cmap_cache; + /* h_advance caching */ mutable hb_atomic_int_t cached_coords_serial; mutable hb_atomic_ptr_t advance_cache; @@ -78,6 +86,33 @@ _hb_ot_font_create (hb_font_t *font) ot_font->ot_face = &font->face->table; + // retry: + auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face, + &hb_ot_font_cmap_cache_user_data_key); + if (!cmap_cache) + { + cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t)); + if (unlikely (!cmap_cache)) goto out; + cmap_cache->init (); + if (unlikely (!hb_face_set_user_data (font->face, + &hb_ot_font_cmap_cache_user_data_key, + cmap_cache, + hb_free, + false))) + { + hb_free (cmap_cache); + cmap_cache = nullptr; + /* Normally we would retry here, but that would + * infinite-loop if the face is the empty-face. + * Just let it go and this font will be uncached if it + * happened to collide with another thread creating the + * cache at the same time. */ + // goto retry; + } + } + out: + ot_font->cmap_cache = cmap_cache; + return ot_font; } @@ -87,11 +122,7 @@ _hb_ot_font_destroy (void *font_data) hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; auto *cache = ot_font->advance_cache.get_relaxed (); - if (cache) - { - cache->fini (); - hb_free (cache); - } + hb_free (cache); hb_free (ot_font); } @@ -105,7 +136,7 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_nominal_glyph (unicode, glyph); + return ot_face->cmap->get_nominal_glyph (unicode, glyph, ot_font->cmap_cache); } static unsigned int @@ -122,7 +153,8 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, const hb_ot_face_t *ot_face = ot_font->ot_face; return ot_face->cmap->get_nominal_glyphs (count, first_unicode, unicode_stride, - first_glyph, glyph_stride); + first_glyph, glyph_stride, + ot_font->cmap_cache); } static hb_bool_t @@ -135,7 +167,9 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph); + return ot_face->cmap->get_variation_glyph (unicode, + variation_selector, glyph, + ot_font->cmap_cache); } static void @@ -147,10 +181,13 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; + hb_position_t *orig_first_advance = first_advance; + #ifndef HB_NO_VAR const OT::HVAR &HVAR = *hmtx.var_table; const OT::VariationStore &varStore = &HVAR + HVAR.varStore; @@ -224,6 +261,18 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, #ifndef HB_NO_VAR OT::VariationStore::destroy_cache (varStore_cache); #endif + + if (font->x_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? x_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #ifndef HB_NO_VERTICAL @@ -240,6 +289,8 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + hb_position_t *orig_first_advance = first_advance; + if (vmtx.has_data ()) { #ifndef HB_NO_VAR @@ -274,6 +325,18 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } + + if (font->y_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? y_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #endif @@ -349,6 +412,9 @@ hb_ot_get_glyph_extents (hb_font_t *font, #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) if (ot_face->sbix->get_extents (font, glyph, extents)) return true; if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; +#endif +#if !defined(HB_NO_COLOR) && !defined(HB_NO_PAINT) + if (ot_face->COLR->get_extents (font, glyph, extents)) return true; #endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF @@ -356,7 +422,6 @@ hb_ot_get_glyph_extents (hb_font_t *font, if (ot_face->cff2->get_extents (font, glyph, extents)) return true; #endif - // TODO Hook up side-bearings variations. return false; } @@ -401,9 +466,16 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); + bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); + + /* Embolden */ + int y_shift = font->y_strength; + if (font->y_scale < 0) y_shift = -y_shift; + metrics->ascender += y_shift; + + return ret; } #ifndef HB_NO_VERTICAL @@ -421,17 +493,62 @@ hb_ot_get_font_v_extents (hb_font_t *font, #ifndef HB_NO_DRAW static void -hb_ot_get_glyph_shape (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data) +hb_ot_draw_glyph (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data) { - hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); - if (font->face->table.glyf->get_path (font, glyph, draw_session)) return; + bool embolden = font->x_strength || font->y_strength; + hb_outline_t outline; + + { // Need draw_session to be destructed before emboldening. + hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs, + embolden ? &outline : draw_data, font->slant_xy); + if (!font->face->table.glyf->get_path (font, glyph, draw_session)) #ifndef HB_NO_CFF - if (font->face->table.cff1->get_path (font, glyph, draw_session)) return; - if (font->face->table.cff2->get_path (font, glyph, draw_session)) return; + if (!font->face->table.cff1->get_path (font, glyph, draw_session)) + if (!font->face->table.cff2->get_path (font, glyph, draw_session)) +#endif + {} + } + + if (embolden) + { + float x_shift = font->embolden_in_place ? 0 : (float) font->x_strength / 2; + float y_shift = (float) font->y_strength / 2; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->y_scale < 0) y_shift = -y_shift; + outline.embolden (font->x_strength, font->y_strength, + x_shift, y_shift); + + outline.replay (draw_funcs, draw_data); + } +} +#endif + +#ifndef HB_NO_PAINT +static void +hb_ot_paint_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ +#ifndef HB_NO_COLOR + if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return; + if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return; +#ifndef HB_NO_OT_FONT_BITMAP + if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return; + if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return; +#endif +#endif + if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; +#ifndef HB_NO_CFF + if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; + if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; #endif } #endif @@ -459,7 +576,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tface->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); -} - -unsigned -_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) -{ - return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical); -} -#endif - - #endif diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-hdmx-table.hh b/third_party/harfbuzz-ng/src/src/hb-ot-hdmx-table.hh index dea2b7e29a97..3bfd75502a48 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-hdmx-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-hdmx-table.hh @@ -76,7 +76,7 @@ struct DeviceRecord HBUINT8 maxWidth; /* Maximum width. */ UnsizedArrayOf widthsZ; /* Array of widths (numGlyphs is from the 'maxp' table). */ public: - DEFINE_SIZE_ARRAY (2, widthsZ); + DEFINE_SIZE_UNBOUNDED (2); }; @@ -87,14 +87,6 @@ struct hdmx unsigned int get_size () const { return min_size + numRecords * sizeDeviceRecord; } - const DeviceRecord& operator [] (unsigned int i) const - { - /* XXX Null(DeviceRecord) is NOT safe as it's num-glyphs lengthed. - * https://github.com/harfbuzz/harfbuzz/issues/1300 */ - if (unlikely (i >= numRecords)) return Null (DeviceRecord); - return StructAtOffset (&this->firstDeviceRecord, i * sizeDeviceRecord); - } - template bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) @@ -156,6 +148,7 @@ struct hdmx TRACE_SANITIZE (this); return_trace (c->check_struct (this) && !hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) && + min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord && sizeDeviceRecord >= DeviceRecord::min_size && c->check_range (this, get_size ())); } diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-head-table.hh b/third_party/harfbuzz-ng/src/src/hb-ot-head-table.hh index 20991aab2b3e..770cf52d1735 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-head-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-head-table.hh @@ -63,7 +63,25 @@ struct head bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - return_trace (serialize (c->serializer)); + head *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + if (c->plan->normalized_coords) + { + if (unlikely (!c->serializer->check_assign (out->xMin, c->plan->head_maxp_info.xMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->xMax, c->plan->head_maxp_info.xMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMin, c->plan->head_maxp_info.yMin, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + if (unlikely (!c->serializer->check_assign (out->yMax, c->plan->head_maxp_info.yMax, + HB_SERIALIZE_ERROR_INT_OVERFLOW))) + return_trace (false); + } + return_trace (true); } enum mac_style_flag_t { @@ -97,6 +115,7 @@ struct head * entire font as HBUINT32, then store * 0xB1B0AFBAu - sum. */ HBUINT32 magicNumber; /* Set to 0x5F0F3CF5u. */ + public: HBUINT16 flags; /* Bit 0: Baseline for font at y=0; * Bit 1: Left sidebearing point at x=0; * Bit 2: Instructions may depend on point size; @@ -141,6 +160,7 @@ struct head * encoded in the cmap subtables represent proper * support for those code points. * Bit 15: Reserved, set to 0. */ + protected: HBUINT16 unitsPerEm; /* Valid range is from 16 to 16384. This value * should be a power of 2 for fonts that have * TrueType outlines. */ @@ -148,10 +168,12 @@ struct head January 1, 1904. 64-bit integer */ LONGDATETIME modified; /* Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer */ + public: HBINT16 xMin; /* For all glyph bounding boxes. */ HBINT16 yMin; /* For all glyph bounding boxes. */ HBINT16 xMax; /* For all glyph bounding boxes. */ HBINT16 yMax; /* For all glyph bounding boxes. */ + protected: HBUINT16 macStyle; /* Bit 0: Bold (if set to 1); * Bit 1: Italic (if set to 1) * Bit 2: Underline (if set to 1) diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-hmtx-table.hh b/third_party/harfbuzz-ng/src/src/hb-ot-hmtx-table.hh index 96a394ba4278..835a1a585e86 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-hmtx-table.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-hmtx-table.hh @@ -31,6 +31,7 @@ #include "hb-ot-maxp-table.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-var-hvar-table.hh" +#include "hb-ot-var-mvar-table.hh" #include "hb-ot-metrics.hh" /* @@ -49,6 +50,9 @@ _glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gly HB_INTERNAL unsigned _glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +HB_INTERNAL bool +_glyf_get_leading_bearing_without_var_unscaled (hb_face_t *face, hb_codepoint_t gid, bool is_vertical, int *lsb); + namespace OT { @@ -73,13 +77,15 @@ struct hmtxvmtx return_trace (true); } - const hb_hashmap_t>* get_mtx_map (const hb_subset_plan_t *plan) const - { return T::is_horizontal ? plan->hmtx_map : plan->vmtx_map; } + const hb_hashmap_t>* get_mtx_map (const hb_subset_plan_t *plan) const + { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; } - bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + bool subset_update_header (hb_subset_context_t *c, + unsigned int num_hmetrics, + const hb_hashmap_t> *mtx_map, + const hb_map_t *bounds_map) const { - hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (plan->source, H::tableTag); + hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (c->plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); hb_blob_destroy (src_blob); @@ -89,9 +95,58 @@ struct hmtxvmtx unsigned int length; H *table = (H *) hb_blob_get_data (dest_blob, &length); - table->numberOfLongMetrics = num_hmetrics; + c->serializer->check_assign (table->numberOfLongMetrics, num_hmetrics, HB_SERIALIZE_ERROR_INT_OVERFLOW); + +#ifndef HB_NO_VAR + if (c->plan->normalized_coords) + { + auto &MVAR = *c->plan->source->table.MVAR; + if (T::is_horizontal) + { + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, caretSlopeRise); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, caretSlopeRun); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset); + } + else + { + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE, caretSlopeRise); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN, caretSlopeRun); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset); + } - bool result = plan->add_table (H::tableTag, dest_blob); + int min_lsb = 0x7FFF; + int min_rsb = 0x7FFF; + int max_extent = -0x7FFF; + unsigned max_adv = 0; + for (const auto _ : *mtx_map) + { + hb_codepoint_t gid = _.first; + unsigned adv = _.second.first; + int lsb = _.second.second; + max_adv = hb_max (max_adv, adv); + + if (bounds_map->has (gid)) + { + unsigned bound_width = bounds_map->get (gid); + int rsb = adv - lsb - bound_width; + int extent = lsb + bound_width; + min_lsb = hb_min (min_lsb, lsb); + min_rsb = hb_min (min_rsb, rsb); + max_extent = hb_max (max_extent, extent); + } + } + + table->advanceMax = max_adv; + if (!bounds_map->is_empty ()) + { + table->minLeadingBearing = min_lsb; + table->minTrailingBearing = min_rsb; + table->maxExtent = max_extent; + } + } +#endif + + bool result = c->plan->add_table (H::tableTag, dest_blob); hb_blob_destroy (dest_blob); return result; @@ -113,12 +168,19 @@ struct hmtxvmtx lm.sb = _.second; if (unlikely (!c->embed (&lm))) return; } - else + else if (idx < 0x10000u) { FWORD *sb = c->allocate_size (FWORD::static_size); if (unlikely (!sb)) return; *sb = _.second; } + else + { + // TODO: This does not do tail optimization. + UFWORD *adv = c->allocate_size (UFWORD::static_size); + if (unlikely (!adv)) return; + *adv = _.first; + } idx++; } } @@ -132,12 +194,12 @@ struct hmtxvmtx accelerator_t _mtx (c->plan->source); unsigned num_long_metrics; - const hb_hashmap_t> *mtx_map = get_mtx_map (c->plan); + const hb_hashmap_t> *mtx_map = get_mtx_map (c->plan); { /* Determine num_long_metrics to encode. */ auto& plan = c->plan; - num_long_metrics = plan->num_output_glyphs (); + num_long_metrics = hb_min (plan->num_output_glyphs (), 0xFFFFu); unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) @@ -156,7 +218,8 @@ struct hmtxvmtx if (!c->plan->old_gid_for_new_gid (_, &old_gid)) return hb_pair (0u, 0); int lsb = 0; - (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); + if (!_mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb)) + (void) _glyf_get_leading_bearing_without_var_unscaled (c->plan->source, old_gid, !T::is_horizontal, &lsb); return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); } return mtx_map->get (_); @@ -169,7 +232,8 @@ struct hmtxvmtx return_trace (false); // Amend header num hmetrics - if (unlikely (!subset_update_header (c->plan, num_long_metrics))) + if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map, + T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map))) return_trace (false); return_trace (true); @@ -291,8 +355,6 @@ struct hmtxvmtx /* num_bearings <= glyph < num_glyphs; * num_bearings <= num_advances */ - /* TODO Optimize */ - if (num_bearings == num_advances) return get_advance_without_var_unscaled (num_bearings - 1); @@ -315,7 +377,7 @@ struct hmtxvmtx if (var_table.get_length ()) return advance + roundf (var_table->get_advance_delta_unscaled (glyph, font->coords, font->num_coords, - store_cache)); // TODO Optimize?! + store_cache)); return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else @@ -340,19 +402,17 @@ struct hmtxvmtx /* get advance: when no variations, call get_advance_without_var_unscaled. * when there're variations, get advance value from mtx_map in subset_plan*/ unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan, - const hb_hashmap_t> *mtx_map, + const hb_hashmap_t> *mtx_map, unsigned new_gid, const accelerator_t &_mtx) const { - if (mtx_map->is_empty () || - (new_gid == 0 && !mtx_map->has (new_gid))) + if (mtx_map->is_empty ()) { hb_codepoint_t old_gid = 0; return plan->old_gid_for_new_gid (new_gid, &old_gid) ? _mtx.get_advance_without_var_unscaled (old_gid) : 0; } - else - { return mtx_map->get (new_gid).first; } + return mtx_map->get (new_gid).first; } protected: diff --git a/third_party/harfbuzz-ng/src/src/hb-ot-layout-common.hh b/third_party/harfbuzz-ng/src/src/hb-ot-layout-common.hh index 28f492bac438..ad8a6e0be645 100644 --- a/third_party/harfbuzz-ng/src/src/hb-ot-layout-common.hh +++ b/third_party/harfbuzz-ng/src/src/hb-ot-layout-common.hh @@ -44,42 +44,6 @@ using OT::Layout::Common::RangeRecord; using OT::Layout::SmallTypes; using OT::Layout::MediumTypes; -#ifndef HB_MAX_NESTING_LEVEL -#define HB_MAX_NESTING_LEVEL 64 -#endif -#ifndef HB_MAX_CONTEXT_LENGTH -#define HB_MAX_CONTEXT_LENGTH 64 -#endif -#ifndef HB_CLOSURE_MAX_STAGES -/* - * The maximum number of times a lookup can be applied during shaping. - * Used to limit the number of iterations of the closure algorithm. - * This must be larger than the number of times add_gsub_pause() is - * called in a collect_features call of any shaper. - */ -#define HB_CLOSURE_MAX_STAGES 12 -#endif - -#ifndef HB_MAX_SCRIPTS -#define HB_MAX_SCRIPTS 500 -#endif - -#ifndef HB_MAX_LANGSYS -#define HB_MAX_LANGSYS 2000 -#endif - -#ifndef HB_MAX_LANGSYS_FEATURE_COUNT -#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 -#endif - -#ifndef HB_MAX_FEATURE_INDICES -#define HB_MAX_FEATURE_INDICES 1500 -#endif - -#ifndef HB_MAX_LOOKUP_VISIT_COUNT -#define HB_MAX_LOOKUP_VISIT_COUNT 35000 -#endif - namespace OT { @@ -192,19 +156,19 @@ struct hb_subset_layout_context_t : { if (tag_ == HB_OT_TAG_GSUB) { - lookup_index_map = c_->plan->gsub_lookups; - script_langsys_map = c_->plan->gsub_langsys; - feature_index_map = c_->plan->gsub_features; - feature_substitutes_map = c_->plan->gsub_feature_substitutes_map; - feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map; + lookup_index_map = &c_->plan->gsub_lookups; + script_langsys_map = &c_->plan->gsub_langsys; + feature_index_map = &c_->plan->gsub_features; + feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map; + feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map; } else { - lookup_index_map = c_->plan->gpos_lookups; - script_langsys_map = c_->plan->gpos_langsys; - feature_index_map = c_->plan->gpos_features; - feature_substitutes_map = c_->plan->gpos_feature_substitutes_map; - feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map; + lookup_index_map = &c_->plan->gpos_lookups; + script_langsys_map = &c_->plan->gpos_langsys; + feature_index_map = &c_->plan->gpos_features; + feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map; + feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map; } } @@ -478,7 +442,7 @@ struct IndexArray : Array16Of { if (_count) { - + this->sub_array (start_offset, _count) + + this->as_array ().sub_array (start_offset, _count) | hb_sink (hb_array (_indexes, *_count)) ; } @@ -565,6 +529,9 @@ struct FeatureParamsSize return_trace (true); } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { nameids_to_retain->add (subfamilyNameID); } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -621,6 +588,9 @@ struct FeatureParamsStylisticSet return_trace (c->check_struct (this)); } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { nameids_to_retain->add (uiNameID); } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -658,7 +628,7 @@ struct FeatureParamsCharacterVariants { if (char_count) { - + characters.sub_array (start_offset, char_count) + + characters.as_array ().sub_array (start_offset, char_count) | hb_sink (hb_array (chars, *char_count)) ; } @@ -668,6 +638,20 @@ struct FeatureParamsCharacterVariants unsigned get_size () const { return min_size + characters.len * HBUINT24::static_size; } + void collect_name_ids (hb_set_t *nameids_to_retain /* OUT */) const + { + if (featUILableNameID) nameids_to_retain->add (featUILableNameID); + if (featUITooltipTextNameID) nameids_to_retain->add (featUITooltipTextNameID); + if (sampleTextNameID) nameids_to_retain->add (sampleTextNameID); + + if (!firstParamUILabelNameID || !numNamedParameters || numNamedParameters >= 0x7FFF) + return; + + unsigned last_name_id = (unsigned) firstParamUILabelNameID + (unsigned) numNamedParameters - 1; + if (last_name_id >= 256 && last_name_id <= 32767) + nameids_to_retain->add_range (firstParamUILabelNameID, last_name_id); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); @@ -730,6 +714,19 @@ struct FeatureParams return_trace (true); } + void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const + { +#ifdef HB_NO_LAYOUT_FEATURE_PARAMS + return; +#endif + if (tag == HB_TAG ('s','i','z','e')) + return (u.size.collect_name_ids (nameids_to_retain)); + if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return (u.stylisticSet.collect_name_ids (nameids_to_retain)); + if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return (u.characterVariants.collect_name_ids (nameids_to_retain)); + } + bool subset (hb_subset_context_t *c, const Tag* tag) const { TRACE_SUBSET (this); @@ -798,6 +795,12 @@ struct Feature bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const { return lookupIndex.intersects (lookup_indexes); } + void collect_name_ids (hb_tag_t tag, hb_set_t *nameids_to_retain /* OUT */) const + { + if (featureParams) + get_feature_params ().collect_name_ids (tag, nameids_to_retain); + } + bool subset (hb_subset_context_t *c, hb_subset_layout_context_t *l, const Tag *tag = nullptr) const @@ -932,7 +935,7 @@ struct RecordArrayOf : SortedArray16Of> { if (record_count) { - + this->sub_array (start_offset, record_count) + + this->as_array ().sub_array (start_offset, record_count) | hb_map (&Record::tag) | hb_sink (hb_array (record_tags, *record_count)) ; @@ -980,18 +983,16 @@ struct RecordListOfFeature : RecordListOf auto *out = c->serializer->start_embed (*this); if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - unsigned count = this->len; - - + hb_zip (*this, hb_range (count)) - | hb_filter (l->feature_index_map, hb_second) - | hb_apply ([l, out, this] (const hb_pair_t&, unsigned>& _) + + hb_enumerate (*this) + | hb_filter (l->feature_index_map, hb_first) + | hb_apply ([l, out, this] (const hb_pair_t&>& _) { const Feature *f_sub = nullptr; const Feature **f = nullptr; - if (l->feature_substitutes_map->has (_.second, &f)) + if (l->feature_substitutes_map->has (_.first, &f)) f_sub = *f; - subset_record_array (l, out, this, f_sub) (_.first); + subset_record_array (l, out, this, f_sub) (_.second); }) ; @@ -1147,7 +1148,6 @@ struct Script return; } - unsigned langsys_count = get_lang_sys_count (); if (has_default_lang_sys ()) { //only collect features from non-redundant langsys @@ -1156,24 +1156,24 @@ struct Script d.collect_features (c); } - for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) + for (auto _ : + hb_enumerate (langSys)) { - const LangSys& l = this+_.first.offset; + const LangSys& l = this+_.second.offset; if (!c->visitLangsys (l.get_feature_count ())) continue; if (l.compare (d, c->duplicate_feature_map)) continue; l.collect_features (c); - c->script_langsys_map->get (script_index)->add (_.second); + c->script_langsys_map->get (script_index)->add (_.first); } } else { - for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) + for (auto _ : + hb_enumerate (langSys)) { - const LangSys& l = this+_.first.offset; + const LangSys& l = this+_.second.offset; if (!c->visitLangsys (l.get_feature_count ())) continue; l.collect_features (c); - c->script_langsys_map->get (script_index)->add (_.second); + c->script_langsys_map->get (script_index)->add (_.first); } } } @@ -1184,7 +1184,7 @@ struct Script { TRACE_SUBSET (this); if (!l->visitScript ()) return_trace (false); - if (tag && !c->plan->layout_scripts->has (*tag)) + if (tag && !c->plan->layout_scripts.has (*tag)) return false; auto *out = c->serializer->start_embed (*this); @@ -1211,10 +1211,9 @@ struct Script const hb_set_t *active_langsys = l->script_langsys_map->get (l->cur_script_index); if (active_langsys) { - unsigned count = langSys.len; - + hb_zip (langSys, hb_range (count)) - | hb_filter (active_langsys, hb_second) - | hb_map (hb_first) + + hb_enumerate (langSys) + | hb_filter (active_langsys, hb_first) + | hb_map (hb_second) | hb_filter ([=] (const Record& record) {return l->visitLangSys (); }) | hb_apply (subset_record_array (l, &(out->langSys), this)) ; @@ -1250,12 +1249,11 @@ struct RecordListOfScript : RecordListOf