diff --git a/graf2d/mathtext/CMakeLists.txt b/builtins/libmathtext/CMakeLists.txt similarity index 51% rename from graf2d/mathtext/CMakeLists.txt rename to builtins/libmathtext/CMakeLists.txt index 5f3e6240ac585..f39da6eebc71f 100644 --- a/graf2d/mathtext/CMakeLists.txt +++ b/builtins/libmathtext/CMakeLists.txt @@ -4,23 +4,23 @@ # For the licensing terms see $ROOTSYS/LICENSE. # For the list of contributors see $ROOTSYS/README/CREDITS. -ROOT_LINKER_LIBRARY(mathtext - fontembed.cxx - fontembedps.cxx - mathrender.cxx - mathrenderstyle.cxx - mathrendertoken.cxx - mathtext.cxx - mathtextencode.cxx - mathtextparse.cxx - mathtextview.cxx - TYPE - STATIC - NOINSTALL +add_library(mathtext STATIC + fontembed.cc + fontembedpdf.cc + fontembedps.cc + geometry.cc + mathrender.cc + mathrenderstyle.cc + mathrendertoken.cc + mathtext.cc + mathtextencode.cc + mathtextparse.cc + mathtextview.cc ) +target_include_directories(mathtext PUBLIC ./) check_cxx_compiler_flag(-Wbidi-chars=none GCC_HAS_BIDI_CHARS_FLAG) if(GCC_HAS_BIDI_CHARS_FLAG) - set_source_files_properties(src/fontembed.cxx COMPILE_FLAGS "-Wbidi-chars=none") + set_source_files_properties(fontembed.cc COMPILE_FLAGS "-Wbidi-chars=none") endif() set_property(TARGET mathtext PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/builtins/libmathtext/LICENSE b/builtins/libmathtext/LICENSE new file mode 100644 index 0000000000000..f795d0a8240c0 --- /dev/null +++ b/builtins/libmathtext/LICENSE @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +␌ + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +␌ + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. +␌ + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +␌ + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +␌ + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +␌ + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. +␌ + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +␌ + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +␌ + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/builtins/libmathtext/fontembed.cc b/builtins/libmathtext/fontembed.cc new file mode 100644 index 0000000000000..ef7a5c9f26512 --- /dev/null +++ b/builtins/libmathtext/fontembed.cc @@ -0,0 +1,1925 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2016 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include +#include +#if defined(__APPLE__) +#include +#define bswap_16 OSSwapInt16 +#define bswap_32 OSSwapInt32 +#elif defined(_WIN32) +#define bswap_16(x) _byteswap_ushort(x) +#define bswap_32(x) _byteswap_ulong(x) +#else +#include +#endif + +// References: +// +// Adobe Systems, Inc. and Microsoft Corp., OpenType specification +// (2002), version 1.4. +// +// Apple Computer, Inc., TrueType reference ranual (2002) +// +// Microsoft Corp., TrueType 1.0 font files: technical specification +// (1995), version 1.66 + +#define ERROR_ACCESS(t) \ + (fprintf(stderr, "%s:%d: error: access out of bound in %s\n", \ + __FILE__, __LINE__, t)); +#define ERROR_UNSUPPORTED(t) \ + (fprintf(stderr, "%s:%d: error: %s is not supported\n", \ + __FILE__, __LINE__, t)); + +namespace mathtext { + + typedef int32_t fixed_t; + + void font_embed_t::protected_memcpy( + void *destination, + std::vector::const_iterator source, + std::vector::const_iterator source_end, + size_t length, const char *location) + { + if (source + length > source_end) { + ERROR_ACCESS(location); + } + memcpy(destination, &source[0], length); + } + + void font_embed_t::parse_ttf_encoding_subtable_format4( + std::map &cid_map, + const std::vector &font_data, const size_t offset) + { + static const char *location = + "TrueType encoding table format 4"; + + cid_map.clear(); + + size_t offset_current = offset; + + struct ttf_encoding_subtable_format4_s { + uint16_t format; + uint16_t length; + uint16_t language; + uint16_t seg_count_x2; + uint16_t search_range; + uint16_t entry_selector; + uint16_t range_shift; + } encoding_subtable_format4; + + protected_memcpy(&encoding_subtable_format4, + font_data.begin() + offset_current, + font_data.end(), + sizeof(struct ttf_encoding_subtable_format4_s), + location); + offset_current += + sizeof(struct ttf_encoding_subtable_format4_s); +#ifdef LITTLE_ENDIAN + encoding_subtable_format4.length = + bswap_16(encoding_subtable_format4.length); + encoding_subtable_format4.seg_count_x2 = + bswap_16(encoding_subtable_format4.seg_count_x2); +#endif // LITTLE_ENDIAN + + const uint16_t seg_count = + encoding_subtable_format4.seg_count_x2 >> 1; + uint16_t *end_code = new uint16_t[seg_count]; + + protected_memcpy(end_code, + font_data.begin() + offset_current, + font_data.end(), + seg_count * sizeof(uint16_t), + location); + offset_current += seg_count * sizeof(uint16_t); +#ifdef LITTLE_ENDIAN + for (uint16_t segment = 0; segment < seg_count; segment++) { + end_code[segment] = bswap_16(end_code[segment]); + } +#endif // LITTLE_ENDIAN + + uint16_t reserved_pad; + + protected_memcpy(&reserved_pad, + font_data.begin() + offset_current, + font_data.end(), sizeof(uint16_t), + location); + offset_current += sizeof(uint16_t); + + uint16_t *start_code = new uint16_t[seg_count]; + + protected_memcpy(start_code, + font_data.begin() + offset_current, + font_data.end(), + seg_count * sizeof(uint16_t), location); + offset_current += seg_count * sizeof(uint16_t); +#ifdef LITTLE_ENDIAN + for (uint16_t segment = 0; segment < seg_count; segment++) { + start_code[segment] = bswap_16(start_code[segment]); + } +#endif // LITTLE_ENDIAN + + uint16_t *id_delta = new uint16_t[seg_count]; + + protected_memcpy(id_delta, + font_data.begin() + offset_current, + font_data.end(), + seg_count * sizeof(uint16_t), location); + offset_current += seg_count * sizeof(uint16_t); +#ifdef LITTLE_ENDIAN + for (uint16_t segment = 0; segment < seg_count; segment++) { + id_delta[segment] = bswap_16(id_delta[segment]); + } +#endif // LITTLE_ENDIAN + + const uint16_t variable = + (encoding_subtable_format4.length >> 1) - + (seg_count << 2) - 8; + uint16_t *id_range_offset = + new uint16_t[seg_count + variable]; + + protected_memcpy(id_range_offset, + font_data.begin() + offset_current, + font_data.end(), + (seg_count + variable) * sizeof(uint16_t), + location); + offset_current += (seg_count + variable) * sizeof(uint16_t); +#ifdef LITTLE_ENDIAN + for (uint16_t j = 0; j < seg_count + variable; j++) { + id_range_offset[j] = bswap_16(id_range_offset[j]); + } +#endif // LITTLE_ENDIAN + + for (uint16_t segment = 0; segment < seg_count; segment++) { + for (uint32_t code = start_code[segment]; + code <= end_code[segment]; code++) { + const uint16_t inner_offset = segment + + (id_range_offset[segment] >> 1) + + (code - start_code[segment]); + const uint16_t glyph_id = + id_range_offset[segment] == 0 ? + id_delta[segment] + code : + inner_offset >= seg_count + variable ? + 0 : id_range_offset[inner_offset]; + + cid_map[static_cast(code)] = glyph_id; + } + } + + delete [] end_code; + delete [] start_code; + delete [] id_delta; + delete [] id_range_offset; + } + + void font_embed_t::parse_ttf_encoding_subtable_format12( + std::map &cid_map, + const std::vector &font_data, const size_t offset) + { + static const char *location = + "TrueType encoding table format 12"; + + cid_map.clear(); + + size_t offset_current = offset; + + struct ttf_encoding_subtable_format12_s { + uint16_t format; + uint16_t reserved; + uint32_t length; + uint32_t language; + uint32_t ngroups; + } encoding_subtable_format12; + + protected_memcpy(&encoding_subtable_format12, + font_data.begin() + offset_current, + font_data.end(), + sizeof(struct ttf_encoding_subtable_format12_s), + location); + offset_current += + sizeof(struct ttf_encoding_subtable_format12_s); +#ifdef LITTLE_ENDIAN + encoding_subtable_format12.ngroups = + bswap_32(encoding_subtable_format12.ngroups); +#endif // LITTLE_ENDIAN + + struct ttf_encoding_subtable_format12_group_s { + uint32_t start_char_code; + uint32_t end_char_code; + uint32_t start_glyph_id; + } encoding_subtable_format12_group; + + for (uint32_t group = 0; + group < encoding_subtable_format12.ngroups; group++) { + protected_memcpy( + &encoding_subtable_format12_group, + font_data.begin() + offset_current, + font_data.end(), + sizeof(struct ttf_encoding_subtable_format12_group_s), + location); + offset_current += + sizeof(struct ttf_encoding_subtable_format12_group_s); +#ifdef LITTLE_ENDIAN + encoding_subtable_format12_group.start_char_code = + bswap_32(encoding_subtable_format12_group.start_char_code); + encoding_subtable_format12_group.end_char_code = + bswap_32(encoding_subtable_format12_group.end_char_code); + encoding_subtable_format12_group.start_glyph_id = + bswap_32(encoding_subtable_format12_group.start_glyph_id); +#endif // LITTLE_ENDIAN + for (uint32_t code = + encoding_subtable_format12_group.start_char_code, + glyph_id = + encoding_subtable_format12_group.start_glyph_id; + code <= encoding_subtable_format12_group.end_char_code; + code++, glyph_id++) { + cid_map[static_cast(code)] = glyph_id; + } + } + } + + ///////////////////////////////////////////////////////////////////// + // Currently unfinished font subsetting code below + ///////////////////////////////////////////////////////////////////// + +#if 0 + // Rename: + // name + // Subset: + // glyf, loca, hmtx, vmtx, cmap, hdmx, VDMX, kern, LTSH, VORG + // Conditional subset: + // post 2.0 + // Remove completely: + // DSIG, BASE, GDEF, GPOS, GSUB, JSTF, EBDT, EBLC, EBSC + + void font_embed_t::subset_rename_otf_name_table( + struct table_data_s &table_data, + std::map glyph_usage) + { + // Prefix name IDs 1, 4, 6, 16, 19, 20, 21 + + // No platform ID other than 1 and 3 is permitted for the name + // table + + // Platform ID = 1: 1 byte + // Platform ID = 3: 2 byte + + // Reset UID 4,000,000 and 4,999,999 and XUID + } + + void font_embed_t::subset_ttf_glyf_table( + struct table_data_s &table_data, + std::map glyph_usage) + { + } + + void font_embed_t::subset_ttf_loca_table( + struct table_data_s &table_data, + std::map glyph_usage) + { + } + + void font_embed_t::subset_ttf_post_table( + struct table_data_s &table_data, + std::map glyph_usage) + { + } + + class cff_index_t { + public: + uint16_t count; + uint8_t off_size; + std::vector offset; + std::vector data; + cff_index_t(const uint8_t *input_data) + { + memcpy(&count, input_data, sizeof(uint16_t)); +#ifdef LITTLE_ENDIAN + count = bswap_16(count); +#endif // LITTLE_ENDIAN + memcpy(&off_size, input_data + sizeof(uint16_t), + sizeof(uint8_t)); + + if (!(off_size >= 1 && off_size < 5)) { + return; + } + + const uint8_t *input_data_offset = + input_data + sizeof(uint16_t) + sizeof(uint8_t); + + // The off by one or indexing from one convention in CFF + // is corrected here, i.e. the resulting offset table is + // zero-based, and not the CFF one. + + offset.reserve(count + 1); + switch (off_size) { + case 1: + for (size_t i = 0; i < count + 1; i++) { + offset.push_back(input_data_offset[i]); + } + break; + case 2: + for (size_t i = 0; i < count + 1; i++) { + offset.push_back(reinterpret_cast( + input_data_offset)[i]); +#ifdef LITTLE_ENDIAN + offset.back() = bswap_16(offset.back()); +#endif // LITTLE_ENDIAN + } + break; + case 3: + for (size_t i = 0; i < 3 * (count + 1); i += 3) { + const uint32_t value = + input_data_offset[3 * i] << 16 | + input_data_offset[3 * i + 1] << 8 | + input_data_offset[3 * i + 2]; + + offset.push_back(value); + } + break; + case 4: + for (size_t i = 0; i < count + 1; i++) { + offset.push_back(reinterpret_cast( + input_data_offset)[i]); +#ifdef LITTLE_ENDIAN + offset.back() = bswap_32(offset.back()); +#endif // LITTLE_ENDIAN + } + break; + } + + const uint8_t *input_data_data = + input_data_offset + off_size * (count + 1); + + data = std::vector(input_data_data, input_data_data); + } + ~cff_index_t(void) + { + } + }; + + void font_embed_t::subset_otf_cff_table( + struct table_data_s &table_data, + std::map glyph_usage) + { + } + + std::vector font_embed_t::subset_otf( + const std::vector &font_data, + const std::map &glyph_usage) + { + std::vector retval; + struct otf_offset_table_s { + char sfnt_version[4]; + uint16_t num_tables; + uint16_t search_range; + uint16_t entry_selector; + uint16_t range_shift; + } offset_table; + + memcpy(&offset_table, &font_data[0], + sizeof(struct otf_offset_table_s)); + if (strncmp(offset_table.sfnt_version, "OTTO", 4) != 0 || + strncmp(offset_table.sfnt_version, "\0\1\0\0", 4) != 0) { + // Neither a OpenType, nor TrueType font +#if 0 + fprintf(stderr, "%s:%d: error: unknown sfnt_version = " + "0x%02x%02x%02x%02x\n", __FILE__, __LINE__, + offset_table.sfnt_version[0], + offset_table.sfnt_version[1], + offset_table.sfnt_version[2], + offset_table.sfnt_version[3]); +#endif + return retval; + } +#ifdef LITTLE_ENDIAN + offset_table.num_tables = bswap_16(offset_table.num_tables); +#endif // LITTLE_ENDIAN + + struct otf_table_directory_s { + char tag[4]; + uint32_t check_sum; + uint32_t offset; + uint32_t length; + }; + struct table_data_s *table_data = + new struct table_data_s[offset_table.num_tables]; + + for (uint16_t i = 0; i < offset_table.num_tables; i++) { + struct otf_table_directory_s table_directory; + + protected_memcpy( + &table_directory, + font_data.begin() + + sizeof(struct otf_offset_table_s) + i * + sizeof(struct otf_table_directory_s), + font_data.end(), + sizeof(struct otf_table_directory_s), + location); +#ifdef LITTLE_ENDIAN + table_directory.offset = + bswap_32(table_directory.offset); + table_directory.length = + bswap_32(table_directory.length); +#endif // LITTLE_ENDIAN +#if 0 + fprintf(stderr, "%s:%d: tag = %c%c%c%c, offset = %u, " + "length = %u\n", __FILE__, __LINE__, + table_directory.tag[0], table_directory.tag[1], + table_directory.tag[2], table_directory.tag[3], + table_directory.offset, table_directory.length); +#endif + memcpy(table_data[i].tag, table_directory.tag, + 4 * sizeof(char)); + table_data[i].data.resize(table_directory.length); + memcpy(&(table_data[i].data[0]), + &font_data[table_directory.offset], + table_directory.length); + } + + size_t size_count; + + size_count = sizeof(struct otf_offset_table_s) + + offset_table.num_tables * + sizeof(struct otf_table_directory_s); + for (size_t i = 0; i < offset_table.num_tables; i++) { + size_count += table_data[i].data.size(); + } + + size_t offset_current = sizeof(struct otf_offset_table_s); + size_t offset_check_sum_adjustment = 0; + bool head_table_exists = false; + + retval.resize(size_count); + memcpy(&retval[0], &font_data[0], + sizeof(struct otf_offset_table_s)); + for (size_t i = 0; i < offset_table.num_tables; i++) { + struct otf_table_directory_s table_directory; + const bool head_table = + strncmp(table_directory.tag, "head", 4) == 0; + + memcpy(table_directory.tag, table_data[i].tag, + 4 * sizeof(char)); + if (head_table) { + // Reset checkSumAdjustment in order to calculate the + // check sum of the head table + offset_check_sum_adjustment = 2 * sizeof(fixed_t); + *reinterpret_cast(&(table_data[i].data[ + offset_check_sum_adjustment])) = 0U; + // Change the offset for checkSumAdjustment to the + // global indexing + offset_check_sum_adjustment += offset_current; + head_table_exists = true; + } + table_directory.check_sum = + otf_check_sum(table_data[i].data); + table_directory.offset = size_count; + table_directory.length = table_data[i].data.size(); + + memcpy(&retval[offset_current], &table_directory, + sizeof(struct otf_table_directory_s)); + size_count += table_data[i].data.size(); + offset_current += sizeof(struct otf_table_directory_s); + } + + for (size_t i = 0; i < offset_table.num_tables; i++) { + memcpy(&retval[offset_current], &(table_data[i].data[0]), + table_data[i].data.size()); + offset_current += table_data[i].data.size(); + + const size_t padding_size = + (4U - table_data[i].data.size()) & 3U; + + memset(&retval[offset_current], '\0', padding_size); + offset_current += padding_size; + } + + if (head_table_exists) { + // Set checkSumAdjustment in the head table + *reinterpret_cast(&(retval[ + offset_check_sum_adjustment])) = + 0xb1b0afbaU - otf_check_sum(retval); + } + + return retval; + } +#endif ////////////////////////////////////////////////////////////// + + uint32_t font_embed_t::otf_check_sum( + const std::vector &table_data) + { + const uint32_t *table = + reinterpret_cast(&(table_data[0])); + const uint32_t nword = table_data.size() >> 2; + uint32_t sum = 0; + + for (size_t i = 0; i < nword; i++) { +#ifdef LITTLE_ENDIAN + sum += bswap_32(table[i]); +#else // LITTLE_ENDIAN + sum += table[i]; +#endif // LITTLE_ENDIAN + } + + // Do not assume 0x00 padding and calculate partial uint32_t + // checksums directly. + const uint8_t *table_tail = + reinterpret_cast(&(table[nword])); + + switch(table_data.size() & 3U) { + case 3: sum += table_tail[2] << 8; + case 2: sum += table_tail[1] << 16; + case 1: sum += table_tail[0] << 24; break; + } + + return sum; + } + + std::vector font_embed_t::read_font_data(FILE *fp) + { + std::vector font_data; + + if (fp == NULL) { + return font_data; + } + if (fseek(fp, 0L, SEEK_SET) == -1) { + perror("fseek"); + return font_data; + } + if (fseek(fp, 0L, SEEK_END) == -1) { + perror("fseek"); + return font_data; + } + + const long length = ftell(fp); + + if (length == -1) { + perror("ftell"); + return font_data; + } + font_data.resize(length); + if (fseek(fp, 0L, SEEK_SET) == -1) { + perror("fseek"); + font_data.clear(); + return font_data; + } + if (fread(&font_data[0], sizeof(uint8_t), + length, fp) != static_cast(length)) { + perror("fread"); + font_data.clear(); + return font_data; + } + fseek(fp, 0L, SEEK_SET); + + return font_data; + } + + std::vector font_embed_t::read_font_data( + const std::string &filename) + { + FILE *fp = fopen(filename.c_str(), "r"); + std::vector font_data; + + if (fp == NULL) { + perror("fopen"); + return font_data; + } + font_data = read_font_data(fp); + fclose(fp); + + return font_data; + } + + std::map > + font_embed_t::parse_ttf_offset_table( + const std::vector &font_data, + size_t offset_table_size, uint16_t num_tables) + { + std::map > table; + + for (uint16_t i = 0; i < num_tables; i++) { + struct ttf_table_directory_s { + char tag[4]; + uint32_t check_sum; + uint32_t offset; + uint32_t length; + } table_directory; + + if (!(offset_table_size + (i + 1) * + sizeof(struct ttf_table_directory_s) <= + font_data.size())) { + ERROR_ACCESS("table directory"); + continue; + } + memcpy(&table_directory, + &font_data[offset_table_size + i * + sizeof(struct ttf_table_directory_s)], + sizeof(struct ttf_table_directory_s)); +#ifdef LITTLE_ENDIAN + table_directory.offset = + bswap_32(table_directory.offset); + table_directory.length = + bswap_32(table_directory.length); +#endif // LITTLE_ENDIAN + if (!(table_directory.offset + table_directory.length <= + font_data.size())) { + ERROR_ACCESS("table directory"); + continue; + } + table[std::string(table_directory.tag, + table_directory.tag + 4)] = + std::pair( + table_directory.offset, + table_directory.length); + } + + return table; + } + + void font_embed_t::parse_ttf_cmap( + std::map &cid_map, + const std::vector &font_data, + uint32_t cmap_offset) + { + if (cmap_offset == 0) { + return; + } + + struct ttf_mapping_table_s { + uint16_t version; + uint16_t num_encoding_tables; + } mapping_table; + + memcpy(&mapping_table, &font_data[cmap_offset], + sizeof(struct ttf_mapping_table_s)); +#ifdef LITTLE_ENDIAN + mapping_table.num_encoding_tables = + bswap_16(mapping_table.num_encoding_tables); +#endif // LITTLE_ENDIAN + + uint32_t *subtable_offset = + new uint32_t[mapping_table.num_encoding_tables]; + + for (uint16_t i = 0; + i < mapping_table.num_encoding_tables; i++) { + struct ttf_encoding_table_s { + uint16_t platform_id; + uint16_t encoding_id; + uint32_t offset; + } encoding_table; + + memcpy( + &encoding_table, + &font_data[cmap_offset + + sizeof(struct ttf_mapping_table_s) + + i * sizeof(struct ttf_encoding_table_s)], + sizeof(struct ttf_encoding_table_s)); +#ifdef LITTLE_ENDIAN + encoding_table.platform_id = + bswap_16(encoding_table.platform_id); + encoding_table.encoding_id = + bswap_16(encoding_table.encoding_id); + encoding_table.offset = bswap_32(encoding_table.offset); +#endif // LITTLE_ENDIAN + subtable_offset[i] = cmap_offset + encoding_table.offset; + } + + int priority_max = 0; + + for (uint16_t i = 0; + i < mapping_table.num_encoding_tables; i++) { + struct ttf_encoding_subtable_common_s { + uint16_t format; + uint16_t length; + uint16_t language; + } encoding_subtable_common; + + memcpy(&encoding_subtable_common, + &font_data[subtable_offset[i]], + sizeof(struct ttf_encoding_subtable_common_s)); +#ifdef LITTLE_ENDIAN + encoding_subtable_common.format = + bswap_16(encoding_subtable_common.format); + encoding_subtable_common.length = + bswap_16(encoding_subtable_common.length); + encoding_subtable_common.language = + bswap_16(encoding_subtable_common.language); +#endif // LITTLE_ENDIAN + + size_t offset_current = subtable_offset[i]; +#if 0 + fprintf(stderr, "%s:%d: encoding_subtable_common.format " + "= %hu\n", __FILE__, __LINE__, + encoding_subtable_common.format); + fprintf(stderr, "%s:%d: encoding_subtable_common.length " + "= %hu\n", __FILE__, __LINE__, + encoding_subtable_common.length); + fprintf(stderr, "%s:%d: encoding_subtable_common.language " + "= %hu\n", __FILE__, __LINE__, + encoding_subtable_common.language); +#endif + + int priority; + + switch(encoding_subtable_common.format) { + ///////////////////////////////////////////////////// + // 8 and 16 bit mappings + // Priority range 1, 3..5 (2 reserved for format 13) + case 0: + priority = 1; + // Byte encoding table + break; + case 2: + // High-byte mapping through table + priority = 3; + break; + case 4: + // Segment mapping to delta values + priority = 5; +#if 0 + fprintf(stderr, "%s:%d: priority = %d, priority_max " + "= %d\n", __FILE__, __LINE__, priority, + priority_max); +#endif + if (priority_max <= priority) { + parse_ttf_encoding_subtable_format4( + cid_map, font_data, offset_current); + priority_max = priority; + } + break; + case 6: + // Trimmed table mapping + priority = 5; + break; + ///////////////////////////////////////////////////// + // 32-bit mappings + // Priority range 6..9 (2 reserved for format 13) + case 8: + // Mixed 16-bit and 32-bit coverage + priority = 6; + break; + case 10: + // Trimmed array + priority = 6; + break; + case 12: + // Segmented coverage + priority = 6; + if (priority_max <= priority) { + parse_ttf_encoding_subtable_format12( + cid_map, font_data, offset_current); + priority_max = priority; + } + break; + case 13: + // Last resort font + priority = 2; + break; + case 14: + // Unicode variation sequences + priority = 9; + break; + default: + delete [] subtable_offset; + return; + } + } + + delete [] subtable_offset; + } + + void font_embed_t::parse_ttf_head( + double *font_bbox, uint16_t &units_per_em, + const std::vector &font_data, + uint32_t head_offset) + { + if (head_offset == 0) { + return; + } + + struct ttf_head_table_s { + fixed_t version; + fixed_t font_revision; + uint32_t check_sum_adjustment; + uint32_t magic_number; + uint16_t flags; + uint16_t units_per_em; + char created[8]; + char modified[8]; + int16_t x_min; + int16_t y_min; + int16_t x_max; + int16_t y_max; + uint16_t mac_style; + uint16_t lowest_rec_ppem; + int16_t font_direction_hint; + int16_t index_to_loc_format; + int16_t glyph_data_format; + } head_table; + + if (!(head_offset + sizeof(struct ttf_head_table_s) <= + font_data.size())) { + ERROR_ACCESS("head table"); + return; + } + memcpy(&head_table, &font_data[head_offset], + sizeof(struct ttf_head_table_s)); +#ifdef LITTLE_ENDIAN + head_table.units_per_em = bswap_16(head_table.units_per_em); + head_table.x_min = bswap_16(head_table.x_min); + head_table.y_min = bswap_16(head_table.y_min); + head_table.x_max = bswap_16(head_table.x_max); + head_table.y_max = bswap_16(head_table.y_max); +#endif // LITTLE_ENDIAN + + units_per_em = head_table.units_per_em; + font_bbox[0] = head_table.x_min * 1000.0 / units_per_em; + font_bbox[1] = head_table.y_min * 1000.0 / units_per_em; + font_bbox[2] = head_table.x_max * 1000.0 / units_per_em; + font_bbox[3] = head_table.y_max * 1000.0 / units_per_em; + } + + uint16_t font_embed_t::parse_ttf_hhea( + const std::vector &font_data, + uint32_t hhea_offset) + { + if (!(hhea_offset + 36 <= font_data.size())) { + ERROR_ACCESS("hhea table"); + } + + // We don't care about anything other than numberOfHMetrics, which + // sits at a common position for both versions 0.5 (OTF CFF) + // and 1.0 (TTF). + + uint16_t number_of_h_metrics; + + memcpy(&number_of_h_metrics, &font_data[hhea_offset + 34], 2); +#ifdef LITTLE_ENDIAN + number_of_h_metrics = bswap_16(number_of_h_metrics); +#endif // LITTLE_ENDIAN + + return number_of_h_metrics; + } + + std::vector font_embed_t::parse_ttf_hmtx( + const std::vector &font_data, + uint32_t hmtx_offset, uint16_t number_of_h_metrics) + { + std::vector advance_width; + + advance_width.resize(number_of_h_metrics); + for (size_t i = 0; i < number_of_h_metrics; i++) { + memcpy(&advance_width[i], &font_data[hmtx_offset + 4 * i], 2); +#ifdef LITTLE_ENDIAN + advance_width[i] = bswap_16(advance_width[i]); +#endif // LITTLE_ENDIAN + } + + return advance_width; + } + + uint16_t font_embed_t::parse_ttf_maxp( + const std::vector &font_data, + uint32_t maxp_offset) + { + if (!(maxp_offset + 6 <= font_data.size())) { + ERROR_ACCESS("maxp table"); + } + + // We don't care about anything other than numGlyphs, which + // sits at a common position for both versions 0.5 (OTF CFF) + // and 1.0 (TTF). + + uint16_t num_glyphs; + + memcpy(&num_glyphs, &font_data[maxp_offset + 4], 2); +#ifdef LITTLE_ENDIAN + num_glyphs = bswap_16(num_glyphs); +#endif // LITTLE_ENDIAN + + return num_glyphs; + } + + void font_embed_t::parse_ttf_name( + std::string &font_name, uint16_t &cid_encoding_id, + const std::vector &font_data, + uint32_t name_offset) + { + if (name_offset == 0) { + return; + } + + struct ttf_naming_table_header_s { + uint16_t format; + uint16_t count; + uint16_t string_offset; + } naming_table_header; + + if (!(name_offset + + sizeof(struct ttf_naming_table_header_s) <= + font_data.size())) { + ERROR_ACCESS("name table"); + return; + } + + memcpy(&naming_table_header, &font_data[name_offset], + sizeof(struct ttf_naming_table_header_s)); +#ifdef LITTLE_ENDIAN + naming_table_header.format = + bswap_16(naming_table_header.format); + naming_table_header.count = + bswap_16(naming_table_header.count); + naming_table_header.string_offset = + bswap_16(naming_table_header.string_offset); +#endif // LITTLE_ENDIAN + + cid_encoding_id = 0xffffU; + + for (uint16_t i = 0; i < naming_table_header.count; i++) { + struct ttf_name_record_s { + uint16_t platform_id; + uint16_t encoding_id; + uint16_t language_id; + uint16_t name_id; + uint16_t length; + uint16_t offset; + } name_record; + const size_t base_offset = name_offset + + sizeof(struct ttf_naming_table_header_s); + + if (!(base_offset + (i + 1) * + sizeof(struct ttf_name_record_s) <= + font_data.size())) { + ERROR_ACCESS("name table"); + continue; + } + memcpy(&name_record, + &font_data[base_offset + i * + sizeof(struct ttf_name_record_s)], + sizeof(struct ttf_name_record_s)); +#ifdef LITTLE_ENDIAN + name_record.platform_id = + bswap_16(name_record.platform_id); + name_record.encoding_id = + bswap_16(name_record.encoding_id); + name_record.name_id = bswap_16(name_record.name_id); +#endif // LITTLE_ENDIAN + if (name_record.platform_id == 1 && + name_record.encoding_id == 0 && + name_record.name_id == 6) { + // Postscript name in Mac OS Roman + // + // The font name in Mac OS Roman encoding is + // sufficient to obtain an ASCII PostScript name (and + // is required by OpenType specification), while the + // Windows platform uses a UCS-2 string that would + // require conversion. +#ifdef LITTLE_ENDIAN + name_record.length = bswap_16(name_record.length); + name_record.offset = bswap_16(name_record.offset); +#endif // LITTLE_ENDIAN + if (!(name_offset + + naming_table_header.string_offset + + name_record.offset + name_record.length < + font_data.size())) { + ERROR_ACCESS("name table"); + continue; + } + + const char *p = reinterpret_cast( + &font_data[name_offset + + naming_table_header.string_offset + + name_record.offset]); + + font_name = std::string(p, p + name_record.length); + } + else if (name_record.platform_id == 3 && + name_record.encoding_id == 1 && + name_record.name_id == 6) { +#ifdef LITTLE_ENDIAN + name_record.length = bswap_16(name_record.length); + name_record.offset = bswap_16(name_record.offset); +#endif // LITTLE_ENDIAN + if (!(name_offset + + naming_table_header.string_offset + + name_record.offset + name_record.length < + font_data.size())) { + ERROR_ACCESS("name table"); + continue; + } + // Very ugly UCS-2 to ASCII conversion, but should + // work for most font names + font_name.resize(name_record.length >> 1); + + for (uint16_t j = 0; j < (name_record.length >> 1); + j++) { + font_name[j] = + font_data[name_offset + + naming_table_header.string_offset + + name_record.offset + j * 2 + 1]; + } + } + if (name_record.platform_id == 1 && + name_record.name_id == 20) { + // PostScript CID findfont name + // + // encoding_id Macintosh CMap + // --------------------------- + // 1 83pv-RKSJ-H + // 2 B5pc-H + // 3 KSCpc-EUC-H + // 25 GBpc-EUC-H + cid_encoding_id = name_record.encoding_id; + // The actual Macintosh encoding CMap name is of no + // further use. Note that Adobe currently only + // actively maintains the Unicode based CMaps. + } + } + } + + void font_embed_t::parse_ttf_os_2( + uint32_t &font_descriptor_flag, double &ascent, + double &descent, double &leading, double &cap_height, + double &x_height, double &stem_v, double &avg_width, + const std::vector &font_data, + uint32_t os_2_offset, uint16_t units_per_em) + { + if (os_2_offset == 0) { + return; + } + + struct ttf_os_2_table_s { + uint16_t version; + int16_t x_avg_char_width; + uint16_t us_weight_class; + uint16_t us_width_class; + uint16_t fs_type; + int16_t y_subscript_x_size; + int16_t y_subscript_y_size; + int16_t y_subscript_x_offset; + int16_t y_subscript_y_offset; + int16_t y_superscript_x_size; + int16_t y_superscript_y_size; + int16_t y_superscript_x_offset; + int16_t y_superscript_y_offset; + int16_t y_strikeout_size; + int16_t y_strikeout_position; + int16_t s_family_class; + uint8_t panose[10]; + uint32_t ul_unicode_range1; + uint32_t ul_unicode_range2; + uint32_t ul_unicode_range3; + uint32_t ul_unicode_range4; + char ach_vend_id[4]; + uint16_t fs_selection; + uint16_t us_first_char_index; + uint16_t us_last_char_index; + int16_t s_typo_ascender; + int16_t s_typo_descender; + int16_t s_typo_line_gap; + uint16_t us_win_ascent; + uint16_t us_win_descent; + uint32_t ul_code_page_range1; + uint32_t ul_code_page_range2; + int16_t s_x_height; + int16_t s_cap_height; + uint16_t us_default_char; + uint16_t us_break_char; + uint16_t us_max_context; + uint16_t us_lower_optical_point_size; + uint16_t us_upper_optical_point_size; + } os_2_table; + + if (!(os_2_offset + sizeof(struct ttf_os_2_table_s) <= + font_data.size())) { + ERROR_ACCESS("OS/2 table"); + return; + } + memcpy(&os_2_table, &font_data[os_2_offset], + sizeof(struct ttf_os_2_table_s)); +#ifdef LITTLE_ENDIAN + os_2_table.x_avg_char_width = + bswap_16(os_2_table.x_avg_char_width); + os_2_table.s_family_class = + bswap_16(os_2_table.s_family_class); + os_2_table.s_typo_ascender = + bswap_16(os_2_table.s_typo_ascender); + os_2_table.s_typo_descender = + bswap_16(os_2_table.s_typo_descender); + os_2_table.s_typo_line_gap = + bswap_16(os_2_table.s_typo_line_gap); + os_2_table.s_x_height = bswap_16(os_2_table.s_x_height); + os_2_table.s_cap_height = bswap_16(os_2_table.s_cap_height); +#endif // LITTLE_ENDIAN + + switch (os_2_table.s_family_class >> 8) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 7: + // Serif + font_descriptor_flag |= (1U << 1); + break; + case 8: + // Sans serif + font_descriptor_flag &= ~(1U << 1); + break; + case 10: + // Script + font_descriptor_flag |= (1U << 3); + break; + case 12: + // Symbolic + font_descriptor_flag |= (1U << 2); + // Nonsymbolic + font_descriptor_flag &= ~(1U << 2); + break; + } + if (os_2_table.fs_selection & (1U << 0) || + os_2_table.fs_selection & (1U << 9)) { + // Italic (or oblique) + font_descriptor_flag |= (1U << 6); + } + ascent = os_2_table.s_typo_ascender * 1000.0 / units_per_em; + descent = os_2_table.s_typo_descender * 1000.0 / units_per_em; + leading = os_2_table.s_typo_line_gap * 1000.0 / units_per_em; + cap_height = os_2_table.s_cap_height * 1000.0 / units_per_em; + x_height = os_2_table.s_x_height * 1000.0 / units_per_em; + + // The PDFLib values + static const uint16_t weight_class_stem_v[] = { + 50, 71, 109, 125, 135, 165, 201, 241 + }; + + stem_v = weight_class_stem_v[ + std::max(0, std::min(7, + os_2_table.us_weight_class / 100)) - 3]; + avg_width = os_2_table.x_avg_char_width * 1000.0 / + units_per_em; + } + + void font_embed_t::parse_ttf_post( + std::vector &charset, + double &italic_angle, uint32_t &font_descriptor_flags, + const std::vector &font_data, + uint32_t post_offset) + { + if (post_offset == 0) { + return; + } + + struct ttf_post_script_table_s { + fixed_t format_type; + fixed_t italic_angle; + int16_t underline_position; + int16_t underline_thickness; + uint32_t is_fixed_pitch; + uint32_t min_mem_type42; + uint32_t max_mem_type42; + uint32_t min_mem_type1; + uint32_t max_mem_type1; + } post_script_table; + + if (!(post_offset + + sizeof(struct ttf_post_script_table_s) <= + font_data.size())) { + ERROR_ACCESS("post table"); + return; + } + + memcpy(&post_script_table, + &font_data[post_offset], + sizeof(struct ttf_post_script_table_s)); + +#ifdef LITTLE_ENDIAN + post_script_table.format_type = + bswap_32(post_script_table.format_type); + post_script_table.italic_angle = + bswap_32(post_script_table.italic_angle); + post_script_table.is_fixed_pitch = + bswap_32(post_script_table.is_fixed_pitch); + post_script_table.min_mem_type42 = + bswap_32(post_script_table.min_mem_type42); + post_script_table.max_mem_type42 = + bswap_32(post_script_table.max_mem_type42); +#endif // LITTLE_ENDIAN + + italic_angle = post_script_table.italic_angle * + (1.0 / (1U << 16)); + if (post_script_table.italic_angle != 0) { + font_descriptor_flags |= (1U << 6); + } + if (post_script_table.is_fixed_pitch != 0) { + font_descriptor_flags |= (1U << 0); + } + + size_t offset_current = post_offset; + +#if 0 + if (post_script_table.format_type == 0x00010000) { + // Exactly the 258 glyphs in the standard Macintosh glyph + // set + } +#endif + if (post_script_table.format_type == 0x00020000) { + // Version required by TrueType-based fonts to be used on + // Windows + // + // numberOfGlyphs, glyphNameIndex[numGlyphs], + // names[numberNewGlyphs] table + + uint16_t num_glyphs; + + memcpy(&num_glyphs, + &font_data[post_offset + + sizeof(struct ttf_post_script_table_s)], + sizeof(uint16_t)); +#ifdef LITTLE_ENDIAN + num_glyphs = bswap_16(num_glyphs); +#endif // LITTLE_ENDIAN + + uint16_t *glyph_name_index = new uint16_t[num_glyphs]; + + memcpy(glyph_name_index, + &font_data[post_offset + + sizeof(struct ttf_post_script_table_s) + + sizeof(uint16_t)], + num_glyphs * sizeof(uint16_t)); +#ifdef LITTLE_ENDIAN + for (uint16_t i = 0; i < num_glyphs; i++) { + glyph_name_index[i] = bswap_16(glyph_name_index[i]); + } +#endif // LITTLE_ENDIAN + + size_t max_glyph_name_index = 0; + for (int i = num_glyphs - 1; i >= 0; i--) { + if (glyph_name_index[i] > max_glyph_name_index) { + max_glyph_name_index = glyph_name_index[i]; + } + } + + std::string *glyph_name = + new std::string[max_glyph_name_index - 258 + 1]; + + offset_current += + sizeof(struct ttf_post_script_table_s) + + (num_glyphs + 1) * sizeof(uint16_t); + for (uint16_t i = 0; i <= max_glyph_name_index - 258; i++) { + uint8_t length; + + memcpy(&length, &font_data[offset_current], + sizeof(uint8_t)); + offset_current += sizeof(uint8_t); + + char *buffer = new char[length + 1UL]; + + memcpy(buffer, &font_data[offset_current], + length * sizeof(uint8_t)); + offset_current += length * sizeof(uint8_t); + buffer[length] = '\0'; + glyph_name[i] = buffer; + + delete [] buffer; + } + + charset.resize(num_glyphs); +#include "table/macintoshordering.h" + for (uint16_t glyph = 0; glyph < num_glyphs; glyph++) { + charset[glyph] = glyph_name_index[glyph] >= 258 ? + glyph_name[glyph_name_index[glyph] - 258].c_str() : + macintosh_ordering[glyph_name_index[glyph]]; + } + + delete [] glyph_name_index; + delete [] glyph_name; + } + else if (post_script_table.format_type == 0x00030000) { + // No PostScript name information is provided for the + // glyphs + + // Do nothing, cid_map will be initialized with standard + // Adobe glyph names once cmap is read + } + else { + fprintf(stderr, "%s:%d: unsupported post table format " + "0x%08x\n", __FILE__, __LINE__, + post_script_table.format_type); + + return; + } +#if 0 + if (post_script_table.format_type == 0x00025000) { + // Pure subset/simple reordering of the standard Macintosh + // glyph set. Deprecated as of OpenType Specification v1.3 + // + // numberOfGlyphs, offset[numGlyphs] + return; + } +#endif + } + + std::vector > + font_embed_t::parse_cff_index( + const std::vector &font_data, + uint32_t ¤t_offset, uint32_t *skip) + { + struct cff_index_s { + uint16_t count; + uint8_t off_size; + std::vector offset; + std::vector > data; + } cff_index; + + memcpy(&cff_index.count, &font_data[current_offset], 2); +#ifdef LITTLE_ENDIAN + cff_index.count = bswap_16(cff_index.count); +#endif // LITTLE_ENDIAN + current_offset += 2; + if (!(cff_index.count > 0)) { + return cff_index.data; + } + + cff_index.off_size = font_data[current_offset]; + current_offset++; + + for (size_t i = 0; i < cff_index.count + 1U; i++) { + cff_index.offset.push_back(font_data[current_offset]); + current_offset++; + for (size_t j = 1; j < cff_index.off_size; j++) { + cff_index.offset.back() <<= 8; + cff_index.offset.back() |= font_data[current_offset]; + current_offset++; + } + } + if (skip == NULL) { + for (size_t i = 0; i < cff_index.count; i++) { + cff_index.data.push_back(std::vector( + &font_data[current_offset + + cff_index.offset[i] - 1], + &font_data[current_offset + + cff_index.offset[i + 1] - 1])); + } + } + else { + *skip = cff_index.count; + } + current_offset += cff_index.offset.back() - 1; + + return cff_index.data; + } + + double font_embed_t::parse_cff_dict_number( + std::vector::const_iterator &data, + std::vector::const_iterator end) + { + const char *nibble_chr[16] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + ".", "E", "E-", "", "-", "" + }; + std::string nibble_str; + uint8_t nibble = 0; + bool nibble_high = true; + double ret = NAN; + int16_t ret_int16; + int32_t ret_int32; + + if (!(data < end)) { + ERROR_ACCESS("CFF DICT number"); + return NAN; + } + switch (data[0]) { + case 0x1e: + // Floating point value + while (!(nibble_high && nibble == 0xf) && data < end) { + nibble = nibble_high ? (data[0] >> 4) : + data[0] & 0xf; + nibble_str += nibble_chr[nibble]; + nibble_high = !nibble_high; + if (nibble_high) { + data++; + if (!(data < end)) { + ERROR_ACCESS("CFF DICT floating-point " + "number"); + return NAN; + } + } + }; + sscanf(nibble_str.c_str(), "%lf", &ret); + break; + case 28: + if (!(data + 3 <= end)) { + ERROR_ACCESS("CFF DICT 3 byte integer number"); + return NAN; + } + ret_int16 = (data[1] << 8) | data[2]; + ret = ret_int16; + data += 3; + break; + case 29: + if (!(data + 5 <= end)) { + ERROR_ACCESS("CFF DICT 5 byte integer number"); + return NAN; + } + ret_int32 = + (data[1] << 24) | + (data[2] << 16) | + (data[3] << 8) | + data[4]; + ret = ret_int32; + data += 5; + break; + default: + if (data[0] >= 32 && data[0] <= 246) { + ret = data[0] - 139; + data++; + } + else if (data[0] >= 247 && data[0] <= 250) { + if (!(data + 2 <= end)) { + ERROR_ACCESS("CFF DICT 2 byte positive integer " + "number"); + return NAN; + } + ret = (data[0] - 247) * 256 + + data[1] + 108; + data += 2; + } + else if (data[0] >= 251 && data[0] <= 254) { + if (!(data + 2 <= end)) { + ERROR_ACCESS("CFF DICT 2 byte negative integer " + "number"); + return NAN; + } + ret = -(data[0] - 251) * 256 - + data[1] - 108; + data += 2; + } + else { + fprintf(stderr, "%s:%d: Illegal CFF DICT number, " + "b0 = %d, 0x%02x\n", + __FILE__, __LINE__, data[0], data[0]); + } + } + + return ret; + } + + double font_embed_t::search_cff_top_dict_number( + const std::vector &top_dict, + uint8_t operator_value_1, uint8_t operator_value_2) + { + if (!(operator_value_1 <= 21)) { + fprintf(stderr, "%s:%d: Illegal CFF operator %d, " + "0x%02x requested\n", __FILE__, __LINE__, + operator_value_1, operator_value_1); + return NAN; + } + + double last = NAN; + + for (std::vector::const_iterator iterator = + top_dict.begin(); + iterator != top_dict.end();) { + if (operator_value_1 == 12 ? + iterator[0] == 12 && iterator[1] == operator_value_2 : + iterator[0] == operator_value_1) { + return last; + } + else if (iterator[0] <= 21) { + // Some other operators + last = NAN; + iterator += iterator[0] == 12 ? 2 : 1; + } + else if ((iterator[0] >= 28 && iterator[0] <= 30) || + (iterator[0] >= 32 && iterator[0] <= 254)) { + last = parse_cff_dict_number(iterator, top_dict.end()); + } + else { + fprintf(stderr, "%s:%d: error: unexpected byte %d, " + "0x%02x in CFF DICT (attempt to skip...)\n", + __FILE__, __LINE__, iterator[0], iterator[0]); + iterator++; + } + } + + return NAN; + } + + std::string font_embed_t::cff_sid_to_string( + uint16_t sid, + const std::vector > &string_index) + { +#include "table/cffstdstr.h" + if (!(sid < ncff_standard_string + string_index.size())) { + ERROR_ACCESS("CFF SID"); + } + + return sid < ncff_standard_string ? + cff_standard_string[sid] : + sid - ncff_standard_string < string_index.size() ? + std::string( + string_index[sid - ncff_standard_string].begin(), + string_index[sid - ncff_standard_string].end()) : + ""; + } + + std::vector font_embed_t::parse_cff_charset( + const std::vector &data, + uint32_t charset_offset, uint32_t nglyph, + const std::vector > &string_index) + { + if (!(charset_offset < data.size())) { + ERROR_ACCESS("CFF Charset"); + } + + const uint8_t format = data[charset_offset]; + std::vector charset; + + switch (format) { + case 0: + charset.push_back(".notdef"); + for (size_t i = 0; i < nglyph - 1; i++) { + uint16_t sid; + + if (!(charset_offset + 2 * i + 3 <= data.size())) { + ERROR_ACCESS("CFF Charset"); + } + memcpy(&sid, &data[charset_offset + 2 * i + 1], 2); +#ifdef LITTLE_ENDIAN + sid = bswap_16(sid); +#endif // LITTLE_ENDIAN + charset.push_back(cff_sid_to_string(sid, string_index)); + } + break; + default: + fprintf(stderr, "%s:%d: error: unsupported Charset " + "format %d\n", __FILE__, __LINE__, format); + break; + } + + return charset; + } + + void font_embed_t::parse_cff( + std::vector &charset, + const std::vector &font_data, + uint32_t cff_offset) + { + struct cff_header_s { + uint8_t major; + uint8_t minor; + uint8_t hdr_size; + uint8_t off_size; + } cff_header; + + uint32_t current_offset = cff_offset; + + if (!(current_offset + sizeof(struct cff_header_s) <= + font_data.size())) { + ERROR_ACCESS("CFF header"); + } + + memcpy(&cff_header, &font_data[current_offset], + sizeof(struct cff_header_s)); + current_offset += sizeof(struct cff_header_s); + + const std::vector > cff_name_index = + parse_cff_index(font_data, current_offset); + const std::vector > cff_top_dict_index = + parse_cff_index(font_data, current_offset); + + if (cff_top_dict_index.size() != 1) { + fprintf(stderr, "%s:%d: error: CFF FontSet is not " + "supported\n", __FILE__, __LINE__); + return; + } + + const uint32_t charset_offset = cff_offset + + search_cff_top_dict_number(cff_top_dict_index[0], 15); + uint32_t charstrings_offset = cff_offset + + search_cff_top_dict_number(cff_top_dict_index[0], 17); + uint32_t cff_nglyph = 0; + + parse_cff_index(font_data, charstrings_offset, &cff_nglyph); + + const std::vector > string_index = + parse_cff_index(font_data, current_offset); + + charset = parse_cff_charset(font_data, charset_offset, + cff_nglyph, string_index); + } + + bool font_embed_t::parse_otf_cff_header( + std::string &font_name, unsigned short &cid_encoding_id, + uint32_t font_descriptor_flags, double *font_bbox, + double &italic_angle, double &ascent, double &descent, + double &leading, double &cap_height, double &x_height, + double &stem_v,double &avg_width, + std::map &cid_map, + std::vector &charset, + std::vector &advance_width, + unsigned int &cff_offset, unsigned int &cff_length, + const std::vector &font_data) + { + // OpenType file structure + struct otf_offset_table_s { + char sfnt_version[4]; + uint16_t num_tables; + uint16_t search_range; + uint16_t entry_selector; + uint16_t range_shift; + } offset_table; + + if (!(sizeof(struct otf_offset_table_s) <= + font_data.size())) { + ERROR_ACCESS("OTF offset table"); + } + memcpy(&offset_table, &font_data[0], + sizeof(struct otf_offset_table_s)); + if (strncmp(offset_table.sfnt_version, "OTTO", 4) != 0) { + // Not a OpenType CFF/Type 2 font + return false; + } +#ifdef LITTLE_ENDIAN + offset_table.num_tables = bswap_16(offset_table.num_tables); +#endif // LITTLE_ENDIAN + + std::map > table = + parse_ttf_offset_table( + font_data, sizeof(struct otf_offset_table_s), + offset_table.num_tables); + + const uint32_t cmap_offset = table["cmap"].first; + const uint32_t head_offset = table["head"].first; + const uint32_t hhea_offset = table["hhea"].first; + const uint32_t hmtx_offset = table["hmtx"].first; + const uint32_t maxp_offset = table["maxp"].first; + const uint32_t name_offset = table["name"].first; + const uint32_t os_2_offset = table["OS/2"].first; + const uint32_t post_offset = table["post"].first; + + cff_offset = table["CFF "].first; + cff_length = table["CFF "].second; + + if (!(cmap_offset != 0 && head_offset != 0 && + hhea_offset != 0 && hmtx_offset != 0 && + maxp_offset != 0 && name_offset != 0 && + os_2_offset != 0 && cff_offset != 0)) { + fprintf(stderr, "%s:%d: error: OTF CFF font is " + "missing required tables\n", __FILE__, __LINE__); + return false; + } + + parse_ttf_name(font_name, cid_encoding_id, font_data, + name_offset); + + uint16_t units_per_em; + + parse_ttf_head(font_bbox, units_per_em, font_data, + head_offset); + font_descriptor_flags = 0; + parse_ttf_post(charset, italic_angle, font_descriptor_flags, + font_data, post_offset); + parse_ttf_cmap(cid_map, font_data, cmap_offset); + parse_ttf_os_2(font_descriptor_flags, ascent, descent, + leading, cap_height, x_height, stem_v, + avg_width, font_data, os_2_offset, + units_per_em); + + const uint16_t num_glyphs = + parse_ttf_maxp(font_data, maxp_offset); + advance_width = + parse_ttf_hmtx(font_data, hmtx_offset, + parse_ttf_hhea(font_data, hhea_offset)); + + if (advance_width.empty()) { + fprintf(stderr, "%s:%d: error: hMetrics in hmtx is " + "empty\n", __FILE__, __LINE__); + return false; + } + advance_width.resize(num_glyphs, advance_width.back()); + + if (charset.empty()) { + parse_cff(charset, font_data, cff_offset); + } + + cid_map.erase(L'\uffff'); + + return true; + } + + bool font_embed_t::parse_otf_cff_header( + std::string &font_name, unsigned short &cid_encoding_id, + unsigned int &cff_offset, unsigned int &cff_length, + const std::vector &font_data) + { + uint32_t font_descriptor_flags = 0; + double font_bbox[4]; + double italic_angle; + double ascent; + double descent; + double leading; + double cap_height; + double x_height; + double stem_v; + double avg_width; + std::map cid_map; + std::vector charset; + std::vector advance_width; + + return parse_otf_cff_header( + font_name, cid_encoding_id, font_descriptor_flags, + font_bbox, italic_angle, ascent, descent, leading, + cap_height, x_height, stem_v, avg_width, cid_map, + charset, advance_width, cff_offset, cff_length, + font_data); + } + + std::vector + font_embed_t::charset_from_adobe_glyph_list( + std::map &cid_map) + { + // Regenerate cid_map from the Adobe glyph list + + std::vector charset; + + if (cid_map.empty()) { + return std::vector(1, ".notdef"); + } + charset.resize(cid_map.size()); + for (std::map::const_iterator iterator = + cid_map.begin(); + iterator != cid_map.end(); iterator++) { + if (iterator->second < charset.size()) { +#include "table/adobeglyphlist.h" + + const wchar_t *lower = std::lower_bound( + adobe_glyph_ucs, adobe_glyph_ucs + nadobe_glyph, + iterator->first); + // The longest Adobe glyph name is 20 characters long + // (0x03b0 = upsilondieresistonos) + char buf[21]; + + if (iterator->first == L'\uffff') { + strncpy(buf, ".notdef", 8); + } + else if (lower < adobe_glyph_ucs + nadobe_glyph && + *lower == iterator->first) { + const size_t index = + lower - adobe_glyph_ucs; + + snprintf(buf, 21, "%s", adobe_glyph_name[index]); + } + else { + snprintf(buf, 21, "uni%04X", iterator->first); + } + charset[iterator->second] = buf; + } + } + + return charset; + } + + bool font_embed_t::parse_ttf_header( + std::string &font_name, unsigned short &cid_encoding_id, + uint32_t font_descriptor_flags, double *font_bbox, + double &italic_angle, double &ascent, double &descent, + double &leading, double &cap_height, double &x_height, + double &stem_v,double &avg_width, + std::map &cid_map, + std::vector &charset, + std::vector &advance_width, + const std::vector &font_data) + { + cid_map.clear(); + charset.clear(); + + struct ttf_offset_table_s { + fixed_t sfnt_version; + uint16_t num_tables; + uint16_t search_range; + uint16_t entry_selector; + uint16_t range_shift; + } offset_table; + + if (!(sizeof(struct ttf_offset_table_s) <= + font_data.size())) { + ERROR_ACCESS("TTF offset table"); + } + memcpy(&offset_table, &font_data[0], + sizeof(struct ttf_offset_table_s)); +#ifdef LITTLE_ENDIAN + offset_table.sfnt_version = + bswap_32(offset_table.sfnt_version); + offset_table.num_tables = bswap_16(offset_table.num_tables); +#endif // LITTLE_ENDIAN + if (offset_table.sfnt_version != 0x00010000) { + return false; + } + + std::map > table = + parse_ttf_offset_table( + font_data, sizeof(struct ttf_offset_table_s), + offset_table.num_tables); + + const uint32_t cmap_offset = table["cmap"].first; + const uint32_t head_offset = table["head"].first; + const uint32_t hhea_offset = table["hhea"].first; + const uint32_t hmtx_offset = table["hmtx"].first; + const uint32_t maxp_offset = table["maxp"].first; + const uint32_t name_offset = table["name"].first; + const uint32_t os_2_offset = table["OS/2"].first; + const uint32_t post_offset = table["post"].first; + + if (!(cmap_offset != 0 && head_offset != 0 && + hhea_offset != 0 && hmtx_offset != 0 && + maxp_offset != 0 && name_offset != 0 && + os_2_offset != 0)) { + fprintf(stderr, "%s:%d: error: TTF font is missing " + "required tables\n", __FILE__, __LINE__); + return false; + } + + parse_ttf_name(font_name, cid_encoding_id, font_data, + name_offset); + + uint16_t units_per_em; + + parse_ttf_head(font_bbox, units_per_em, font_data, + head_offset); + font_descriptor_flags = 0; + parse_ttf_post(charset, italic_angle, font_descriptor_flags, + font_data, post_offset); + parse_ttf_cmap(cid_map, font_data, cmap_offset); + parse_ttf_os_2(font_descriptor_flags, ascent, descent, + leading, cap_height, x_height, stem_v, + avg_width, font_data, os_2_offset, + units_per_em); + + const uint16_t num_glyphs = + parse_ttf_maxp(font_data, maxp_offset); + advance_width = + parse_ttf_hmtx(font_data, hmtx_offset, + parse_ttf_hhea(font_data, hhea_offset)); + + if (advance_width.empty()) { + fprintf(stderr, "%s:%d: error: hMetrics in hmtx is " + "empty\n", __FILE__, __LINE__); + return false; + } + advance_width.resize(num_glyphs, advance_width.back()); + + if (charset.empty()) { + charset = charset_from_adobe_glyph_list(cid_map); + } + + cid_map.erase(L'\uffff'); + + return true; + } + + bool font_embed_t::parse_ttf_header( + std::string &font_name, double *font_bbox, + std::map &cid_map, + std::vector &charset, + const std::vector &font_data) + { + uint16_t cid_encoding_id; + uint32_t font_descriptor_flags = 0; + double italic_angle; + double ascent; + double descent; + double leading; + double cap_height; + double x_height; + double stem_v; + double avg_width; + std::vector advance_width; + + return parse_ttf_header( + font_name, cid_encoding_id, font_descriptor_flags, + font_bbox, italic_angle, ascent, descent, leading, + cap_height, x_height, stem_v, avg_width, cid_map, + charset, advance_width, font_data); + } + +} diff --git a/builtins/libmathtext/fontembedpdf.cc b/builtins/libmathtext/fontembedpdf.cc new file mode 100644 index 0000000000000..2878c4c7c3250 --- /dev/null +++ b/builtins/libmathtext/fontembedpdf.cc @@ -0,0 +1,534 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2016 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include + +// References: +// +// Adobe Systems, Inc., PostScript language Document Structuring +// Convention specification (Adobe Systems, Inc., San Jose, CA, 1992), +// version 3.0, section 5.1. +// +// Adobe Systems, Inc., PostScript language reference manual +// (Addison-Wesley, Reading, MA, 1999), 3rd edition, section 5.8.1. +// +// Adobe Systems, Inc., Adobe Type 1 Font Format (Addison-Wesley, +// Reading, MA, 1993), version 1.1 +// +// Adobe Systems, Inc., The Compact Font Format specification, Adobe +// Technical Note 5176 (Adobe, Mountain View, CA, 2003), 4 December +// 2003 document +// +// Adobe Systems, Inc., Type 2 charstring format, Adobe Technical Note +// 5177 (Adobe, San Jose, CA, 2000), 16 March 2000 document + +namespace mathtext { + + uint16_t font_embed_pdf_t::utf16_high_surrogate(uint32_t code) + { + return ((code - 0x10000) >> 10) + 0xd800; + } + + uint16_t font_embed_pdf_t::utf16_low_surrogate(uint32_t code) + { + return ((code - 0x10000) & ((1U << 10) - 1U)) + 0xdc00; + } + + std::string font_embed_pdf_t::utf16be_str(uint32_t code) + { + char buffer[9]; + + if (code < 0x10000) { + snprintf(buffer, 5, "%04x", code); + } + else if (code < 0x110000) { + snprintf(buffer, 9, "%04x%04x", + utf16_high_surrogate(code), + utf16_low_surrogate(code)); + } + else { + snprintf(buffer, 5, "????"); + } + buffer[8] = '\0'; + + return buffer; + } + + std::string font_embed_pdf_t::uint16_str(uint16_t cid) + { + char buffer[6]; + + snprintf(buffer, 6, "%u", cid); + buffer[5] = '\0'; + + return buffer; + } + + void font_embed_pdf_t::add_cidfont_w_token( + std::string &s, const std::string &t) + { + while (!s.empty() && + (s.rbegin()[0] == ' ' || s.rbegin()[0] == '\n')) { + s.resize(s.size() - 1); + } + + if (!((s.rbegin()[0] == '[' && + t.begin()[0] >= '0' && s.begin()[0] <= '9') || + (s.rbegin()[0] >= '0' && s.rbegin()[0] <= '9' && + t.begin()[0] == ']'))) { + s += " "; + } + s += t; + + static const size_t pdf_line_width = 79; + const size_t last_break = s.rfind('\n'); + + if (last_break != std::string::npos && + s.size() - last_break - 1 <= pdf_line_width) { + return; + } + + const size_t new_break = + s.rfind(' ', + last_break == std::string::npos ? s.size() : + last_break + pdf_line_width + 1); + + if (new_break != std::string::npos) { + s[new_break] = '\n'; + } + } + + std::string font_embed_pdf_t::cidfont_w( + const std::vector &advance_width) + { + // Format 1 and 2 are the two formats on PDF 1.4 Reference, p. + // 340: + // + // c [w1 w2 ... wn] <-- "format 1" + // cfirst clast w <-- "format 2" + bool in_format_1 = false; + std::string str; + + str = "/W ["; + for (size_t cid = 1, cid_next = 2; + cid < advance_width.size(); cid = cid_next) { + while (cid_next < advance_width.size() && + advance_width[cid_next] == advance_width[cid]) { + cid_next++; + } + + if (cid_next == cid + 1) { + if (!in_format_1) { + add_cidfont_w_token(str, uint16_str(cid)); + add_cidfont_w_token(str, "["); + } + in_format_1 = true; + } + else { + if (in_format_1) { + add_cidfont_w_token(str, "]"); + } + add_cidfont_w_token(str, uint16_str(cid)); + add_cidfont_w_token(str, uint16_str(cid_next - 1)); + in_format_1 = false; + } + add_cidfont_w_token(str, uint16_str(advance_width[cid])); + } + if (in_format_1) { + add_cidfont_w_token(str, "]"); + } + add_cidfont_w_token(str, "]\n"); + + return str; + } + + std::map + font_embed_pdf_t::font_embed_cid( + std::string &font_name, + const std::vector &font_data, + unsigned int type) + { + unsigned short cid_encoding_id; + uint32_t font_descriptor_flags = 0; + double font_bbox[4]; + double italic_angle; + double ascent; + double descent; + double leading; + double cap_height; + double x_height; + double stem_v; + double avg_width; + std::map cid_map; + std::vector charset; + std::vector advance_width; + unsigned int cff_offset = 0; + unsigned int cff_length = 0; + + std::map pdf_object; + + if (!(type == 0 ? + parse_otf_cff_header( + font_name, cid_encoding_id, font_descriptor_flags, + font_bbox, italic_angle, ascent, descent, leading, + cap_height, x_height, stem_v, avg_width, cid_map, + charset, advance_width, cff_offset, cff_length, + font_data) : + parse_ttf_header( + font_name, cid_encoding_id, font_descriptor_flags, + font_bbox, italic_angle, ascent, descent, leading, + cap_height, x_height, stem_v, avg_width, cid_map, + charset, advance_width, font_data))) { + return pdf_object; + } + + // Layout of a embedded CID Type 0/2 font + // + // /Font (/Subtype /Type0/2) + // | /Encoding + // +-- /CMap + // | /DescendantFonts + // +-- /Font (/Subtype /CIDFontType0/2) + // | /FontDescriptor + // +-- /FontDescriptor + // | /FontFile3/2 + // +-- stream (plain or /SubType /CIDFontType0C) + + const uint16_t max_width = + *std::max_element(advance_width.begin(), + advance_width.end()); + + std::string font_file32 = + "<<\n"; + + if (type == 0) { + font_file32 += "/Subtype /CIDFontType0C\n"; + } + + char buffer[4096]; + + snprintf(buffer, 4096, + "/Length %u\n" + ">>\n" + "stream\n", + type == 0 ? cff_length : + static_cast(font_data.size())); + font_file32 += buffer; + + if (type == 0) { + font_file32.insert( + font_file32.end(), font_data.begin() + cff_offset, + font_data.begin() + cff_offset + cff_length); + } + else { + font_file32.insert( + font_file32.end(), font_data.begin(), + font_data.end()); + } + font_file32 += "\nendstream\n"; + + pdf_object["/FontFile32"] = font_file32; + + std::string font_descriptor = + "<<\n" + "/Type /FontDescriptor\n"; + + snprintf(buffer, 4096, + "/FontName /%s\n" + "/Flags %u\n" + "/FontBBox [%g %g %g %g]\n" + "/ItalicAngle %g\n" + "/Ascent %g\n" + "/Descent %g\n" + "/Leading %g\n" + "/CapHeight %g\n" + "/XHeight %g\n" + "/StemV %g\n" + "/StemH %g\n" + "/AvgWidth %g\n" + "/MaxWidth %hu\n", + font_name.c_str(), font_descriptor_flags, + font_bbox[0], font_bbox[1], font_bbox[2], + font_bbox[3], italic_angle, ascent, descent, + leading, cap_height, x_height, stem_v, 0.0, + avg_width, max_width); + font_descriptor += buffer; + font_descriptor += "/FontFile" + + std::string(type == 0 ? "3" : "2") + " %u %u R\n"; + font_descriptor += ">>\n"; + + pdf_object["/FontDescriptor"] = font_descriptor; + + const std::string registry = "Adobe"; + const std::string ordering = "Identity"; + const std::string supplement = "0"; + + pdf_object["/CIDFont"] = + "<<\n" + "/Type /Font\n" + "/Subtype /CIDFontType" + + std::string(type == 0 ? "0" : "2") + "\n" + "/BaseFont /" + font_name + "\n" + "/CIDSystemInfo\n" + "<<\n" + "/Registry (" + registry + ")\n" + "/Ordering (" + ordering + ")\n" + "/Supplement " + supplement + "\n" + ">>\n" + "/FontDescriptor %u %u R\n" + + cidfont_w(advance_width) + + ">>\n"; + + const std::string cmap_name = "UniMT-UTF16-H"; + std::string cmap_stream; + + cmap_stream = + "%!PS-Adobe-3.0 Resource-CMap\n" + "%%DocumentNeededResources: ProcSet (CIDInit)\n" + "%%IncludeResource: ProcSet (CIDInit)\n" + "%%BeginResource: CMap (" + cmap_name + ")\n" + "%%Title: (" + cmap_name + " " + registry + " " + + ordering + " " + supplement + ")\n" + "%%Version: 1.000\n" + "%%EndComments\n" + "\n" + "/CIDInit /ProcSet findresource begin\n" + "\n" + "12 dict begin\n" + "\n" + "begincmap\n" + "\n" + "/CIDSystemInfo 3 dict dup begin\n" + " /Registry (" + registry + ") def\n" + " /Ordering (" + ordering + ") def\n" + " /Supplement " + supplement + " def\n" + "end def\n" + "\n" + "/CMapName /" + cmap_name + " def\n" + "/CMapVersion 1.000 def\n" + "/CMapType 1 def\n" + "\n" + "/XUID [1000000 10] def\n" + "\n" + "/WMode 0 def\n" + "\n"; + + // UTF-16BE + + cmap_stream += + "3 begincodespacerange\n" + " <0000> \n" + " \n" + " \n" + "endcodespacerange\n" + "\n" + "1 beginnotdefrange\n" + "<0000> <001f> 1\n" + "endnotdefrange\n" + "\n"; + + // Split into begin/endcidchar and begin/endcidrange + + std::vector cid_char; + std::vector cid_range; + + { + std::map::const_iterator iterator = + cid_map.begin(); + const struct cid_range_s r0 = { + static_cast(iterator->first), + static_cast(iterator->first), + iterator->second + }; + + cid_range.push_back(r0); + iterator++; + for (; iterator != cid_map.end(); iterator++) { + const unsigned int code = iterator->first; + if (code == cid_range.back().code_last + 1U && + iterator->second == + iterator->first - cid_range.back().code_first + + cid_range.back().cid && + // Split around UTF-16BE byte overflow (<..ff> to + // <..00>) + (code & ((1U << 8) - 1U)) != 0U && + (code < 0x10000 ? true : + ((code >> 10) & ((1U << 8) - 1U)) != 0U)) { + cid_range.back().code_last++; + } + else { + if (cid_range.back().code_first == + cid_range.back().code_last) { + const struct cid_char_s c = { + cid_range.back().code_first, + cid_range.back().cid + }; + + cid_char.push_back(c); + cid_range.pop_back(); + } + + const struct cid_range_s r = { + static_cast(iterator->first), + static_cast(iterator->first), + iterator->second + }; + + cid_range.push_back(r); + } + } + } + if (cid_range.back().code_first == + cid_range.back().code_last) { + const struct cid_char_s c = { + cid_range.back().code_first, + cid_range.back().cid + }; + + cid_char.push_back(c); + cid_range.pop_back(); + } + + for (std::vector::const_iterator + iterator = cid_char.begin(); + iterator != cid_char.end(); iterator++) { + if ((iterator - cid_char.begin()) % 100U == 0U) { + if (iterator != cid_char.begin()) { + cmap_stream += + "endcidchar\n" + "\n"; + } + + const unsigned int chunk = + std::min(100U, static_cast + (cid_char.end() - iterator) / 2); + + snprintf(buffer, 4096, "%u begincidchar\n", + chunk); + cmap_stream += buffer; + } + + cmap_stream += "<" + utf16be_str(iterator->code) + "> " + + uint16_str(iterator->cid) + "\n"; + } + if (!cid_char.empty()) { + cmap_stream += + "endcidchar\n" + "\n"; + } + + for (std::vector::const_iterator + iterator = cid_range.begin(); + iterator != cid_range.end(); iterator++) { + if ((iterator - cid_range.begin()) % 100U == 0U) { + if (iterator != cid_range.begin()) { + cmap_stream += + "endcidrange\n" + "\n"; + } + + const unsigned int chunk = + std::min(100U, static_cast + (cid_range.end() - iterator) / 3); + + snprintf(buffer, 4096, "%u begincidrange\n", + chunk); + cmap_stream += buffer; + } + cmap_stream += "<" + utf16be_str(iterator->code_first) + + "> <" + utf16be_str(iterator->code_last) + "> " + + uint16_str(iterator->cid) + "\n"; + } + if (!cid_range.empty()) { + cmap_stream += + "endcidrange\n" + "\n"; + } + + cmap_stream += + "endcmap\n" + "CMapName currentdict /CMap defineresource pop\n" + "end\n" + "end\n" + "\n" + "%%EndResource\n" + "%%EOF"; + + std::string cmap; + + snprintf(buffer, 4096, + "<<\n" + "/CMapName /%s\n", + cmap_name.c_str()); + cmap = buffer; + cmap += + "/Type /CMap\n" + "/CIDSystemInfo\n" + "<<\n" + "/Registry (" + registry + ")\n" + "/Ordering (" + ordering + ")\n" + "/Supplement " + supplement + "\n" + ">>\n" + "/WMode 0\n"; + pdf_object["/CMap.dict_part"] = cmap; + snprintf(buffer, 4096, + "/Length %u\n" + ">>\n" + "stream\n", + static_cast(cmap_stream.size())); + cmap += buffer; + pdf_object["/CMap.stream"] = cmap_stream; + cmap += cmap_stream; + cmap += "\nendstream\n"; + + pdf_object["/CMap"] = cmap; + + // PDF 1.4 Reference, p. 353, Table 5.17 + + pdf_object["/Font"] = + "<<\n" + "/Type /Font\n" + "/Subtype /Type0\n" + "/BaseFont /" + font_name + "\n" + "/Encoding %u %u R\n" + "/DescendantFonts [%u %u R]\n" + ">>\n"; + + return pdf_object; + } + + std::map + font_embed_pdf_t::font_embed_type_2( + std::string &font_name, + const std::vector &font_data) + { + return font_embed_cid(font_name, font_data, 0); + } + + std::map + font_embed_pdf_t::font_embed_type_42( + std::string &font_name, + const std::vector &font_data) + { + return font_embed_cid(font_name, font_data, 2); + } + +} diff --git a/graf2d/mathtext/src/fontembedps.cxx b/builtins/libmathtext/fontembedps.cc similarity index 91% rename from graf2d/mathtext/src/fontembedps.cxx rename to builtins/libmathtext/fontembedps.cc index de1bfccfb7669..904eed75c5c99 100644 --- a/graf2d/mathtext/src/fontembedps.cxx +++ b/builtins/libmathtext/fontembedps.cc @@ -16,28 +16,41 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA // 02110-1301 USA -#include "../inc/fontembed.h" +#include +#include #include #include -#include -#ifdef WIN32 -#define snprintf _snprintf +#if defined(__APPLE__) +#include +#define bswap_16 OSSwapInt16 +#define bswap_32 OSSwapInt32 +#elif defined(_WIN32) +#define bswap_16(x) _byteswap_ushort(x) +#define bswap_32(x) _byteswap_ulong(x) +#else +#include #endif -// ROOT integration -#include -#ifdef R__BYTESWAP -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1 -#endif // LITTLE_ENDIAN -#else // R__BYTESWAP -#ifdef LITTLE_ENDIAN -#undef LITTLE_ENDIAN -#endif // LITTLE_ENDIAN -#endif // R__BYTESWAP -#include "Byteswap.h" -#define bswap_16(x) Rbswap_16((x)) -#define bswap_32(x) Rbswap_32((x)) +#ifdef _WIN32 +// https://stackoverflow.com/questions/52988769/writing-own-memmem-for-windows +void *memmem(const void *haystack, size_t haystack_len, + const void * const needle, const size_t needle_len) +{ + if (haystack == nullptr) return nullptr; // or assert(haystack != nullptr); + if (haystack_len == 0) return nullptr; + if (needle == nullptr) return nullptr; // or assert(needle != nullptr); + if (needle_len == 0) return nullptr; + + for (const char *h = (const char *)haystack; + haystack_len >= needle_len; + ++h, --haystack_len) { + if (!memcmp(h, needle, needle_len)) { + return (void *)h; + } + } + return NULL; +} +#endif // References: // @@ -254,7 +267,6 @@ namespace mathtext { segment_header.length = bswap_32(segment_header.length); #endif // LITTLE_ENDIAN - const char *match = "/FontName"; char *buffer = new char[segment_header.length]; char *fname; @@ -276,8 +288,9 @@ namespace mathtext { buffer[segment_header.length - 1] = '\n'; } ret.append(buffer, segment_header.length); - fname = std::search(buffer, buffer+segment_header.length, - match, match+9); + + fname = (char*)memmem(buffer, segment_header.length, + "/FontName", 9); if (fname) { fname += 9; while (fname < buffer + segment_header.length && @@ -410,7 +423,7 @@ namespace mathtext { unsigned int glyph_index = cid_map[code_point]; if (char_strings[glyph_index] != ".notdef" && - !char_strings[glyph_index].empty()) { + char_strings[glyph_index] != "") { snprintf(linebuf, BUFSIZ, "dup %u /%s put\n", code_point, char_strings[glyph_index].c_str()); @@ -443,8 +456,9 @@ namespace mathtext { unsigned int char_strings_count = 0; - for (std::vector::const_iterator iterator = char_strings.begin(); iterator < char_strings.end(); - ++iterator) { + for (std::vector::const_iterator iterator = + char_strings.begin(); + iterator < char_strings.end(); iterator++) { if (!iterator->empty()) { char_strings_count++; } diff --git a/builtins/libmathtext/geometry.cc b/builtins/libmathtext/geometry.cc new file mode 100644 index 0000000000000..b040fa9604486 --- /dev/null +++ b/builtins/libmathtext/geometry.cc @@ -0,0 +1,80 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include + +namespace mathtext { + + point_t::operator std::string(void) const + { + std::stringstream stream; + + stream << '(' << _x[0] << ", " << _x[1] << ')'; + + return stream.str(); + } + + const affine_transform_t affine_transform_t::identity = + affine_transform_t(1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F); + const affine_transform_t affine_transform_t::flip_y = + affine_transform_t(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F); + + affine_transform_t affine_transform_t:: + translate(const float tx, const float ty) + { + return affine_transform_t(1.0F, 0.0F, 0.0F, 1.0F, tx, ty); + } + + affine_transform_t affine_transform_t:: + scale(const float sx, const float sy) + { + return affine_transform_t(sx, 0.0F, 0.0F, sy, 0.0F, 0.0F); + } + + affine_transform_t affine_transform_t::rotate(const float angle) + { + float sin_angle; + float cos_angle; + +#if defined(__APPLE__) + __sincosf(angle, &sin_angle, &cos_angle); +#elif defined(_WIN32) + sin_angle = std::sin(angle); + cos_angle = std::cos(angle); +#else + sincosf(angle, &sin_angle, &cos_angle); +#endif + + return affine_transform_t(cos_angle, sin_angle, + -sin_angle, cos_angle, 0, 0); + } + + affine_transform_t::operator std::string(void) const + { + std::stringstream stream; + + stream << '(' << _a[0] << ", " << _a[1] << ", 0)" << std::endl; + stream << '(' << _a[2] << ", " << _a[3] << ", 0)" << std::endl; + stream << '(' << _a[4] << ", " << _a[5] << ", 1)"; + + return stream.str(); + } + +} diff --git a/builtins/libmathtext/mathrender.cc b/builtins/libmathtext/mathrender.cc new file mode 100644 index 0000000000000..50980c7ebc19b --- /dev/null +++ b/builtins/libmathtext/mathrender.cc @@ -0,0 +1,577 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + +#ifdef __INTEL_COMPILER +#pragma warning(push) +#pragma warning(disable: 869) +#endif // __INTEL_COMPILER + + bool math_text_renderer_t::is_cyrillic(const wchar_t c) + { + return c >= L'\u0400' && c <= L'\u052f'; + } + + bool math_text_renderer_t::is_cjk(const wchar_t c) + { + return + // Acceleration when most characters are below the CJK + // Radicals Supplement + c >= L'\u2e80' && + (// CJK Radicals Supplement ... Yi Radicals + (/* c >= L'\u2e80' && */ c <= L'\ua4cf') || + // Modifier Tone Letters + (c >= L'\ua700' && c <= L'\ua71f') || + // Hangul Syllables + (c >= L'\uac00' && c <= L'\ud7af') || + // CJK Compatibility Ideographs + (c >= L'\uf900' && c <= L'\ufaff') || + // Vertical Forms + (c >= L'\ufe10' && c <= L'\ufe1f') || + // CJK Compatibility Forms + (c >= L'\ufe30' && c <= L'\ufe4f') || + // Halfwidth and Fullwidth Forms + (c >= L'\uff00' && c <= L'\uffef') || + // CJK Unified Ideographs, Extension B + (c >= L'\U00020000' && c <= L'\U0002a6df') || + // CJK Unified Ideographs, Extension C + (c >= L'\U0002a700' && c <= L'\U0002b73f') || + // CJK Compatibility Ideographs + (c >= L'\U0002f800' && c <= L'\U0002fa1f')); + } + +#if 0 + bool math_text_renderer_t::is_wgl_4(const wchar_t c) + { + return true; + } +#endif + + // @see http://www.w3.org/International/questions/qa-scripts + // @see http://www.unicode.org/reports/tr9/tr9-21.html + bool math_text_renderer_t::is_right_to_left(const wchar_t c) + { + return + (// Hebrew ... N'Ko + (c >= L'\u0590' && c <= L'\u07ff') || + // Tifinagh + (c >= L'\u2d30' && c <= L'\u2d7f') || + // Hebrew Presentation Forms ... Arabic Presentation + // Forms A + (c >= L'\ufb1d' && c <= L'\ufdff') || + // Arabic Presentation Forms B + (c >= L'\ufb1d' && c <= L'\ufb4f')); + } + +#if 0 + bool math_text_renderer_t::is_cjk_punctuation_open(const wchar_t c) + { + return false; + } + + bool math_text_renderer_t::is_cjk_punctuation_closed(const wchar_t c) + { + return false; + } +#endif + + bounding_box_t math_text_renderer_t:: + math_bounding_box(const math_text_t::box_t &box, + const unsigned int style) + { + set_font_size(style_size(style), FAMILY_REGULAR); + + const bounding_box_t box_bounding_box = + bounding_box(box._string, FAMILY_REGULAR); + + reset_font_size(FAMILY_REGULAR); + + return box_bounding_box; + } + + void math_text_renderer_t:: + math_text(const point_t origin, + const math_text_t::box_t &box, + const unsigned int style, + const bool render_structure) + { + if (render_structure) { + // Nothing + } + set_font_size(style_size(style), FAMILY_REGULAR); + text_raw(origin[0], origin[1], box._string, FAMILY_REGULAR); + reset_font_size(FAMILY_REGULAR); + } +#ifdef __INTEL_COMPILER +#pragma warning(pop) +#endif // __INTEL_COMPILER + + bounding_box_t math_text_renderer_t:: + math_bounding_box(const wchar_t &glyph, + const unsigned int family, const float size) + { + set_font_size(size, family); + + const std::wstring string = std::wstring(1, glyph); + const bounding_box_t math_symbol_bounding_box = + bounding_box(string, family); + + reset_font_size(family); + + return math_symbol_bounding_box; + } + + void math_text_renderer_t:: + math_text(const point_t origin, const wchar_t &glyph, + const unsigned int family, const float size, + const bool render_structure) + { + set_font_size(size, family); + + const std::wstring string = std::wstring(1, glyph); + + if (render_structure) { + text_with_bounding_box(origin[0], origin[1], string, + family); + } + else { + text_raw(origin[0], origin[1], string, family); + } + reset_font_size(family); + } + + bounding_box_t math_text_renderer_t:: + math_bounding_box(const math_text_t::math_symbol_t &math_symbol, + const unsigned int style) + { + const unsigned int family = math_family(math_symbol); + const float size = style_size(style); + + return math_bounding_box(math_symbol._glyph, family, size); + } + + void math_text_renderer_t:: + math_text(const point_t origin, + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, + const bool render_structure) + { + const unsigned int family = math_family(math_symbol); + const float size = style_size(style); + + math_text(origin, math_symbol._glyph, family, size, + render_structure); + } + + bounding_box_t math_text_renderer_t:: + math_bounding_box(const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height) + { + std::vector token = + math_tokenize(math_symbol, style, height); + + if (token.empty()) + return bounding_box_t(0, 0, 0, 0, 0, 0); + + std::vector::const_iterator iterator = + token.begin(); + bounding_box_t ret = iterator->_offset + + iterator->_bounding_box; + + for (; iterator != token.end(); iterator++) + ret = ret.merge(iterator->_offset + + iterator->_bounding_box); + + return ret; + } + + void math_text_renderer_t:: + math_text(const point_t origin, + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height, + const bool render_structure) + { + std::vector token = + math_tokenize(math_symbol, style, height); + + for (std::vector::const_iterator iterator = + token.begin(); + iterator != token.end(); iterator++) + math_text(origin + + transform_pixel_to_logical().linear() * + iterator->_offset, + iterator->_extensible._glyph, + iterator->_extensible._family, + iterator->_extensible._size, render_structure); + } + + ///////////////////////////////////////////////////////////////// + + // A field can be a math symbol or a math list + bounding_box_t math_text_renderer_t:: + math_bounding_box(const std::vector:: + const_iterator &math_list_begin, + const std::vector:: + const_iterator &math_list_end, + unsigned int style) + { + std::vector token = + math_tokenize(math_list_begin, math_list_end, style); + + if (token.empty()) + return bounding_box_t(0, 0, 0, 0, 0, 0); + + std::vector::const_iterator iterator = + token.begin(); + bounding_box_t ret = iterator->_offset + + iterator->_bounding_box; + + for (; iterator != token.end(); iterator++) + ret = ret.merge(iterator->_offset + + iterator->_bounding_box); + + return ret; + } + + void math_text_renderer_t:: + math_text(const point_t origin, + const std::vector:: + const_iterator &math_list_begin, + const std::vector:: + const_iterator &math_list_end, + const unsigned int style, + const bool render_structure) + { + if (render_structure) { + point(origin[0], origin[1]); + rectangle(origin + + math_bounding_box(math_list_begin, + math_list_end, style)); + } + + std::vector::const_iterator + math_list_begin_interior = math_list_begin; + std::vector::const_iterator + math_list_end_interior = math_list_end; + bool delimiter = false; + + if (math_list_begin->_type == + math_text_t::item_t::TYPE_BOUNDARY && + (math_list_end - 1)->_type == + math_text_t::item_t::TYPE_BOUNDARY) { + math_list_begin_interior++; + math_list_end_interior--; + delimiter = true; + } + + std::vector token = + math_tokenize(math_list_begin, math_list_end, style); + std::vector::const_iterator token_iterator = + token.begin(); + + if (delimiter) { + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + math_list_begin->_atom._nucleus._math_symbol, + style, token_iterator->_delimiter_height, + render_structure); + token_iterator++; + } + + static const math_text_t::item_t fraction_item = + math_text_t::item_t::TYPE_GENERALIZED_FRACTION; + const std::vector::const_iterator + fraction_iterator = + std::find(math_list_begin_interior, + math_list_end_interior, fraction_item); + + if (fraction_iterator != math_list_end_interior) { + const float thickness = fraction_iterator->_length * + default_rule_thickness * style_size(style); + + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + fraction_iterator + 1, math_list_end_interior, + token_iterator->_style, + render_structure); + token_iterator++; + if (thickness > 0) { + filled_rectangle( + origin + + transform_pixel_to_logical().linear() * + (token_iterator->_offset + + token_iterator->_bounding_box)); + token_iterator++; + } + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + math_list_begin_interior, fraction_iterator, + token_iterator->_style, + render_structure); + token_iterator++; + } + else + // Incrementally process a math list + for (std::vector::const_iterator + iterator = math_list_begin_interior; + iterator != math_list_end_interior; iterator++) { + switch (iterator->_type) { + case math_text_t::item_t::TYPE_ATOM: + if (render_structure) + rectangle(origin + + transform_pixel_to_logical().linear() * + (token_iterator->_offset + + token_iterator->_bounding_box)); + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + iterator->_atom, + token_iterator->_style, + render_structure); + token_iterator++; + break; + } + // math_text_t::item_t::TYPE_KERN can be ignored + } + + if (delimiter) + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + (math_list_end - 1)-> + _atom._nucleus._math_symbol, + token_iterator->_style, + token_iterator->_delimiter_height, + render_structure); + } + + bounding_box_t math_text_renderer_t:: + math_bounding_box(const math_text_t::field_t &field, + const unsigned int style) + { + switch (field._type) { + case math_text_t::field_t::TYPE_MATH_SYMBOL: + return math_bounding_box(field._math_symbol, style); + break; + case math_text_t::field_t::TYPE_BOX: + return math_bounding_box(field._box, style); + break; + case math_text_t::field_t::TYPE_MATH_LIST: + return math_bounding_box(field._math_list.begin(), + field._math_list.end(), style); + break; + default: + return bounding_box_t(0, 0, 0, 0, 0, 0); + } + } + + void math_text_renderer_t:: + math_text(const point_t origin, + const math_text_t::field_t &field, + const unsigned int style, const bool render_structure) + { + switch (field._type) { + case math_text_t::field_t::TYPE_MATH_SYMBOL: + math_text(origin, field._math_symbol, style, + render_structure); + break; + case math_text_t::field_t::TYPE_BOX: + math_text(origin, field._box, style, render_structure); + break; + case math_text_t::field_t::TYPE_MATH_LIST: + math_text(origin, field._math_list.begin(), + field._math_list.end(), style, + render_structure); + break; + } + } + + // TeX algorithm for (three-way) atoms: + // + // See Knuth, The TeXbook (1986), pp. 445f. + bounding_box_t math_text_renderer_t:: + math_bounding_box(const math_text_t::atom_t &atom, + const unsigned int style) + { + std::vector token = + math_tokenize(atom, style); + + if (token.empty()) + return bounding_box_t(0, 0, 0, 0, 0, 0); + + std::vector::const_iterator iterator = + token.begin(); + bounding_box_t ret = iterator->_offset + + iterator->_bounding_box; + + for (; iterator != token.end(); iterator++) + ret = ret.merge(iterator->_offset + + iterator->_bounding_box); + + return ret; + } + + void math_text_renderer_t:: + math_text(const point_t origin, + const math_text_t::atom_t &atom, + const unsigned int style, + const bool render_structure) + { + const float x = origin[0]; + const float y = origin[1]; + + if (render_structure) { + point(x, y); + rectangle(point_t(x, y) + + math_bounding_box(atom, style)); + } + + std::vector token = + math_tokenize(atom, style); + std::vector::const_iterator token_iterator = + token.begin(); + + bounding_box_t nucleus_bounding_box; + + // Rule 11 + if (atom._type == math_text_t::atom_t::TYPE_RAD) { + if (!atom._index.empty()) { + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._index, token_iterator->_style, + render_structure); + token_iterator++; + } + + const math_text_t::math_symbol_t + symbol_surd("\\surd", style); + + // Surd + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + symbol_surd, token_iterator->_style, + token_iterator->_delimiter_height, + render_structure); + token_iterator++; + // Rule with clearance + filled_rectangle( + origin + transform_pixel_to_logical().linear() * + (token_iterator->_offset + + token_iterator->_bounding_box)); + // Skip the clearance token, too + token_iterator += 2; + } + if (atom._type == math_text_t::atom_t::TYPE_OP && + atom._nucleus._type == + math_text_t::field_t::TYPE_MATH_SYMBOL) + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._nucleus._math_symbol._glyph, + FAMILY_STIX_REGULAR, + style_size(style) * if_else_display(style, + large_operator_display_scale, 1.0F), + render_structure); + else + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._nucleus, token_iterator->_style, + render_structure); + + if (atom._superscript.empty() && atom._subscript.empty()) + return; + + token_iterator++; + + if (atom._superscript.empty()) { + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._subscript, token_iterator->_style, + render_structure); + return; + } + if (atom._subscript.empty()) { + math_text(origin + + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._superscript, token_iterator->_style, + render_structure); + return; + } + math_text(origin + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._superscript, token_iterator->_style, + render_structure); + token_iterator++; + math_text(origin + transform_pixel_to_logical().linear() * + token_iterator->_offset, + atom._subscript, token_iterator->_style, + render_structure); + } + + bounding_box_t math_text_renderer_t:: + bounding_box(const math_text_t &text, const bool display_style) + { + if (!text.well_formed()) + bounding_box(L"*** invalid: " + text.code()); + + const unsigned int initial_style = display_style ? + math_text_t::item_t::STYLE_DISPLAY : + math_text_t::item_t::STYLE_TEXT; + + return math_bounding_box(text._math_list._math_list, + initial_style); + } + + void math_text_renderer_t:: + text(const float x, const float y, const math_text_t &text, + const bool display_style) + { + if (!text.well_formed()) { + text_raw(x, y, L"*** invalid: " + text.code()); + } + + const unsigned int initial_style = display_style ? + math_text_t::item_t::STYLE_DISPLAY : + math_text_t::item_t::STYLE_TEXT; + + if (text._render_structure) { + point(x, y); + rectangle(point_t(x, y) + math_bounding_box( + text._math_list._math_list, initial_style)); + } + math_text(point_t(x, y), text._math_list._math_list, + initial_style, text._render_structure); + } + +} diff --git a/builtins/libmathtext/mathrenderstyle.cc b/builtins/libmathtext/mathrenderstyle.cc new file mode 100644 index 0000000000000..78dbd3177b669 --- /dev/null +++ b/builtins/libmathtext/mathrenderstyle.cc @@ -0,0 +1,481 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + + ///////////////////////////////////////////////////////////////// + + float math_text_renderer_t:: + style_size(const unsigned int style) const + { + // Intel C++ Compiler 10.1 chokes on this if declared static + // const and using -O1: + const float size[math_text_t::item_t::NSTYLE - 1] = { + script_script_ratio, script_script_ratio, + script_ratio, script_ratio, 1.0F, 1.0F, 1.0F, 1.0F + }; + + if (style == math_text_t::item_t::STYLE_UNKNOWN || + style >= math_text_t::item_t::NSTYLE) + return font_size(); + + return size[style - 1] * font_size(); + } + + bool math_text_renderer_t:: + is_display_style(const unsigned int style) const + { + switch (style) { + case math_text_t::item_t::STYLE_DISPLAY: + case math_text_t::item_t::STYLE_DISPLAY_PRIME: + return true; + default: + return false; + } + } + + bool math_text_renderer_t:: + is_script_style(const unsigned int style) const + { + switch (style) { + case math_text_t::item_t::STYLE_SCRIPT: + case math_text_t::item_t::STYLE_SCRIPT_PRIME: + case math_text_t::item_t::STYLE_SCRIPT_SCRIPT: + case math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME: + return true; + default: + return false; + } + } + + unsigned int math_text_renderer_t:: + prime_style(const unsigned int style) const + { + switch (style) { + case math_text_t::item_t::STYLE_DISPLAY: + return math_text_t::item_t::STYLE_DISPLAY_PRIME; + case math_text_t::item_t::STYLE_TEXT: + return math_text_t::item_t::STYLE_TEXT_PRIME; + case math_text_t::item_t::STYLE_SCRIPT: + return math_text_t::item_t::STYLE_SCRIPT_PRIME; + case math_text_t::item_t::STYLE_SCRIPT_SCRIPT: + return math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME; + default: + return style; + } + } + + bool math_text_renderer_t:: + is_prime_style(const unsigned int style) const + { + switch (style) { + case math_text_t::item_t::STYLE_DISPLAY_PRIME: + case math_text_t::item_t::STYLE_TEXT_PRIME: + case math_text_t::item_t::STYLE_SCRIPT_PRIME: + case math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME: + return true; + default: + return false; + } + } + + // Knuth, The TeXbook (1986), p. 441 + + unsigned int math_text_renderer_t:: + next_superscript_style(const unsigned int style) const + { + switch (style) { + case math_text_t::item_t::STYLE_DISPLAY: + case math_text_t::item_t::STYLE_TEXT: + return math_text_t::item_t::STYLE_SCRIPT; + case math_text_t::item_t::STYLE_DISPLAY_PRIME: + case math_text_t::item_t::STYLE_TEXT_PRIME: + return math_text_t::item_t::STYLE_SCRIPT_PRIME; + case math_text_t::item_t::STYLE_SCRIPT: + case math_text_t::item_t::STYLE_SCRIPT_SCRIPT: + return math_text_t::item_t::STYLE_SCRIPT_SCRIPT; + case math_text_t::item_t::STYLE_SCRIPT_PRIME: + case math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME: + return math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME; + default: + return style; + } + } + + unsigned int math_text_renderer_t:: + next_subscript_style(const unsigned int style) const + { + return prime_style(next_superscript_style(style)); + } + + unsigned int math_text_renderer_t:: + next_numerator_style(const unsigned int style) const + { + switch (style) { + case math_text_t::item_t::STYLE_DISPLAY: + return math_text_t::item_t::STYLE_TEXT; + case math_text_t::item_t::STYLE_DISPLAY_PRIME: + return math_text_t::item_t::STYLE_TEXT_PRIME; + default: + return next_superscript_style(style); + } + } + + unsigned int math_text_renderer_t:: + next_denominator_style(const unsigned int style) const + { + return if_else_display( + style, + static_cast( + math_text_t::item_t::STYLE_TEXT_PRIME), + next_subscript_style(style)); + } + + // The most elementary building block is the math symbol + float math_text_renderer_t::x_height(const unsigned int style) + { + const unsigned int family = FAMILY_ITALIC; + const float size = style_size(style); + + set_font_size(size, family); + + bounding_box_t math_symbol_bounding_box = + bounding_box(L"x", family); + + reset_font_size(family); + + return math_symbol_bounding_box.ascent(); + } + + float math_text_renderer_t::quad(const unsigned int style) + const + { + const float size = style_size(style); + + return size; + } + + void math_text_renderer_t:: + post_process_atom_type_initial(unsigned int &atom_type) const + { + // Rule 5, initial atom + if (atom_type == math_text_t::atom_t::TYPE_BIN) + atom_type = math_text_t::atom_t::TYPE_ORD; + } + + void math_text_renderer_t:: + post_process_atom_type_interior(unsigned int & + previous_atom_type, + unsigned int &atom_type) const + { + // Rule 5, interior/final atom + if (atom_type == math_text_t::atom_t::TYPE_BIN) + switch (previous_atom_type) { + case math_text_t::atom_t::TYPE_BIN: + case math_text_t::atom_t::TYPE_OP: + case math_text_t::atom_t::TYPE_REL: + case math_text_t::atom_t::TYPE_OPEN: + case math_text_t::atom_t::TYPE_PUNCT: + atom_type = math_text_t::atom_t::TYPE_ORD; + break; + } + // Rule 6 + else if (previous_atom_type == math_text_t::atom_t::TYPE_BIN) + switch (atom_type) { + case math_text_t::atom_t::TYPE_REL: + case math_text_t::atom_t::TYPE_CLOSE: + case math_text_t::atom_t::TYPE_PUNCT: + previous_atom_type = math_text_t::atom_t::TYPE_ORD; + break; + } + } + + bool math_text_renderer_t:: + valid_accent(bool &vertical_alignment, + const std::vector:: + const_iterator &iterator, + const std::vector:: + const_iterator &math_list_end) + const + { + if (iterator->_atom._type == math_text_t::atom_t::TYPE_ACC) { + std::vector::const_iterator + iterator_next = iterator + 1; + + vertical_alignment = true; + return iterator_next != math_list_end && + iterator_next->_type == + math_text_t::item_t::TYPE_ATOM; + } + else if (iterator->_atom.is_combining_diacritical()) { + std::vector::const_iterator + iterator_next = iterator + 1; + + vertical_alignment = false; + return iterator_next != math_list_end && + iterator_next->_type == + math_text_t::item_t::TYPE_ATOM; + } + else + return false; + } + + float math_text_renderer_t::kerning_mu(const float amount) const + { + // Rule 2 + return amount / 18.0F * font_size(); + } + + float math_text_renderer_t:: + math_spacing(unsigned int left_type, unsigned int right_type, + unsigned int style) const + { + const unsigned int left_type_modified = + left_type <= + static_cast( + math_text_t::atom_t::TYPE_INNER) ? + left_type : + static_cast( + math_text_t::atom_t::TYPE_ORD); + const unsigned int right_type_modified = + right_type <= + static_cast( + math_text_t::atom_t::TYPE_INNER) ? + right_type : + static_cast( + math_text_t::atom_t::TYPE_ORD); + const unsigned int space = math_text_t::atom_t:: + spacing(left_type_modified, right_type_modified, + is_script_style(style)); + float mu_skip; + + switch (space) { + case 1: mu_skip = thin_mu_skip; break; + case 2: mu_skip = med_mu_skip; break; + case 3: mu_skip = thick_mu_skip; break; + default: mu_skip = 0.0F; + } + + return kerning_mu(mu_skip); + } + + unsigned int math_text_renderer_t:: + math_family(const math_text_t::math_symbol_t &math_symbol) const + { + // Use the text font for Latin, Greek, Cyrillic and the minus + // sign, and STIX for everything else. + if (math_symbol._glyph <= L'\u017e' || + (math_symbol._glyph >= L'\u0384' && + math_symbol._glyph <= L'\u03ce') || + (math_symbol._glyph >= L'\u0400' && + math_symbol._glyph <= L'\u052f') || + math_symbol._glyph == L'\u2212') { + return math_symbol._family; + } + else { + switch (math_symbol._family) { + case FAMILY_REGULAR: + return FAMILY_STIX_REGULAR; + case FAMILY_ITALIC: + return FAMILY_STIX_ITALIC; + case FAMILY_BOLD: + return FAMILY_STIX_BOLD; + case FAMILY_BOLD_ITALIC: + return FAMILY_STIX_BOLD_ITALIC; + case FAMILY_STIX_REGULAR: + case FAMILY_STIX_ITALIC: + case FAMILY_STIX_BOLD: + case FAMILY_STIX_BOLD_ITALIC: + case FAMILY_STIX_SIZE_1_REGULAR: + case FAMILY_STIX_SIZE_1_BOLD: + case FAMILY_STIX_SIZE_2_REGULAR: + case FAMILY_STIX_SIZE_2_BOLD: + case FAMILY_STIX_SIZE_3_REGULAR: + case FAMILY_STIX_SIZE_3_BOLD: + case FAMILY_STIX_SIZE_4_REGULAR: + case FAMILY_STIX_SIZE_4_BOLD: + case FAMILY_STIX_SIZE_5_REGULAR: + return math_symbol._family; + default: + return FAMILY_STIX_REGULAR; + } + } + } + + void math_text_renderer_t:: + large_family(unsigned long &nfamily, const unsigned int *&family, + const math_text_t::math_symbol_t &math_symbol) const + { + static const unsigned long nlarge_family = 5; + static const unsigned int + large_family_regular[nlarge_family] = { + FAMILY_STIX_REGULAR, + FAMILY_STIX_SIZE_1_REGULAR, + FAMILY_STIX_SIZE_2_REGULAR, + FAMILY_STIX_SIZE_3_REGULAR, + FAMILY_STIX_SIZE_4_REGULAR, + }; + static const unsigned int + large_family_bold[nlarge_family] = { + FAMILY_STIX_BOLD, + FAMILY_STIX_SIZE_1_BOLD, + FAMILY_STIX_SIZE_2_BOLD, + FAMILY_STIX_SIZE_3_BOLD, + FAMILY_STIX_SIZE_4_BOLD, + }; + + nfamily = nlarge_family; + family = math_symbol.bold() ? + large_family_bold : large_family_regular; + } + + void math_text_renderer_t:: + extensible_glyph(wchar_t glyph[4], unsigned long &nrepeat, + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height) + { + // See Knuth, The METAFONTbook (1986), p. 318 + enum { + GLYPH_TOP = 0, + GLYPH_MIDDLE, + GLYPH_BOTTOM, + GLYPH_REPEATABLE, + NGLYPH + }; + + switch (math_symbol._glyph) { + case L'(': + glyph[GLYPH_TOP] = L'\u239b'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u239d'; + glyph[GLYPH_REPEATABLE] = L'\u239c'; + break; + case L')': + glyph[GLYPH_TOP] = L'\u239e'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u23a0'; + glyph[GLYPH_REPEATABLE] = L'\u239f'; + break; + case L'[': + glyph[GLYPH_TOP] = L'\u23a1'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u23a3'; + glyph[GLYPH_REPEATABLE] = L'\u23a2'; + break; + case L']': + glyph[GLYPH_TOP] = L'\u23a4'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u23a6'; + glyph[GLYPH_REPEATABLE] = L'\u23a5'; + break; + case L'{': + glyph[GLYPH_TOP] = L'\u23a7'; + glyph[GLYPH_MIDDLE] = L'\u23a8'; + glyph[GLYPH_BOTTOM] = L'\u23a9'; + glyph[GLYPH_REPEATABLE] = L'\u23aa'; + break; + case L'|': + glyph[GLYPH_TOP] = math_symbol._glyph; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = math_symbol._glyph; + glyph[GLYPH_REPEATABLE] = math_symbol._glyph; + break; + case L'}': + glyph[GLYPH_TOP] = L'\u23ab'; + glyph[GLYPH_MIDDLE] = L'\u23ac'; + glyph[GLYPH_BOTTOM] = L'\u23ad'; + glyph[GLYPH_REPEATABLE] = L'\u23aa'; + break; +#if 0 + // FIXME: \lmoustache, \rmoustache, \radical require + // horizontal offsets + case L'\u211a': // \lmoustache + glyph[GLYPH_TOP] = L'\0'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u23b7'; + glyph[GLYPH_REPEATABLE] = L'\u23b9'; + break; + case L'\u23b0': // \rmoustache + glyph[GLYPH_TOP] = L'\u239b'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u23a0'; + glyph[GLYPH_REPEATABLE] = L'\u239c'; + break; + case L'\u23b1': // \radical + glyph[GLYPH_TOP] = L'\u239e'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\u239d'; + glyph[GLYPH_REPEATABLE] = L'\u239f'; + break; +#endif + default: + glyph[GLYPH_TOP] = L'\0'; + glyph[GLYPH_MIDDLE] = L'\0'; + glyph[GLYPH_BOTTOM] = L'\0'; + glyph[GLYPH_REPEATABLE] = L'\0'; + } + + const unsigned int family = math_symbol._glyph == L'|' ? + FAMILY_STIX_REGULAR : FAMILY_STIX_SIZE_1_REGULAR; + const float size = style_size(style); + + if (glyph[GLYPH_REPEATABLE] != L'\0') { + bounding_box_t bounding_box_sum(0, 0, 0, 0, 0, 0); + float current_y = 0; + + for (unsigned long i = GLYPH_TOP; i <= GLYPH_BOTTOM; + i++) { + if (glyph[i] != L'\0') { + bounding_box_t glyph_bounding_box = + math_bounding_box(glyph[i], family, size); + + current_y += glyph_bounding_box.descent(); + bounding_box_sum = bounding_box_sum. + merge(point_t(0, current_y) + + glyph_bounding_box); + current_y += glyph_bounding_box.ascent(); + } + } + + const bounding_box_t bounding_box_repeatable = + math_bounding_box(glyph[GLYPH_REPEATABLE], family, + size); + const float remaining_height = + height - bounding_box_sum.height(); + const unsigned long repeat_ratio = + (unsigned long)ceil( + remaining_height / + bounding_box_repeatable.height()); + + nrepeat = glyph[GLYPH_MIDDLE] == L'\0' ? + repeat_ratio : ((repeat_ratio + 1UL) >> 1); + } + else + nrepeat = 0; + } + + // Font parameters +#include "table/mathfontparam.h" + +} diff --git a/builtins/libmathtext/mathrendertoken.cc b/builtins/libmathtext/mathrendertoken.cc new file mode 100644 index 0000000000000..c15f39bbf0a92 --- /dev/null +++ b/builtins/libmathtext/mathrendertoken.cc @@ -0,0 +1,899 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + + ///////////////////////////////////////////////////////////////// + // Math List Tokenization + + std::vector + math_text_renderer_t:: + math_tokenize(const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height) + { + if (math_symbol._glyph == L'.') + return std::vector(); + + enum { + GLYPH_TOP = 0, + GLYPH_MIDDLE, + GLYPH_BOTTOM, + GLYPH_REPEATABLE, + NGLYPH + }; + const unsigned int family = math_family(math_symbol); + const float size = style_size(style); + const bounding_box_t normal_bounding_box = + math_bounding_box(math_symbol._glyph, family, size); + + if (normal_bounding_box.height() >= height) { + const math_token_t token(normal_bounding_box, + math_symbol._glyph, family, + size); + + return std::vector(1, token); + } + + unsigned long nmath_symbol_large_family; + const unsigned int *math_symbol_large_family; + + large_family(nmath_symbol_large_family, + math_symbol_large_family, math_symbol); + + for (unsigned int i = 0; i < nmath_symbol_large_family; i++) { + const bounding_box_t large_bounding_box = + math_bounding_box(math_symbol._glyph, + math_symbol_large_family[i], size); + + if (large_bounding_box.height() >= height) { + const math_token_t token(large_bounding_box, + math_symbol._glyph, + math_symbol_large_family[i], + size); + + return std::vector(1, token); + } + } + + // Extensible glyph after the TFM charlist mechanism, see + // Knuth, The METAFONTbook (1986), p. 317f. + + wchar_t glyph[NGLYPH]; + unsigned long nrepeat; + + extensible_glyph(glyph, nrepeat, math_symbol, style, height); + + if (glyph[GLYPH_BOTTOM] != L'\0' && + glyph[GLYPH_REPEATABLE] != L'\0') { + static const unsigned int extensible_family = + math_symbol._glyph == L'|' ? FAMILY_STIX_REGULAR : + FAMILY_STIX_SIZE_1_REGULAR; + const bounding_box_t bounding_box_bottom = + math_bounding_box(glyph[GLYPH_BOTTOM], + extensible_family, size); + std::vector token_list; + + token_list.push_back(math_token_t( + bounding_box_bottom, glyph[GLYPH_BOTTOM], + extensible_family, size)); + float current_y = 0; + + current_y += bounding_box_bottom.ascent(); + for (unsigned long i = 0; i < nrepeat; i++) { + const bounding_box_t bounding_box_repeatable = + math_bounding_box(glyph[GLYPH_REPEATABLE], + extensible_family, size); + + current_y += bounding_box_repeatable.descent(); + token_list.push_back(math_token_t( + point_t(0, current_y), bounding_box_repeatable, + glyph[GLYPH_REPEATABLE], extensible_family, + size)); + current_y += bounding_box_repeatable.ascent(); + } + if (glyph[GLYPH_MIDDLE] != L'\0') { + const bounding_box_t bounding_box_middle = + math_bounding_box(glyph[GLYPH_MIDDLE], + extensible_family, size); + + current_y += bounding_box_middle.descent(); + token_list.push_back(math_token_t( + point_t(0, current_y), bounding_box_middle, + glyph[GLYPH_MIDDLE], extensible_family, size)); + current_y += bounding_box_middle.ascent(); + for (unsigned long i = 0; i < nrepeat; i++) { + const bounding_box_t bounding_box_repeatable = + math_bounding_box(glyph[GLYPH_REPEATABLE], + extensible_family, size); + + current_y += bounding_box_repeatable.descent(); + token_list.push_back(math_token_t( + point_t(0, current_y), + bounding_box_repeatable, + glyph[GLYPH_REPEATABLE], extensible_family, + size)); + current_y += bounding_box_repeatable.ascent(); + } + } + + const bounding_box_t bounding_box_top = + math_bounding_box(glyph[GLYPH_TOP], + extensible_family, size); + + current_y += bounding_box_top.descent(); + token_list.push_back(math_token_t( + point_t(0, current_y), bounding_box_top, + glyph[GLYPH_TOP], extensible_family, size)); + + return token_list; + } + + const math_token_t token(normal_bounding_box, + math_symbol._glyph, family, size); + + return std::vector(1, token); + } + + std::vector + math_text_renderer_t:: + math_tokenize(const std::vector:: + const_iterator &math_list_begin, + const std::vector:: + const_iterator &math_list_end, + const unsigned int style) + { + const float size = style_size(style); + const float style_axis_height = axis_height * size; + unsigned int previous_atom_type = + math_text_t::atom_t::TYPE_UNKNOWN; + float current_x = 0; + bool has_accent = false; + + // Rule 19 + std::vector::const_iterator + math_list_begin_interior = math_list_begin; + std::vector::const_iterator + math_list_end_interior = math_list_end; + static const math_text_t::item_t fraction_item = + math_text_t::item_t::TYPE_GENERALIZED_FRACTION; + const std::vector::const_iterator + fraction_iterator = + std::find(math_list_begin_interior, + math_list_end_interior, fraction_item); + const bool generalized_fraction = + fraction_iterator != math_list_end_interior; + bool delimiter = false; + float delimiter_height; + bounding_box_t bounding_box_delimiter_left(0, 0, 0, 0, 0, 0); + bounding_box_t bounding_box_delimiter_right(0, 0, 0, 0, 0, 0); + + if (math_list_begin->_type == + math_text_t::item_t::TYPE_BOUNDARY && + (math_list_end - 1)->_type == + math_text_t::item_t::TYPE_BOUNDARY) { + math_list_begin_interior++; + math_list_end_interior--; + delimiter = true; + + const bounding_box_t bounding_box_interior = + math_bounding_box(math_list_begin_interior, + math_list_end_interior, style); + const float extension = + std::max(bounding_box_interior.ascent() - + style_axis_height, + bounding_box_interior.descent() + + style_axis_height); + + delimiter_height = extension * 0.002F * delimiter_factor; + if (generalized_fraction) + // Rule 15e + delimiter_height = std::max(delimiter_height, + if_else_display(style, delim_1, delim_2) * size); + + bounding_box_delimiter_left = + math_bounding_box(math_list_begin->_atom. + _nucleus._math_symbol, + style, delimiter_height); + bounding_box_delimiter_right = + math_bounding_box((math_list_end - 1)->_atom. + _nucleus._math_symbol, + style, delimiter_height); + } + + std::vector token_list; + + if (delimiter) { + // Standard advance mode + + // post_process_atom_type_initial(atom_type) is not + // necessary, since the current item is guaranteed not to + // be of type Bin. + + // FIXME: Must be in starting style. + + const float shift_delimiter_left = style_axis_height - + bounding_box_delimiter_left.vertical_center(); + + token_list.push_back(math_token_t( + point_t(current_x, shift_delimiter_left), + bounding_box_delimiter_left, style, + delimiter_height)); + + current_x += bounding_box_delimiter_left.advance(); + previous_atom_type = math_list_begin->_atom._type; + } + + if (generalized_fraction) { + // Rule 15a, 15b + const float thickness = fraction_iterator->_length * + default_rule_thickness * size; + const bounding_box_t numerator_bounding_box = + math_bounding_box(math_list_begin_interior, + fraction_iterator, + next_numerator_style(style)); + const bounding_box_t denominator_bounding_box = + math_bounding_box(fraction_iterator + 1, + math_list_end_interior, + next_denominator_style(style)); + const float min_shift_up = + if_else_display(style, num_1, + thickness > 0 ? num_2 : num_3) * + size; + const float min_shift_down = + if_else_display(style, denom_1, denom_2) * size; + float shift_up; + float shift_down; + + if (thickness <= 0) { + // Rule 15c (\atop) + const float min_clearance = + if_else_display(style, 7.0F, 3.0F) * + default_rule_thickness * size; + const float actual_clearance = + (min_shift_up - + numerator_bounding_box.descent()) - + (denominator_bounding_box.ascent() - + min_shift_down); + + if (actual_clearance < min_clearance) { + const float difference = 0.5F * + (min_clearance - actual_clearance); + + shift_up = min_shift_up + difference; + shift_down = min_shift_down + difference; + } + else { + shift_up = min_shift_up; + shift_down = min_shift_down; + } + } + else { + // Rule 15d (\over) + const float min_bar_clearance = + if_else_display(style, 3.0F, 1.0F) * thickness; + const float actual_numerator_clearance = + (min_shift_up - + numerator_bounding_box.descent()) - + (style_axis_height + 0.5F * thickness); + const float actual_denominator_clearance = + (style_axis_height - 0.5F * thickness) - + (denominator_bounding_box.ascent() - + min_shift_down); + + if (actual_numerator_clearance < + min_bar_clearance) { + const float difference = + (min_bar_clearance - + actual_numerator_clearance); + + shift_up = min_shift_up + difference; + } + else + shift_up = min_shift_up; + if (actual_denominator_clearance < + min_bar_clearance) { + const float difference = + (min_bar_clearance - + actual_denominator_clearance); + + shift_down = min_shift_down + difference; + } + else + shift_down = min_shift_down; + } + + const float horizontal_center_difference = + numerator_bounding_box.horizontal_center() - + denominator_bounding_box.horizontal_center(); + float horizontal_shift_numerator; + float horizontal_shift_denominator; + + if (horizontal_center_difference > 0) { + horizontal_shift_numerator = 0; + horizontal_shift_denominator = + horizontal_center_difference; + } + else { + horizontal_shift_numerator = + -horizontal_center_difference; + horizontal_shift_denominator = 0; + } + + token_list.push_back(math_token_t( + point_t(current_x + horizontal_shift_denominator, + -shift_down), + denominator_bounding_box, + next_denominator_style(style))); + if (thickness > 0) { +#if 0 + const float constrained_thickness = + std::max(1.0F, thickness); +#endif + const float left = + std::min(numerator_bounding_box.left(), + denominator_bounding_box.left()); + const float right = + std::max(numerator_bounding_box.right(), + denominator_bounding_box.right()); + + token_list.push_back(math_token_t( + point_t(current_x + left, + style_axis_height - 0.5F * thickness), + bounding_box_t(0, 0, right - left, thickness, + 0, 0), + style)); + } + token_list.push_back(math_token_t( + point_t(current_x + horizontal_shift_numerator, + shift_up), + numerator_bounding_box, + next_numerator_style(style))); + + const float advance = + std::max(horizontal_shift_numerator + + numerator_bounding_box.left() + + numerator_bounding_box.right(), + horizontal_shift_denominator + + denominator_bounding_box.left() + + denominator_bounding_box.right()); + + current_x += advance; + } + else + // Incrementally process a math list + for (std::vector::const_iterator + iterator = math_list_begin_interior; + iterator != math_list_end_interior; iterator++) { + unsigned int atom_type; + bounding_box_t item_bounding_box; + unsigned int current_style = has_accent ? + prime_style(style) : style; + bool accent; + bool vertical_alignment; + + switch (iterator->_type) { + case math_text_t::item_t::TYPE_ATOM: + atom_type = iterator->_atom._type; + item_bounding_box = + math_bounding_box(iterator->_atom, + current_style); + accent = valid_accent(vertical_alignment, + iterator, math_list_end); + if (accent) { + // Accent advance mode + const std::vector:: + const_iterator iterator_next = + iterator + 1; + const bounding_box_t next_item_bounding_box = + math_bounding_box(iterator_next->_atom, + style); + const float horizontal_shift = + (iterator == math_list_begin ? 0.0F : + math_spacing(previous_atom_type, + atom_type, style)) + + next_item_bounding_box. + horizontal_center() + + 0.5F * next_item_bounding_box. + italic_correction() - + item_bounding_box.horizontal_center(); + const float vertical_shift = + vertical_alignment ? + std::max(0.0F, + next_item_bounding_box.ascent() - + x_height(style)) : 0.0F; + + token_list.push_back(math_token_t( + point_t(current_x + horizontal_shift, + vertical_shift), + item_bounding_box, style)); + has_accent = true; + } + else { + // Standard advance mode + if (iterator == math_list_begin) + post_process_atom_type_initial(atom_type); + else { + post_process_atom_type_interior( + previous_atom_type, atom_type); + + const float horizontal_shift = + math_spacing(previous_atom_type, + atom_type, + current_style); + + current_x += + horizontal_shift; + } + + token_list.push_back(math_token_t( + point_t(current_x, 0), item_bounding_box, + current_style)); + current_x += item_bounding_box.advance(); + has_accent = false; + previous_atom_type = atom_type; + } + break; + case math_text_t::item_t::TYPE_KERN: + // Rule 2 + current_x += kerning_mu(iterator->_length); + break; + } + } + + // Rule 19 (again) + if (delimiter) { + unsigned int atom_type = + (math_list_end - 1)->_atom._type; + // Standard advance mode + + // FIXME: Must be in starting style. + + post_process_atom_type_interior(previous_atom_type, + atom_type); + + const float horizontal_shift = + math_spacing(previous_atom_type, atom_type, style); + + current_x += horizontal_shift; + + const float shift_delimiter_right = style_axis_height - + bounding_box_delimiter_right.vertical_center(); + + token_list.push_back(math_token_t( + point_t(current_x, shift_delimiter_right), + bounding_box_delimiter_right, style, + delimiter_height)); + } + + return token_list; + } + + std::vector + math_text_renderer_t:: + math_tokenize(const math_text_t::atom_t &atom, + const unsigned int style) + { + const float size = style_size(style); + std::vector token_list; + bounding_box_t nucleus_bounding_box; + float current_x = 0; + float nucleus_shift_up = 0; + + // Rule 11 + if (atom._type == math_text_t::atom_t::TYPE_RAD) { + float style_radical_rule_thickness = + default_rule_thickness * size; + const float min_clearance = + style_radical_rule_thickness + 0.25F * + if_else_display(style, x_height(style), + style_radical_rule_thickness); + const bounding_box_t bounding_box_radicand = + math_bounding_box(atom._nucleus, + prime_style(style)); + const float min_delimiter_height = + bounding_box_radicand.height() + min_clearance + + style_radical_rule_thickness; + const math_text_t::math_symbol_t + symbol_surd("\\surd", style); + const bounding_box_t bounding_box_surd = + math_bounding_box(symbol_surd, style, + min_delimiter_height); + const float surd_intrinsic_shift_down = + bounding_box_surd.ascent() - + style_radical_rule_thickness; + const float modified_descent = + bounding_box_surd.descent() + + surd_intrinsic_shift_down; + const float clearance = modified_descent > + bounding_box_radicand.height() + min_clearance ? + 0.5F * (min_clearance + modified_descent - + bounding_box_radicand.height()) : + min_clearance; + + if (!atom._index.empty()) { + // The positive space of 5 mu to the index is hard + // wired in plain.tex + current_x += (5.0F / 18.0F) * size; + + const bounding_box_t bounding_box_index = + math_bounding_box(atom._index, + math_text_t::item_t::STYLE_SCRIPT_SCRIPT); + const float radical_height = + (std::max(math_bounding_box( + atom._index, prime_style(style)).ascent(), + bounding_box_radicand.ascent() + + clearance + + 2.0F * style_radical_rule_thickness) - + std::max(math_bounding_box( + atom._index, prime_style(style)).descent(), + bounding_box_radicand.descent())); + + nucleus_bounding_box = + point_t(current_x, 0.6F * radical_height) + + math_bounding_box( + atom._index, + math_text_t::item_t::STYLE_SCRIPT_SCRIPT); + token_list.push_back(math_token_t( + point_t(current_x, 0.6F * radical_height), + bounding_box_index, + math_text_t::item_t::STYLE_SCRIPT_SCRIPT)); + // The negative space of 10 mu to the surd is hard + // wired in plain.tex + current_x += bounding_box_index.advance() - + (10.0F / 18.0F) * size; + } + + const float radicand_ascent_clearance = + bounding_box_radicand.ascent() + clearance; + + nucleus_bounding_box = nucleus_bounding_box.merge( + point_t(current_x, + radicand_ascent_clearance - + surd_intrinsic_shift_down) + + bounding_box_surd); + token_list.push_back(math_token_t( + point_t(current_x, + radicand_ascent_clearance - + surd_intrinsic_shift_down), + bounding_box_surd, style, min_delimiter_height)); + current_x += bounding_box_surd.advance(); + + const float constrained_thickness = +#if 0 + // Pixel height constraint + std::max(1.0F, style_radical_rule_thickness) +#else + style_radical_rule_thickness +#endif + ; + static const float surd_rule_correction_x = -1.5F; + static const float surd_rule_correction_y = -0.5F; + + const point_t origin_rule = + point_t(current_x, radicand_ascent_clearance); + const bounding_box_t bounding_box_rule = + bounding_box_t(surd_rule_correction_x * + constrained_thickness, + surd_rule_correction_y * + constrained_thickness, + bounding_box_radicand.advance(), + (surd_rule_correction_y + 1.0F) * + constrained_thickness, + 0, 0); + + nucleus_bounding_box = nucleus_bounding_box.merge( + origin_rule + bounding_box_rule); + token_list.push_back(math_token_t( + origin_rule, bounding_box_rule, style)); + + const bounding_box_t bounding_box_clearance = + bounding_box_t(0, -2.0F * constrained_thickness, + bounding_box_radicand.advance(), + constrained_thickness, + 0, 0); + + nucleus_bounding_box = nucleus_bounding_box.merge( + origin_rule + bounding_box_clearance); + token_list.push_back(math_token_t( + origin_rule, bounding_box_clearance, style)); + + const point_t origin_radicand = point_t(current_x, 0); + + nucleus_bounding_box = nucleus_bounding_box.merge( + origin_radicand + bounding_box_radicand); + token_list.push_back(math_token_t( + origin_radicand, bounding_box_radicand, + prime_style(style))); + current_x += bounding_box_radicand.advance(); + } + else if (atom._type == math_text_t::atom_t::TYPE_OP) { + const bool limits = + atom._limits == math_text_t::atom_t::LIMITS_LIMITS || + (atom._limits == + math_text_t::atom_t::LIMITS_DISPLAYLIMITS && + is_display_style(style)); + + if (atom._nucleus._type == + math_text_t::field_t::TYPE_MATH_SYMBOL) { + // Rule 13 + nucleus_bounding_box = math_bounding_box( + atom._nucleus._math_symbol._glyph, + FAMILY_STIX_REGULAR, + size * if_else_display(style, + large_operator_display_scale, 1.0F)); + nucleus_shift_up = + axis_height * size - + nucleus_bounding_box.vertical_center(); + if (limits && atom._subscript.empty()) + nucleus_bounding_box.advance() += + nucleus_bounding_box.italic_correction(); + } + else + nucleus_bounding_box = + math_bounding_box(atom._nucleus, style); + + if (limits && !(atom._superscript.empty() && + atom._subscript.empty())) { + // Rule 13a + const unsigned int superscript_style = + next_superscript_style(style); + const unsigned int subscript_style = + next_subscript_style(style); + + if (atom._superscript.empty()) { + const bounding_box_t subscript_bounding_box = + math_bounding_box(atom._subscript, + subscript_style); + const float shift_right = + nucleus_bounding_box.horizontal_center() - + subscript_bounding_box.horizontal_center() - + 0.5F * + nucleus_bounding_box.italic_correction(); + const float clearance = + std::max(big_op_spacing_2 * size, + big_op_spacing_4 * size - + subscript_bounding_box.ascent()); + const float shift_down = + nucleus_bounding_box.descent() + clearance + + subscript_bounding_box.ascent() - + nucleus_shift_up; + + if (shift_right >= 0) { + token_list.push_back(math_token_t( + point_t(0, nucleus_shift_up), + nucleus_bounding_box, style)); + token_list.push_back(math_token_t( + point_t(shift_right, -shift_down), + subscript_bounding_box, + subscript_style)); + } + else { + token_list.push_back(math_token_t( + point_t(-shift_right, + nucleus_shift_up), + nucleus_bounding_box, style)); + token_list.push_back(math_token_t( + point_t(0, -shift_down), + subscript_bounding_box, + subscript_style)); + } + return token_list; + } + if (atom._subscript.empty()) { + const bounding_box_t superscript_bounding_box = + math_bounding_box(atom._superscript, + superscript_style); + const float shift_right = + nucleus_bounding_box.horizontal_center() - + superscript_bounding_box. + horizontal_center() + 0.5F * + nucleus_bounding_box.italic_correction(); + const float clearance = + std::max(big_op_spacing_1 * size, + big_op_spacing_3 * size - + superscript_bounding_box.descent()); + const float shift_up = + nucleus_bounding_box.ascent() + clearance + + superscript_bounding_box.descent() + + nucleus_shift_up; + + if (shift_right >= 0) { + token_list.push_back(math_token_t( + point_t(0, nucleus_shift_up), + nucleus_bounding_box, style)); + token_list.push_back(math_token_t( + point_t(shift_right, shift_up), + superscript_bounding_box, + superscript_style)); + } + else { + token_list.push_back(math_token_t( + point_t(-shift_right, + nucleus_shift_up), + nucleus_bounding_box, style)); + token_list.push_back(math_token_t( + point_t(0, shift_up), + superscript_bounding_box, + superscript_style)); + } + return token_list; + } + const bounding_box_t superscript_bounding_box = + math_bounding_box(atom._superscript, + superscript_style); + const bounding_box_t subscript_bounding_box = + math_bounding_box(atom._subscript, + subscript_style); + const float shift_right_superscript = + nucleus_bounding_box.horizontal_center() - + superscript_bounding_box.horizontal_center() + + 0.5F * nucleus_bounding_box.italic_correction(); + const float shift_right_subscript = + nucleus_bounding_box.horizontal_center() - + subscript_bounding_box.horizontal_center() - + 0.5F * nucleus_bounding_box.italic_correction(); + const float clearance_superscript = + std::max(big_op_spacing_1 * size, + big_op_spacing_3 * size - + superscript_bounding_box.descent()); + const float clearance_subscript = + std::max(big_op_spacing_2 * size, + big_op_spacing_4 * size - + subscript_bounding_box.ascent()); + const float shift_up = + nucleus_bounding_box.ascent() + + clearance_superscript + + superscript_bounding_box.descent() + + nucleus_shift_up; + const float shift_down = + nucleus_bounding_box.descent() + + clearance_subscript + + subscript_bounding_box.ascent() - + nucleus_shift_up; + const float min_shift_right = + std::min(0.0F, std::min(shift_right_superscript, + shift_right_subscript)); + + token_list.push_back(math_token_t( + point_t(-min_shift_right, + nucleus_shift_up), + nucleus_bounding_box, style)); + token_list.push_back(math_token_t( + point_t(shift_right_superscript - + min_shift_right, + shift_up), + superscript_bounding_box, + superscript_style)); + token_list.push_back(math_token_t( + point_t(shift_right_subscript - + min_shift_right, + -shift_down), + subscript_bounding_box, + subscript_style)); + return token_list; + } + + // \nolimits or nucleus only + token_list.push_back(math_token_t( + point_t(0, nucleus_shift_up), + nucleus_bounding_box, style)); + current_x += nucleus_bounding_box.advance(); + } + else { // Neither Rad nor Op + nucleus_bounding_box = + math_bounding_box(atom._nucleus, style); + token_list.push_back(math_token_t( + nucleus_bounding_box, style)); + current_x += nucleus_bounding_box.advance(); + } + + if (atom._superscript.empty() && atom._subscript.empty()) + return token_list; + + const float current_x_italic_corrected = current_x + + nucleus_bounding_box.italic_correction(); + const float nucleus_size = size; + const unsigned int superscript_style = + next_superscript_style(style); + const unsigned int subscript_style = + next_subscript_style(style); + const float superscript_size = style_size(superscript_style); + const float subscript_size = style_size(subscript_style); + // Rule 18a + const float min_shift_up = nucleus_bounding_box.ascent() - + superscript_size * sup_drop; + const float min_shift_down = nucleus_bounding_box.descent() + + subscript_size * sub_drop; + + // Rule 18b + if (atom._superscript.empty()) { + const bounding_box_t subscript_bounding_box = + math_bounding_box(atom._subscript, subscript_style); + const float shift_down = + std::max(std::max(min_shift_down, + nucleus_size * sub_1), + subscript_bounding_box.ascent() - + 0.8F * x_height(subscript_style)); + token_list.push_back(math_token_t( + point_t(current_x, nucleus_shift_up - shift_down), + subscript_bounding_box, subscript_style)); + return token_list; + } + // Rule 18c + const bounding_box_t superscript_bounding_box = + math_bounding_box(atom._superscript, superscript_style); + const float min_shift_up_2 = nucleus_size * + (style == math_text_t::item_t::STYLE_DISPLAY ? + sup_1 : is_prime_style(style) ? sup_3 : sup_2); + float shift_up = + std::max(std::max(min_shift_up, min_shift_up_2), + superscript_bounding_box.descent() + + 0.2F * x_height(superscript_style)); + // Rule 18d + if (atom._subscript.empty()) { + token_list.push_back(math_token_t( + point_t(current_x_italic_corrected, + nucleus_shift_up + shift_up), + superscript_bounding_box, superscript_style)); + return token_list; + } + + // Still rule 18d + float shift_down = + std::max(min_shift_down, nucleus_size * sub_2); + // Rule 18e + const bounding_box_t subscript_bounding_box = + math_bounding_box(atom._subscript, subscript_style); + + if ((shift_up - superscript_bounding_box.descent()) - + (subscript_bounding_box.ascent() - shift_down) < + 4.0F * default_rule_thickness * + nucleus_size) { + shift_down = 4.0F * default_rule_thickness * + nucleus_size + subscript_bounding_box.ascent() + + superscript_bounding_box.descent() - shift_up; + + const float superscript_adjustment = + 0.8F * x_height(superscript_style) - + (shift_up - superscript_bounding_box.descent()); + + if (superscript_adjustment > 0) { + shift_up += superscript_adjustment; + shift_down -= superscript_adjustment; + } + } + // Rule 18f + token_list.push_back(math_token_t( + point_t(current_x_italic_corrected, + nucleus_shift_up + shift_up), + superscript_bounding_box, superscript_style)); + token_list.push_back(math_token_t( + point_t(current_x, + nucleus_shift_up - shift_down), + subscript_bounding_box, subscript_style)); + + return token_list; + } + +} diff --git a/builtins/libmathtext/mathtext.cc b/builtins/libmathtext/mathtext.cc new file mode 100644 index 0000000000000..ab7d72cb8240a --- /dev/null +++ b/builtins/libmathtext/mathtext.cc @@ -0,0 +1,350 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + + ///////////////////////////////////////////////////////////////// + + void math_text_t::field_t::transform_script(void) + { + const unsigned long size = _math_list.size(); + + if (size < 2) + return; + + std::vector::reverse_iterator last = + _math_list.rbegin(); + std::vector::reverse_iterator second_last = + last + 1; + + if (last->_type == item_t::TYPE_ATOM && + second_last->_type == item_t::TYPE_ATOM && + second_last->_atom._type == atom_t::TYPE_ACC && + !(last->_atom._superscript.empty() && + last->_atom._subscript.empty())) { + // Rule 12 + atom_t atom = field_t(); + + atom._nucleus._math_list.push_back(*second_last); + atom._nucleus._math_list.push_back(*last); + atom._superscript = + atom._nucleus._math_list.back()._atom._superscript; + atom._subscript = + atom._nucleus._math_list.back()._atom._subscript; + atom._nucleus._math_list.back()._atom._superscript = + field_t(); + atom._nucleus._math_list.back()._atom._subscript = + field_t(); + _math_list.pop_back(); + _math_list.pop_back(); + _math_list.push_back(item_t(atom)); + } + } + + void math_text_t::field_t::append(const item_t &item) + { + _math_list.push_back(item); + } + + // FIXME: Check for malformed "..._a^b_c" (instead of just + // overwriting) + void math_text_t::field_t:: + append(const field_t &field, const bool superscript, + const bool subscript) + { + if ((superscript || subscript) && _math_list.empty()) + _math_list.push_back(item_t(field_t())); + + if (superscript) { + _math_list.back()._atom._superscript = field; + transform_script(); + } + else if (subscript) { + _math_list.back()._atom._subscript = field; + transform_script(); + } + else + append(item_t(item_t::TYPE_ATOM, atom_t(field))); + } + + void math_text_t::field_t:: + prepend(const unsigned int type, + const math_symbol_t &math_symbol) + { + _math_list.insert(_math_list.begin(), + item_t(type, + atom_t(field_t(math_symbol)))); + } + + void math_text_t::field_t:: + append(const unsigned int type, const math_symbol_t &math_symbol, + const bool superscript, const bool subscript) + { + if ((superscript || subscript) && _math_list.empty()) + _math_list.push_back(item_t(field_t())); + + if (superscript) { + _math_list.back()._atom._superscript = + field_t(math_symbol); + transform_script(); + } + else if (subscript) { + _math_list.back()._atom._subscript = + field_t(math_symbol); + transform_script(); + } + else + append(item_t(type, atom_t(field_t(math_symbol)))); + } + + math_text_t::field_t:: + field_t(const std::vector &str_split, + const unsigned int default_family) + : _type(TYPE_MATH_LIST) + { + parse_math_list(str_split, default_family); + } + + math_text_t::field_t:: + field_t(const std::string &str_delimiter_left, + const std::vector &str_split, + const std::string &str_delimiter_right, + const unsigned int default_family) + : _type(TYPE_MATH_LIST) + { + parse_math_list(str_split, default_family); + + const math_symbol_t + symbol_left(str_delimiter_left, default_family); + + prepend(item_t::TYPE_BOUNDARY, symbol_left); + + const math_symbol_t + symbol_right(str_delimiter_right, default_family); + + append(item_t::TYPE_BOUNDARY, symbol_right, false, false); + } + + bool math_text_t::field_t::generalized_fraction(void) const + { + if (_type == TYPE_MATH_LIST) + for (std::vector::const_iterator iterator = + _math_list.begin(); + iterator != _math_list.end(); iterator++) + if (iterator->_type == + item_t::TYPE_GENERALIZED_FRACTION) + return true; + return false; + } + + void math_text_t::atom_t::classify(void) + { + // Only nucleus affects the atom type (Knuth, The TeXbook, + // 1986, p. 171) + if (_nucleus._type == field_t::TYPE_MATH_SYMBOL) + _type = _nucleus._math_symbol._type; + else if (_nucleus.generalized_fraction()) + _type = atom_t::TYPE_INNER; + else + // FIXME: Does TeX flatten compound expressions before + // classify them? + _type = TYPE_ORD; + } + + bool math_text_t::atom_t::is_combining_diacritical(void) const + { + return _nucleus._type == field_t::TYPE_MATH_SYMBOL && + _nucleus._math_symbol.is_combining_diacritical(); + } + + unsigned int math_text_t::atom_t:: + spacing(const unsigned int left_type, + const unsigned int right_type, const bool script) + { +#include "table/mathspacing.h" + // Since we only handle atom types upto Inner, the upper bound + // is type <= TYPE_INNER and not type < NTYPE. + if (left_type == TYPE_UNKNOWN || left_type > TYPE_INNER || + right_type == TYPE_UNKNOWN || right_type > TYPE_INNER) { + // Invalid + return 0; + } + + int index = ((left_type - TYPE_ORD) << 3) + + (right_type - TYPE_ORD); + int space = spacing_table[index]; + + if (space == nvr) { + // Invalid + return 0; + } + // Interpret the \nonscript sign, which denotes spaces that + // should be ignored within the script (and scriptscript) + // style. + if (space < 0) + space = script ? 0 : -space; + + return space; + } + + bool math_text_t::item_t::operator==(const item_t &item) const + { + switch (_type) { + case TYPE_GENERALIZED_FRACTION: + return item._type == TYPE_GENERALIZED_FRACTION; + break; + default: + return false; + } + } + + std::wstring math_text_t::bad_cast(const std::string string) + { + std::wstring wstring; + + for (std::string::const_iterator iterator = string.begin(); + iterator != string.end(); iterator++) { + wstring.push_back(*iterator); + } + + return wstring; + } + + std::wstring math_text_t::utf8_cast(const std::string string) + { + std::wstring wstring; + + for (std::string::const_iterator iterator = string.begin(); + iterator != string.end();) { + wchar_t c; + + // Skip over byte ordering marks + if ((*iterator & 0xff) == 0xef) { + iterator++; + if ((*iterator & 0xff) == 0xbb) { + iterator++; + if ((*iterator & 0xff) == 0xbf) { + iterator++; + } + } + } + if ((*iterator & 0xf0) == 0xf0) { + c = (*iterator & 0x7) << 18; + iterator++; + if ((*iterator & 0xc0) != 0x80) { + continue; + } + c |= (*iterator & 0x3f) << 12; + iterator++; + if ((*iterator & 0xc0) != 0x80) { + continue; + } + c |= (*iterator & 0x3f) << 6; + iterator++; + if ((*iterator & 0xc0) != 0x80) { + continue; + } + c |= (*iterator & 0x3f); + iterator++; + } + else if ((*iterator & 0xe0) == 0xe0) { + c = (*iterator & 0xf) << 12; + iterator++; + if ((*iterator & 0xc0) != 0x80) { + continue; + } + c |= (*iterator & 0x3f) << 6; + iterator++; + if ((*iterator & 0xc0) != 0x80) { + continue; + } + c |= (*iterator & 0x3f); + iterator++; + } + else if ((*iterator & 0xc0) == 0xc0) { + c = (*iterator & 0x1f) << 6; + iterator++; + if ((*iterator & 0xc0) != 0x80) { + continue; + } + c |= (*iterator & 0x3f); + iterator++; + } + else if ((*iterator & 0x80) == 0x0) { + c = (*iterator & 0x7f); + iterator++; + } + else { + iterator++; + continue; + } + wstring.push_back(c); + } + + return wstring; + } + +#if 0 + std::wstring math_text_t::gb_18030_cast( + const std::string string) + { + } + + std::wstring math_text_t::shift_jis_x_0213_cast( + const std::string string) + { + } + + std::wstring math_text_t::euc_jis_x_0213_cast( + const std::string string) + { + } + + std::wstring math_text_t::ks_x_2901_cast( + const std::string string) + { + } +#endif + + // Apply JIS X 4051:2004 + + bool math_text_t::well_formed(void) const + { + if (_math_list._type != field_t::TYPE_MATH_LIST) + return false; + return true; + } + + std::string tex_form(const double x) + { + std::string retval; + + switch (std::fpclassify(x)) { + default: + return retval; + } + } + +} diff --git a/builtins/libmathtext/mathtext/fontembed.h b/builtins/libmathtext/mathtext/fontembed.h new file mode 100644 index 0000000000000..eeab093940220 --- /dev/null +++ b/builtins/libmathtext/mathtext/fontembed.h @@ -0,0 +1,228 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2016 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include +#include + +namespace mathtext { + + class font_embed_t { + protected: + struct table_data_s { + char tag[4]; + std::vector data; + }; + static void protected_memcpy( + void *destination, + std::vector::const_iterator source, + std::vector::const_iterator source_end, + size_t length, const char *location); + static void subset_rename_otf_name_table( + struct table_data_s &table_data, uint8_t *glyph_usage); + static void subset_ttf_glyf_table( + struct table_data_s &table_data, uint8_t *glyph_usage); + static void subset_ttf_loca_table( + struct table_data_s &table_data, uint8_t *glyph_usage); + static void subset_ttf_post_table( + struct table_data_s &table_data, uint8_t *glyph_usage); + static void subset_otf_cff_table( + struct table_data_s &table_data, uint8_t *glyph_usage); + static void parse_ttf_encoding_subtable_format4( + std::map &cid_map, + const std::vector &font_data, + const size_t offset); + static void parse_ttf_encoding_subtable_format12( + std::map &cid_map, + const std::vector &font_data, + const size_t offset); + static unsigned int otf_check_sum( + const std::vector &table_data); + public: + // I/O + static std::vector read_font_data(FILE *); + static std::vector read_font_data( + const std::string &filename); + // Font parsing + // OTF/TTF tables + static std::map > + parse_ttf_offset_table( + const std::vector &font_data, + size_t offset_table_size, uint16_t num_tables); + static void parse_ttf_cmap( + std::map &cid_map, + const std::vector &font_data, + uint32_t cmap_offset); + static void parse_ttf_head( + double *font_bbox, uint16_t &units_per_em, + const std::vector &font_data, + uint32_t head_offset); + static uint16_t parse_ttf_hhea( + const std::vector &font_data, + uint32_t hhea_offset); + static std::vector parse_ttf_hmtx( + const std::vector &font_data, + uint32_t hmtx_offset, uint16_t number_of_h_metrics); + static uint16_t parse_ttf_maxp( + const std::vector &font_data, + uint32_t maxp_offset); + static void parse_ttf_name( + std::string &font_name, uint16_t &cid_encoding_id, + const std::vector &font_data, + uint32_t name_offset); + static void parse_ttf_os_2( + uint32_t &font_descriptor_flag, double &ascent, + double &descent, double &leading, double &cap_height, + double &x_height, double &stem_v, double &avg_width, + const std::vector &font_data, + uint32_t os_2_offset, uint16_t units_per_em); + static void parse_ttf_post( + std::vector &charset, + double &italic_angle, uint32_t &font_descriptor_flags, + const std::vector &font_data, + uint32_t name_offset); + // CFF parsing + static std::vector > parse_cff_index( + const std::vector &font_data, + uint32_t ¤t_offset, uint32_t *skip_psize = NULL); + static double parse_cff_dict_number( + std::vector::const_iterator &data, + std::vector::const_iterator end); + static double search_cff_top_dict_number( + const std::vector &top_dict, + uint8_t operator_value_1, uint8_t operator_value_2 = 255); + static std::string cff_sid_to_string( + uint16_t sid, + const std::vector > &string_index); + static std::vector parse_cff_charset( + const std::vector &data, + uint32_t charset_offset, uint32_t cff_nglyph, + const std::vector > &string_index); + static void parse_cff( + std::vector &charset, + const std::vector &font_data, + uint32_t cff_offset); + // OTF CFF parsing interface + static bool parse_otf_cff_header( + std::string &font_name, unsigned short &cid_encoding_id, + uint32_t font_descriptor_flags, double *font_bbox, + double &italic_angle, double &ascent, double &descent, + double &leading, double &cap_height, double &x_height, + double &stem_v,double &avg_width, + std::map &cid_map, + std::vector &charset, + std::vector &advance_width, + unsigned int &cff_offset, unsigned int &cff_length, + const std::vector &font_data); + static bool parse_otf_cff_header( + std::string &font_name, unsigned short &cid_encoding_id, + unsigned int &cff_offset, unsigned int &cff_length, + const std::vector &font_data); + static std::vector + charset_from_adobe_glyph_list( + std::map &cid_map); + static bool parse_ttf_header( + std::string &font_name, unsigned short &cid_encoding_id, + uint32_t font_descriptor_flags, double *font_bbox, + double &italic_angle, double &ascent, double &descent, + double &leading, double &cap_height, double &x_height, + double &stem_v,double &avg_width, + std::map &cid_map, + std::vector &charset, + std::vector &advance_width, + const std::vector &font_data); + static bool parse_ttf_header( + std::string &font_name, double *font_bbox, + std::map &cid_map, + std::vector &charset, + const std::vector &font_data); + // Font subsetting + static std::vector subset_otf( + const std::vector &font_data, + const std::map &glyph_usage); + }; + + class font_embed_postscript_t : public font_embed_t { + public: + static void append_asciihex( + std::string &ascii, const uint8_t *buffer, + const size_t length); + static unsigned int ascii85_line_count( + const uint8_t *buffer, const size_t length); + static void append_ascii85( + std::string &ascii, const uint8_t *buffer, + const size_t length); + public: + static std::string font_embed_type_1( + std::string &font_name, + const std::vector &font_data); + static std::string font_embed_type_2( + std::string &font_name, + const std::vector &font_data); + static std::string font_embed_type_42( + std::string &font_name, + const std::vector &font_data); + }; + + class font_embed_pdf_t : public font_embed_t { + protected: + struct cid_char_s { + uint32_t code; + uint16_t cid; + }; + struct cid_range_s { + uint32_t code_first; + uint32_t code_last; + uint16_t cid; + }; + static uint16_t utf16_high_surrogate(uint32_t code); + static uint16_t utf16_low_surrogate(uint32_t code); + static std::string utf16be_str(uint32_t code); + static std::string uint16_str(uint16_t code); + static void add_cidfont_w_token(std::string &s, const std::string &t); + static std::string cidfont_w( + const std::vector &advance_width); + static std::string pdf_vector_differences( + const std::string &key, + const std::map &cid_map, + const std::vector &charset); + static std::map + font_embed_cid( + std::string &font_name, + const std::vector &font_data, + unsigned int type); + public: + static std::map + font_embed_type_2( + std::string &font_name, + const std::vector &font_data); + static std::map + font_embed_type_42( + std::string &font_name, + const std::vector &font_data); + }; + + class font_embed_svg_t : public font_embed_t { + static std::string font_embed_svg( + std::string &font_name, + const std::vector &font_data); + }; + +} diff --git a/builtins/libmathtext/mathtext/geometry.h b/builtins/libmathtext/mathtext/geometry.h new file mode 100644 index 0000000000000..e97b04cd88980 --- /dev/null +++ b/builtins/libmathtext/mathtext/geometry.h @@ -0,0 +1,473 @@ +// -*- mode: c++; -*- + +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#ifndef MATHTEXT_GEOMETRY_H_ +#define MATHTEXT_GEOMETRY_H_ + +#include +#include +#include + +namespace mathtext { + + /** + * 2D point (and vector) + */ + class point_t { + private: + float _x[2]{}; + public: + inline point_t(void) + { + } + inline point_t(const point_t &point) + { + _x[0] = point._x[0]; + _x[1] = point._x[1]; + } + inline point_t(const float x0, const float y0) + { + _x[0] = x0; + _x[1] = y0; + } + inline const float *x(void) const + { + return _x; + } + inline float *x(void) + { + return _x; + } + inline float operator[](const int n) const + { + return _x[n]; + } + inline float &operator[](const int n) + { + return _x[n]; + } + inline point_t operator+(const point_t &point) const + { + return point_t(_x[0] + point._x[0], + _x[1] + point._x[1]); + } + inline point_t operator-(const point_t &point) const + { + return point_t(_x[0] - point._x[0], + _x[1] - point._x[1]); + } + inline point_t operator+=(const point_t &point) + { + _x[0] += point._x[0]; + _x[1] += point._x[1]; + + return *this; + } + inline point_t operator-=(const point_t &point) + { + _x[0] -= point._x[0]; + _x[1] -= point._x[1]; + + return *this; + } + inline point_t operator*(const float scale) const + { + return point_t(_x[0] * scale, _x[1] * scale); + } + inline point_t operator/(const float scale) const + { + return point_t(_x[0] / scale, _x[1] / scale); + } + inline point_t operator*=(const float scale) + { + _x[0] *= scale; + _x[1] *= scale; + + return *this; + } + inline float dot(const point_t &point) const + { + return _x[0] * point._x[0] + _x[1] * point._x[1]; + } + inline float cross(const point_t &point) const + { + return _x[0] * point._x[1] - _x[1] * point._x[0]; + } + inline float norm_square(void) const + { + return _x[0] * _x[0] + _x[1] * _x[1]; + } + inline float norm(void) const + { + return sqrtf(norm_square()); + } + inline point_t unit_vector(void) const + { + return *this / norm(); + } + inline point_t rotate_cw(void) const + { + return point_t(_x[1], -_x[0]); + } + inline point_t rotate_ccw(void) const + { + return point_t(-_x[1], _x[0]); + } + inline bool operator==(const point_t &point) const + { + return _x[0] == point._x[0] && _x[1] == point._x[1]; + } + inline bool operator!=(const point_t &point) const + { + return _x[0] != point._x[0] || _x[1] != point._x[1]; + } + friend point_t operator*(const float scale, + const point_t &point); + operator std::string(void) const; + }; + + inline point_t operator*(const float scale, const point_t &point) + { + return point_t(scale * point._x[0], scale * point._x[1]); + } + + /** + * General 2D affine transform of the Adobe Imaging Model + * + * @see Adobe Systems, Inc., PostScript Language Reference Manual + * (Addison-Wesley, Reading, MA, 1999), section 4.3.3, pp. + * 187-189. + * @see Adobe Systems, Inc., PDF Reference, 6th Edition, Version + * 1.7 (Adobe Systems, Inc., San Jose, CA, 2006), section + * 4.2.2-4.2.3, pp. 204-209. + */ + class affine_transform_t { + private: + float _a[6]; + public: + static const affine_transform_t identity; + static const affine_transform_t flip_y; + static affine_transform_t + translate(const float tx, const float ty); + static affine_transform_t + scale(const float sx, const float sy); + static affine_transform_t rotate(const float angle); + inline affine_transform_t(const float a, const float b, + const float c, const float d, + const float tx, const float ty) + { + _a[0] = a; + _a[1] = b; + _a[2] = c; + _a[3] = d; + _a[4] = tx; + _a[5] = ty; + } + inline const float *a(void) const + { + return _a; + } + inline float *a(void) + { + return _a; + } + inline float operator[](const int n) const + { + return _a[n]; + } + inline float &operator[](const int n) + { + return _a[n]; + } + inline affine_transform_t linear(void) const + { + return affine_transform_t(_a[0], _a[1], _a[2], _a[3], + 0.0F, 0.0F); + } + inline affine_transform_t translate(void) const + { + return affine_transform_t(1.0F, 0.0F, 0.0F, 1.0F, + _a[4], _a[5]); + } + inline affine_transform_t operator*(const float s) const + { + return affine_transform_t(_a[0] * s, _a[1] * s, + _a[2] * s, _a[3] * s, + _a[4] * s, _a[5] * s); + } + inline affine_transform_t operator/(const float s) const + { + return affine_transform_t(_a[0] / s, _a[1] / s, + _a[2] / s, _a[3] / s, + _a[4] / s, _a[5] / s); + } + inline point_t operator*(const point_t x) const + { + return point_t(_a[0] * x[0] + _a[2] * x[1] + _a[4], + _a[1] * x[0] + _a[3] * x[1] + _a[5]); + } + inline affine_transform_t + operator*(const affine_transform_t b) const + { + return affine_transform_t( + _a[0] * b._a[0] + _a[1] * b._a[2], + _a[0] * b._a[1] + _a[1] * b._a[3], + _a[2] * b._a[0] + _a[3] * b._a[2], + _a[2] * b._a[1] + _a[3] * b._a[3], + _a[4] * b._a[0] + _a[5] * b._a[2] + b._a[4], + _a[4] * b._a[1] + _a[5] * b._a[3] + b._a[5]); + } + inline float determinant(void) const + { + return _a[0] * _a[3] - _a[1] * _a[2]; + } + inline affine_transform_t inverse(void) const + { + return affine_transform_t( + _a[3], -_a[1], -_a[2], _a[0], + _a[2] * _a[5] - _a[3] * _a[4], + _a[1] * _a[4] - _a[0] * _a[5]) * + (1.0F / determinant()); + } + operator std::string(void) const; + }; + + class bounding_box_t { + private: + point_t _lower_left; + point_t _upper_right; + float _advance{0.}; + float _italic_correction{0.}; + public: + inline bounding_box_t(void) + { + } + inline bounding_box_t(const point_t lower_left, + const point_t upper_right, + const float advance, + const float italic_correction) + : _lower_left(lower_left), _upper_right(upper_right), + _advance(advance), _italic_correction(italic_correction) + { + } + inline bounding_box_t(const float left, const float bottom, + const float right, const float top, + const float advance, + const float italic_correction) + : _advance(advance), _italic_correction(italic_correction) + { + _lower_left[0] = left; + _lower_left[1] = bottom; + _upper_right[0] = right; + _upper_right[1] = top; + } + inline point_t lower_left(void) const + { + return _lower_left; + } + inline point_t &lower_left(void) + { + return _lower_left; + } + inline point_t upper_right(void) const + { + return _upper_right; + } + inline point_t &upper_right(void) + { + return _upper_right; + } + inline float left(void) const + { + return _lower_left[0]; + } + inline float &left(void) + { + return _lower_left[0]; + } + inline float top(void) const + { + return _upper_right[1]; + } + inline float &top(void) + { + return _upper_right[1]; + } + inline float right(void) const + { + return _upper_right[0]; + } + inline float &right(void) + { + return _upper_right[0]; + } + inline float bottom(void) const + { + return _lower_left[1]; + } + inline float &bottom(void) + { + return _lower_left[1]; + } + inline float advance(void) const + { + return _advance; + } + inline float &advance(void) + { + return _advance; + } + inline float italic_correction(void) const + { + return _italic_correction; + } + inline float &italic_correction(void) + { + return _italic_correction; + } + inline float width(void) const + { + return _upper_right[0] - _lower_left[0]; + } + inline float height(void) const + { + return _upper_right[1] - _lower_left[1]; + } + inline float horizontal_center(void) const + { + return 0.5F * (_lower_left[0] + _upper_right[0]); + } + inline float vertical_center(void) const + { + return 0.5F * (_lower_left[1] + _upper_right[1]); + } + inline float ascent(void) const + { + return _upper_right[1]; + } + inline float descent(void) const + { + return -_lower_left[1]; + } + inline bounding_box_t + merge(const bounding_box_t &bounding_box) const + { + bounding_box_t ret; + + ret._lower_left[0] = + std::min(_lower_left[0], + bounding_box._lower_left[0]); + ret._lower_left[1] = + std::min(_lower_left[1], + bounding_box._lower_left[1]); + if (bounding_box._upper_right[0] > _upper_right[0]) { + ret._upper_right[0] = bounding_box._upper_right[0]; + ret._italic_correction = + bounding_box._italic_correction; + } + else { + ret._upper_right[0] = _upper_right[0]; + ret._italic_correction = _italic_correction; + } + ret._upper_right[1] = + std::max(_upper_right[1], + bounding_box._upper_right[1]); + ret._advance = + std::max(_upper_right[0] + _advance, + bounding_box._upper_right[0] + + bounding_box._advance) - + ret._upper_right[0]; + + return ret; + } + inline bounding_box_t operator+(const point_t &point) const + { + return bounding_box_t(_lower_left + point, + _upper_right + point, + _advance + point[0], + _italic_correction); + } + inline bounding_box_t operator-(const point_t &point) const + { + return bounding_box_t(_lower_left - point, + _upper_right - point, + _advance - point[0], + _italic_correction); + } + inline bounding_box_t operator+=(const point_t &point) + { + _lower_left += point; + _upper_right += point; + _advance += point[0]; + + return *this; + } + inline bounding_box_t operator-=(const point_t &point) + { + _lower_left -= point; + _upper_right -= point; + _advance -= point[0]; + + return *this; + } + friend bounding_box_t + operator+(const point_t &, const bounding_box_t &); + friend bounding_box_t + operator-(const point_t &, const bounding_box_t &); + friend bounding_box_t + operator*(const affine_transform_t &, + const bounding_box_t &); + }; + + inline bounding_box_t + operator+(const point_t &point, + const bounding_box_t &bounding_box) + { + return bounding_box_t(point + bounding_box._lower_left, + point + bounding_box._upper_right, + point[0] + bounding_box._advance, + bounding_box._italic_correction); + } + + inline bounding_box_t + operator-(const point_t &point, + const bounding_box_t &bounding_box) + { + return bounding_box_t(point - bounding_box._lower_left, + point - bounding_box._upper_right, + point[0] + bounding_box._advance, + bounding_box._italic_correction); + } + + inline bounding_box_t + operator*(const affine_transform_t &transform, + const bounding_box_t &bounding_box) + { + return bounding_box_t( + transform * bounding_box._lower_left, + transform * bounding_box._upper_right, + (transform * point_t(bounding_box._advance, 0))[0], + (transform * point_t( + bounding_box._italic_correction, 0))[0]); + } + +} + +#endif // MATHTEXT_GEOMETRY_H_ diff --git a/builtins/libmathtext/mathtext/mathrender.h b/builtins/libmathtext/mathtext/mathrender.h new file mode 100644 index 0000000000000..00f3a94501499 --- /dev/null +++ b/builtins/libmathtext/mathtext/mathrender.h @@ -0,0 +1,388 @@ +// -*- mode: c++; -*- + +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#ifndef MATHRENDER_H_ +#define MATHRENDER_H_ + +#include +#include +#include +#include +#include + +namespace mathtext { + +#ifdef __INTEL_COMPILER +#pragma warning(push) +#pragma warning(disable: 869) +#endif // __INTEL_COMPILER + /** + * Mathematical layout engine for formulae represented by + * math_text_t + * + * The class math_text_renderer_t is a layout engine based on + * TeX's conversion algorithm from a math list to a horizontal + * list. + * + * @see ISO/IEC JTC1/SC2/WG2, ISO/IEC 10646:2003/Amd.2:2006 (ISO, + * Geneva, 2006). + * @see D. E. Knuth, The TeXbook (Addision-Wesley, Cambridge, MA, + * 1986). + * @see D. E. Knuth, The METAFONTbook (Addision-Wesley, Cambridge, + * MA, 1986). + * @see W. Schmidt, The macro package lucimatx (2005), + * unpublished. + * @see W. Schmidt, Using the MathTime Professional II fonts with + * LaTeX (2006), unpublished. + * @see B. Beeton, A. Freytag, M. Sargent III, Unicode support for + * mathematics, Unicode Technical Report #25 + * @author Yue Shi Lai + * @version 1.0 + */ + class math_text_renderer_t { + public: + enum { + DIRECTION_LEFT_TO_RIGHT = 0, + DIRECTION_RIGHT_TO_LEFT, + DIRECTION_TOP_TO_BOTTOM + }; + enum { + MATH_STYLE_LATIN = 0, + MATH_STYLE_MAGHREB + }; + enum { + FAMILY_PLAIN = 0, + FAMILY_REGULAR, + FAMILY_ITALIC, + FAMILY_BOLD, + FAMILY_BOLD_ITALIC, + FAMILY_STIX_REGULAR, + FAMILY_STIX_ITALIC, + FAMILY_STIX_BOLD, + FAMILY_STIX_BOLD_ITALIC, + FAMILY_STIX_SIZE_1_REGULAR, + FAMILY_STIX_SIZE_1_BOLD, + FAMILY_STIX_SIZE_2_REGULAR, + FAMILY_STIX_SIZE_2_BOLD, + FAMILY_STIX_SIZE_3_REGULAR, + FAMILY_STIX_SIZE_3_BOLD, + FAMILY_STIX_SIZE_4_REGULAR, + FAMILY_STIX_SIZE_4_BOLD, + FAMILY_STIX_SIZE_5_REGULAR, + NFAMILY + }; + private: + ///////////////////////////////////////////////////////////// + // Font parameter + static const float script_ratio; + static const float script_script_ratio; + static const float thin_mu_skip; + static const float med_mu_skip; + static const float thick_mu_skip; + static const float delimiter_factor; + static const float delimiter_shortfall; + ///////////////////////////////////////////////////////////// + static const float num_1; + static const float num_2; + static const float num_3; + static const float denom_1; + static const float denom_2; + static const float sup_1; + static const float sup_2; + static const float sup_3; + static const float sub_1; + static const float sub_2; + static const float sup_drop; + static const float sub_drop; + static const float delim_1; + static const float delim_2; + static const float axis_height; + static const float default_rule_thickness; + static const float big_op_spacing_1; + static const float big_op_spacing_2; + static const float big_op_spacing_3; + static const float big_op_spacing_4; + static const float big_op_spacing_5; + ///////////////////////////////////////////////////////////// + static const float radical_rule_thickness; + static const float large_operator_display_scale; + ///////////////////////////////////////////////////////////// + static const float baselineskip_factor; + ///////////////////////////////////////////////////////////// + // Token + class math_token_t { + public: + point_t _offset; + bounding_box_t _bounding_box; + union { + unsigned int _style; + struct { + wchar_t _glyph; + unsigned int _family; + float _size; + } _extensible; + }; + float _delimiter_height; + inline math_token_t( + const bounding_box_t bounding_box, + const unsigned int style, + const float delimiter_height = 0.0F) + : _offset(0, 0), _bounding_box(bounding_box), + _style(style), _delimiter_height(delimiter_height) + { + } + inline math_token_t( + const point_t offset, + const bounding_box_t bounding_box, + const unsigned int style, + const float delimiter_height = 0.0F) + : _offset(offset), _bounding_box(bounding_box), + _style(style), _delimiter_height(delimiter_height) + { + } + inline math_token_t( + const bounding_box_t bounding_box, + const wchar_t glyph, const unsigned int family, + const float size) + : _offset(0, 0), _bounding_box(bounding_box), + _delimiter_height(0.0F) + { + _extensible._glyph = glyph; + _extensible._family = family; + _extensible._size = size; + } + inline math_token_t( + const point_t offset, + const bounding_box_t bounding_box, + const wchar_t glyph, const unsigned int family, + const float size) + : _offset(offset), _bounding_box(bounding_box), + _delimiter_height(0.0F) + { + _extensible._glyph = glyph; + _extensible._family = family; + _extensible._size = size; + } + }; + ///////////////////////////////////////////////////////////// + // Style test and change + float style_size(const unsigned int style) const; + bool is_display_style(const unsigned int style) const; + bool is_script_style(const unsigned int style) const; + unsigned int prime_style(const unsigned int style) const; + bool is_prime_style(const unsigned int style) const; + template + inline value_t + if_else_display(const unsigned int style, + const value_t display_value, + const value_t otherwise_value) const + { + switch (style) { + case math_text_t::item_t::STYLE_DISPLAY: + case math_text_t::item_t::STYLE_DISPLAY_PRIME: + return display_value; + default: + return otherwise_value; + } + } + unsigned int next_superscript_style(const unsigned int style) + const; + unsigned int next_subscript_style(const unsigned int style) + const; + unsigned int next_numerator_style(const unsigned int style) + const; + unsigned int next_denominator_style(const unsigned int style) + const; + ///////////////////////////////////////////////////////////// + float x_height(const unsigned int style); + float quad(const unsigned int style) const; + unsigned int + math_family(const math_text_t::math_symbol_t &math_symbol) + const; + void post_process_atom_type_initial(unsigned int &atom_type) + const; + void post_process_atom_type_interior( + unsigned int &previous_atom_type, + unsigned int &atom_type) + const; + bool valid_accent( + bool &vertical_alignment, + const std::vector::const_iterator & + iterator, + const std::vector::const_iterator & + math_list_end) const; + float kerning_mu(float amount) const; + float math_spacing( + unsigned int left_type, unsigned int right_type, + unsigned int style) const; + protected: + virtual affine_transform_t + transform_logical_to_pixel(void) const = 0; + virtual affine_transform_t + transform_pixel_to_logical(void) const = 0; + ///////////////////////////////////////////////////////////// + // Box rendering + bounding_box_t math_bounding_box( + const math_text_t::box_t &box, const unsigned int style); + void math_text( + const point_t origin, const math_text_t::box_t &box, + const unsigned int style, const bool render_structure); + ///////////////////////////////////////////////////////////// + // Symbol rendering + static bool is_wgl_4(const wchar_t c); + static bool is_left_to_right(const wchar_t c); + static bool is_right_to_left(const wchar_t c); + static bool is_top_to_bottom(const wchar_t c); + static bool is_cyrillic(const wchar_t c); + static bool is_cjk(const wchar_t c); + static bool is_cjk_punctuation_open(const wchar_t c); + static bool is_cjk_punctuation_closed(const wchar_t c); + bounding_box_t math_bounding_box( + const wchar_t &glyph, const unsigned int family, + const float size); + void math_text( + const point_t origin, const wchar_t &glyph, + const unsigned int family, const float size, + const bool render_structure); + bounding_box_t math_bounding_box( + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style); + void math_text( + const point_t origin, + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const bool render_structure); + ///////////////////////////////////////////////////////////// + // Extensible glyph rendering + void large_family( + unsigned long &nfamily, const unsigned int *&family, + const math_text_t::math_symbol_t &math_symbol) const; + void extensible_glyph( + wchar_t glyph[4], unsigned long &nrepeat, + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height); + std::vector math_tokenize( + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height); + bounding_box_t math_bounding_box( + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height); + void math_text( + const point_t origin, + const math_text_t::math_symbol_t &math_symbol, + const unsigned int style, const float height, + const bool render_structure); + ///////////////////////////////////////////////////////////// + // Math list rendering + std::vector math_tokenize( + const std::vector::const_iterator & + math_list_begin, + const std::vector::const_iterator & + math_list_end, + unsigned int style); + bounding_box_t math_bounding_box( + const std::vector::const_iterator & + math_list_begin, + const std::vector::const_iterator & + math_list_end, + unsigned int style); + void math_text( + const point_t origin, + const std::vector::const_iterator & + math_list_begin, + const std::vector::const_iterator & + math_list_end, + const unsigned int style, const bool render_structure); + ///////////////////////////////////////////////////////////// + // Field rendering + bounding_box_t math_bounding_box( + const math_text_t::field_t &field, + const unsigned int style); + void math_text( + const point_t origin, const math_text_t::field_t &field, + const unsigned int style, const bool render_structure); + ///////////////////////////////////////////////////////////// + // Atom rendering + std::vector math_tokenize( + const math_text_t::atom_t &atom, unsigned int style); + bounding_box_t math_bounding_box( + const math_text_t::atom_t &atom, + const unsigned int style); + void math_text( + const point_t origin, const math_text_t::atom_t &atom, + const unsigned int style, const bool render_structure); + ///////////////////////////////////////////////////////////// + public: + ///////////////////////////////////////////////////////////// + // Constructor and destructor + inline math_text_renderer_t(void) + { + } + inline virtual ~math_text_renderer_t(void) + { + } + ///////////////////////////////////////////////////////////// + // Virtual functions + virtual float font_size( + const unsigned int family = FAMILY_PLAIN) const = 0; + virtual void set_font_size( + const float size, const unsigned int family) = 0; + virtual void set_font_size(const float size) = 0; + virtual void reset_font_size( + const unsigned int family) = 0; + virtual void point(const float x, const float y) = 0; + virtual void filled_rectangle( + const bounding_box_t &bounding_box) = 0; + virtual void rectangle( + const bounding_box_t &bounding_box) = 0; + virtual bounding_box_t bounding_box( + const std::wstring string, + const unsigned int family = FAMILY_PLAIN) = 0; + virtual void text_raw( + const float x, const float y, const std::wstring string, + const unsigned int family = FAMILY_PLAIN) = 0; + virtual void text_with_bounding_box( + const float x, const float y, const std::wstring string, + const unsigned int family = FAMILY_PLAIN) = 0; + ///////////////////////////////////////////////////////////// + // Interface + bounding_box_t bounding_box( + const math_text_t &math_text, + const bool display_style = false); + void text( + const float x, const float y, + const math_text_t &math_text, + const bool display_style = false); + ///////////////////////////////////////////////////////////// + inline float default_axis_height( + const bool display_style = false) const + { + (void)display_style; // unused var + return axis_height * style_size( + math_text_t::item_t::STYLE_TEXT); + } + ///////////////////////////////////////////////////////////// + }; +#ifdef __INTEL_COMPILER +#pragma warning(pop) +#endif // __INTEL_COMPILER + +} + +#endif // MATHRENDER_H_ diff --git a/builtins/libmathtext/mathtext/mathtext.h b/builtins/libmathtext/mathtext/mathtext.h new file mode 100644 index 0000000000000..88625eb455214 --- /dev/null +++ b/builtins/libmathtext/mathtext/mathtext.h @@ -0,0 +1,512 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#ifndef MATHTEXT_H_ +#define MATHTEXT_H_ + +#include + +namespace mathtext { + + class surface_t; + + /** + * Hierarchical representation of mathematical formulae + * + * The class math_text_t is a hierarchical representation of + * mathematical formulae similar to TeX's math list. + * + * Limitations: + * + * - Only (spacing) symbols and combining diacritical marks from + * TeX, AMS-TeX, LaTeX, AMS-LaTeX, and MathTime Professional II + * that are representable within ISO/IEC 10646:2003/Amd.2:2006 + * Universal Character Set can be accessed. + * + * - Illegal TeX syntax may result in not well defined behaviors. + * Most notably, `a^b^c' or `a_b_c' result in `a^c' and `a_c', + * i.e. the overwriting of the previous superscripts and + * subscripts, and `a \atop b \atop c' or `a \over b \over c' + * result in `a \atop {b \atop c}' and `a \over {b \over c}', i.e. + * a right associative interpretation. + * + * @see ISO/IEC JTC1/SC2/WG2, ISO/IEC 10646:2003/Amd.2:2006 (ISO, + * Geneva, 2006). + * @see D. E. Knuth, The TeXbook (Addision-Wesley, Cambridge, MA, + * 1986). + * @see D. E. Knuth, The METAFONTbook (Addision-Wesley, Cambridge, + * MA, 1986). + * @see B. Beeton, A. Freytag, M. Sargent III, Unicode support for + * mathematics, Unicode Technical Report #25 + * @author Yue Shi Lai + * @version 1.0 + */ + class math_text_t { + private: + /** + * Mathematical symbol + * + * The class math_symbol_t represents all (spacing) symbols + * and combining diacritical marks representable within + * ISO/IEC 10646:2003/Amd.2:2006 Universal Character Set from + * TeX, AMS-TeX, LaTeX, AMS-LaTeX, and MathTime Professional + * II. + * + * @author Yue Shi Lai + * @version 1.0 + */ + class math_symbol_t { + public: + enum { + FAMILY_PLAIN = 0, + // Math fonts start + FAMILY_REGULAR, + FAMILY_ITALIC, + FAMILY_BOLD, + FAMILY_BOLD_ITALIC, + FAMILY_STIX_REGULAR, + FAMILY_STIX_ITALIC, + FAMILY_STIX_BOLD, + FAMILY_STIX_BOLD_ITALIC, + FAMILY_STIX_SIZE_1_REGULAR, + FAMILY_STIX_SIZE_1_BOLD, + FAMILY_STIX_SIZE_2_REGULAR, + FAMILY_STIX_SIZE_2_BOLD, + FAMILY_STIX_SIZE_3_REGULAR, + FAMILY_STIX_SIZE_3_BOLD, + FAMILY_STIX_SIZE_4_REGULAR, + FAMILY_STIX_SIZE_4_BOLD, + FAMILY_STIX_SIZE_5_REGULAR, + // Below are virtual fonts for bookkeeping and do not + // have to correspond to a physical font available in + // surface_t. + // + // TeX combined styles + FAMILY_MATH_ITALIC, + FAMILY_MATH_BOLD_ITALIC, + // Mathematical Alphanumerical Symbols, mostly in the + // Unicode range U+1D500 - U+1D5FF + FAMILY_MATH_SCRIPT_ITALIC, + FAMILY_MATH_SCRIPT_BOLD_ITALIC, + FAMILY_MATH_FRAKTUR_REGULAR, + FAMILY_MATH_FRAKTUR_BOLD, + FAMILY_MATH_BLACKBOARD_BOLD, + FAMILY_MATH_SANS_SERIF_REGULAR, + FAMILY_MATH_SANS_SERIF_ITALIC, + FAMILY_MATH_SANS_SERIF_BOLD, + FAMILY_MATH_SANS_SERIF_BOLD_ITALIC, + FAMILY_MATH_MONOSPACE, + NFAMILY + }; + private: + /** + * Sets any family that is mathematical italic into the + * upright variant of the same weight, thus preventing + * them from converted into the italic form in the final + * step. + * + * @see void math_italic_is_italic(void) + */ + void math_italic_is_upright(void); + /** + * Sets any family that is mathematical italic into the + * italic variant of the same weight, usually used in the + * final step to convert all remaining character in + * mathematical italic into the italic form. + * + * @see void math_italic_is_upright(void) + */ + void math_italic_is_italic(void); + void encode_character(void); + void encode_control_sequence(void); + void encode_math_blackboard_bold(void); + void encode_math_script_italic(void); + void encode_math_script_bold_italic(void); + void encode_math_fraktur_regular(void); + void encode_math_fraktur_bold(void); + void encode_math_sans_serif_regular(void); + void encode_math_sans_serif_italic(void); + void encode_math_sans_serif_bold(void); + void encode_math_sans_serif_bold_italic(void); + void encode_math_alpha(void); + void encode(void); + public: + std::string _code; + unsigned int _family; + wchar_t _glyph; + unsigned int _type; + inline math_symbol_t(void) + : _family(FAMILY_PLAIN), _type(atom_t::TYPE_UNKNOWN) + { + } + inline math_symbol_t(std::string code, wchar_t glyph, + const unsigned int family) + : _code(code), _family(family), _glyph(glyph), + _type(atom_t::TYPE_UNKNOWN) + { + } + inline math_symbol_t(std::string code, + const unsigned int family) + : _code(code), _family(family), _glyph(0), + _type(atom_t::TYPE_UNKNOWN) + { + encode(); + } + inline bool is_combining_diacritical(void) const + { + // ISO/IEC JTC1/SC2/WG2 (2003), Annex B, but without + // the additional characters from the list + return + (_glyph >= L'\u0300' && _glyph <= L'\u036f') || + (_glyph >= L'\u20d0' && _glyph <= L'\u20ff') || + (_glyph >= L'\ufe20' && _glyph <= L'\ufe2f'); + } + bool bold(void) const; + }; + /** + * (Horizontal) Box + * + * @author Yue Shi Lai + * @version 1.0 + */ + class box_t { + public: + bool _vertical; + std::wstring _string; + box_t(void) + { + } + box_t(std::wstring string) + : _vertical(false), _string(string) + { + } + }; + class atom_t; + class item_t; + /** + * Math field + * + * @author Yue Shi Lai + * @version 1.0 + */ + class field_t { + private: + void transform_script(void); + void append(const item_t &item); + void append(const field_t &field, const bool superscript, + const bool subscript); + void prepend(const unsigned int type, + const math_symbol_t &math_symbol); + void append(const unsigned int type, + const math_symbol_t &math_symbol, + const bool superscript, + const bool subscript); + void parse_math_list( + const std::vector &str_split, + const unsigned int default_family); + public: + enum { + // The explicit TYPE_EMPTY in TeX is represented here + // by an empty math list + TYPE_UNKNOWN = 0, + TYPE_MATH_SYMBOL, + TYPE_BOX, // unused + TYPE_MATH_LIST, + NTYPE + }; + unsigned int _type; + math_symbol_t _math_symbol; + box_t _box; + std::vector _math_list; + inline field_t(void) + : _type(TYPE_MATH_LIST) + { + // Empty math list == implicit TYPE_EMPTY + } + inline field_t(const math_symbol_t &math_symbol) + : _type(TYPE_MATH_SYMBOL), _math_symbol(math_symbol) + { + } + inline field_t(const box_t &box) + : _type(TYPE_BOX), _box(box) + { + } + inline field_t(const std::vector &math_list) + : _type(TYPE_MATH_LIST), _math_list(math_list) + { + } + field_t(const std::vector &str_split, + const unsigned int default_family); + field_t(const std::string &str_delimiter_left, + const std::vector &str_split, + const std::string &str_delimiter_right, + const unsigned int default_family); + inline bool empty(void) const + { + return _type == TYPE_MATH_LIST && _math_list.empty(); + } + bool generalized_fraction(void) const; + }; + /** + * Math atom + * + * @author Yue Shi Lai + * @version 1.0 + */ + class atom_t { + private: + void classify(void); + public: + // TeX's 13 types of math atom + enum { + TYPE_UNKNOWN = 0, + TYPE_ORD, + TYPE_OP, + TYPE_BIN, + TYPE_REL, + TYPE_OPEN, + TYPE_CLOSE, + TYPE_PUNCT, + TYPE_INNER, + TYPE_OVER, // not implemented + TYPE_UNDER, // not implemented + TYPE_ACC, + TYPE_RAD, + TYPE_VCENT, // unused + NTYPE + }; + enum { + LIMITS_UNKNOWN = 0, + LIMITS_LIMITS, + LIMITS_NOLIMITS, + LIMITS_DISPLAYLIMITS, + NLIMITS + }; + unsigned int _type; + // Fields + field_t _nucleus; + field_t _superscript; + field_t _subscript; + unsigned int _limits; + // Index the root with the radicand _nucleus, if _type == + // TYPE_RAD (while TeX uses absolute positioning for the + // index, it is not possible to represent it in an font + // independent way). + field_t _index; + inline atom_t(const unsigned int type, + const field_t &nucleus) + : _type(type), _nucleus(nucleus) + { + } + inline atom_t(const unsigned int type, + const field_t &nucleus, + const unsigned int limits) + : _type(type), _nucleus(nucleus), _limits(limits) + { + } + inline atom_t(const field_t &nucleus) + : _nucleus(nucleus) + { + classify(); + } + inline atom_t(const field_t &nucleus, + const field_t &superscript, + const field_t &subscript) + : _nucleus(nucleus), _superscript(superscript), + _subscript(subscript) + { + classify(); + } + /** + * Returns true if the atom is of type Acc, or if it is a + * math symbol and its character representation is a + * combining diacritical mark within the ISO/IEC + * 10646:2003/Amd.2:2006 Universal Character Set, and + * false otherwise. + * + * @return true if the atom is of type Acc, or if it is a + * math symbol and its character representation is a + * combining diacritical mark within the ISO/IEC + * 10646:2003/Amd.2:2006 Universal Character Set, and + * false otherwise + */ + bool is_combining_diacritical(void) const; + /** + * Returns the interelement spacing between the given left + * and right atom types, and whether the present style is + * script or scriptscript, with 0, 1, 2, and 3 + * representing no space, \thinkmuskip, \medmuskip, and + * \thickmuskip, respectively. + * + * TeX defaults to \thinkmuskip to 3 mu, \medmuskip to 4 + * mu, and \thickmuskip to 5 mu, with 1 mu being 1/18 + * quad. + * + * @param[in] left_type left (enum) atom type + * @param[in] right_type right (enum) atom type + * @return interelement spacing, with 0, 1, 2, and 3 + * representing no space, \thinkmuskip, \medmuskip, and + * \thickmuskip, respectively + */ + static unsigned int + spacing(const unsigned int left_type, + const unsigned int right_type, const bool script); + }; + /** + * Math item + * + * @author Yue Shi Lai + * @version 1.0 + */ + class item_t { + public: + // TeX's 9 types of math item + enum { + TYPE_UNKNOWN = 0, + TYPE_ATOM, // implemented + TYPE_HORIZONTAL, // unused + TYPE_VERTICAL, // unused + TYPE_GLOB_OR_GLUE, // unused + TYPE_KERN, // implemented + TYPE_STYLE_CHANGE, // not implemented + TYPE_GENERALIZED_FRACTION, // not implemented + TYPE_BOUNDARY, // implemented + TYPE_FOUR_WAY_CHOICE, // unused + NTYPE + }; + // TeX's 8 math styles + enum { + STYLE_UNKNOWN = 0, + STYLE_SCRIPT_SCRIPT_PRIME, + STYLE_SCRIPT_SCRIPT, + STYLE_SCRIPT_PRIME, + STYLE_SCRIPT, + STYLE_TEXT_PRIME, + STYLE_TEXT, + STYLE_DISPLAY_PRIME, + STYLE_DISPLAY, + NSTYLE + }; + // TeX's left and right math boundary + enum { + BOUNDARY_UNKNOWN = 0, + BOUNDARY_LEFT, + BOUNDARY_RIGHT, + NBOUNDARY + }; + unsigned int _type; + atom_t _atom; + float _length; + unsigned int _style_change; + unsigned int _boundary; + inline item_t(const unsigned int type, + const float length = 0) + : _type(type), _atom(field_t()), _length(length) + { + } + inline item_t(const atom_t &atom) + : _type(TYPE_ATOM), _atom(atom) + { + } + inline item_t(const unsigned int type, + const atom_t &atom) + : _type(type), _atom(atom) + { + } + bool operator==(const item_t &item) const; + }; + std::wstring _code; + field_t _math_list; + bool _render_structure; + ///////////////////////////////////////////////////////////// + void tree_view_prefix(const std::vector &branch, + const bool final) const; + void tree_view(const field_t &field, + std::vector &branch, const bool final) + const; + void tree_view(const item_t &item, std::vector &branch, + const bool final) const; + void tree_view(const atom_t &atom, std::vector &branch, + const bool final) const; + static std::wstring bad_cast(const std::string string); + static std::wstring utf8_cast(const std::string string); + ///////////////////////////////////////////////////////////// + static std::vector + tex_split(const std::string &raw_code, + const char escape_character = '\\'); + static std::vector + tex_replace(const std::vector &code); + field_t build_math_list(const std::vector & + code_split) const + { + return field_t(code_split, + math_symbol_t::FAMILY_MATH_ITALIC); + } + public: + math_text_t(void) + : _code(), _math_list(), _render_structure(false) + { + } + math_text_t(const std::string &code_string) + : _code(bad_cast(code_string)), _render_structure(false) + { + std::cerr << __FILE__ << ':' << __LINE__ << ": " << std::endl; + std::vector code_split = tex_split(code_string); + _math_list = build_math_list(code_split); + } + math_text_t(const char code_string[]) + : _code(bad_cast(code_string)), _render_structure(false) + { + std::vector code_split = tex_split(code_string); + _math_list = build_math_list(code_split); + } + inline std::wstring code(void) const + { + return _code; + } + inline bool render_structure(void) const + { + return _render_structure; + } + inline bool &render_structure(void) + { + return _render_structure; + } + bool well_formed(void) const; + inline bool empty(void) const + { + return _math_list.empty(); + } + inline void tree_view(void) const + { + std::vector branch; + + tree_view(_math_list, branch, true); + } + friend class math_text_renderer_t; + }; + + /** + * Returns the TeX-formatted scientific representation of a real + * number + */ + extern std::string tex_form(const double x); + +} + +#endif // MATHTEXT_H_ diff --git a/builtins/libmathtext/mathtextencode.cc b/builtins/libmathtext/mathtextencode.cc new file mode 100644 index 0000000000000..b73323da4a51b --- /dev/null +++ b/builtins/libmathtext/mathtextencode.cc @@ -0,0 +1,422 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + + ///////////////////////////////////////////////////////////////// + + // For the symbol classification, see Knuth, The TeXbook (1986), + // pp. 434ff. + + void math_text_t::math_symbol_t::math_italic_is_upright(void) + { + if (_family == FAMILY_MATH_ITALIC) { + _family = FAMILY_REGULAR; + } + else if (_family == FAMILY_MATH_BOLD_ITALIC) { + _family = FAMILY_BOLD; + } + } + + void math_text_t::math_symbol_t::math_italic_is_italic(void) + { + if (_family == FAMILY_MATH_ITALIC) { + _family = FAMILY_ITALIC; + } + else if (_family == FAMILY_MATH_BOLD_ITALIC) { + _family = FAMILY_BOLD_ITALIC; + } + } + + void math_text_t::math_symbol_t::encode_character(void) + { + if (_code.size() != 1) + return; + + // Character encoding for plain characters (not a TeX control + // sequence) + switch (_code[0]) { + case '|': + case '/': + case '.': + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_ORD; + break; + case '+': + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_BIN; + break; + case '-': + math_italic_is_upright(); + _glyph = L'\u2212'; + _type = atom_t::TYPE_BIN; + break; + case '*': + math_italic_is_upright(); + _glyph = L'\u2217'; + _type = atom_t::TYPE_BIN; + break; + case '<': + case '=': + case '>': + case ':': + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_REL; + break; + case '(': + case '[': + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_OPEN; + break; + case '!': + case '?': + case ')': + case ']': + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_CLOSE; + break; + case ',': + case ';': + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_PUNCT; + break; + default: + if ((_code[0] >= 'A' && _code[0] <= 'Z') || + (_code[0] >= 'a' && _code[0] <= 'z')) { + _glyph = _code[0]; + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= '0' && _code[0] <= '9') { + math_italic_is_upright(); + _glyph = _code[0]; + _type = atom_t::TYPE_ORD; + } + } + } + + void math_text_t::math_symbol_t::encode_control_sequence(void) + { + // Character encoding for TeX control sequences +#include "table/mathglyphstd.h" + const char **lower = + std::lower_bound(glyph_control_sequence, + glyph_control_sequence + nglyph, + _code); + + if (lower < glyph_control_sequence + nglyph && + *lower == _code) { + const unsigned long index = + lower - glyph_control_sequence; + + if (glyph_upright[index]) + math_italic_is_upright(); + _glyph = glyph_code_point[index]; + _type = glyph_type[index]; + } + } + + void math_text_t::math_symbol_t::encode_math_blackboard_bold(void) + { + if (_code.size() != 1) { + return; + } + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_REGULAR; + switch (_code[0]) { + case 'C': _glyph = L'\u2102'; break; + case 'H': _glyph = L'\u210d'; break; + case 'N': _glyph = L'\u2115'; break; + case 'P': _glyph = L'\u2119'; break; + case 'Q': _glyph = L'\u211a'; break; + case 'R': _glyph = L'\u211d'; break; + case 'Z': _glyph = L'\u2124'; break; + default: _glyph = L'\U0001d538' + (_code[0] - 'A'); + } + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_REGULAR; + _glyph = L'\U0001d552' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= '0' && _code[0] <= '9') { + _family = FAMILY_STIX_REGULAR; + _glyph = L'\U0001d7d8' + (_code[0] - '0'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t::encode_math_script_italic(void) + { + if (_code.size() != 1) { + return; + } + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_ITALIC; + switch (_code[0]) { + case 'H': _glyph = L'\u210b'; break; + case 'I': _glyph = L'\u2110'; break; + case 'L': _glyph = L'\u2112'; break; + case 'P': _glyph = L'\u2118'; break; + case 'R': _glyph = L'\u211b'; break; + case 'B': _glyph = L'\u212c'; break; + case 'E': _glyph = L'\u2130'; break; + case 'F': _glyph = L'\u2131'; break; + case 'M': _glyph = L'\u2133'; break; + default: _glyph = L'\U0001d49c' + (_code[0] - 'A'); + } + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_ITALIC; + switch (_code[0]) { + case 'g': _glyph = L'\u210a'; break; + case 'l': _glyph = L'\u2113'; break; + case 'e': _glyph = L'\u212f'; break; + case 'o': _glyph = L'\u2134'; break; + default: _glyph = L'\U0001d4b6' + (_code[0] - 'a'); + } + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t::encode_math_script_bold_italic(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_BOLD_ITALIC; + _glyph = L'\U0001d49c' + (_code[0] - 'A'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_BOLD_ITALIC; + _glyph = L'\U0001d4b6' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t::encode_math_fraktur_regular(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_REGULAR; + switch (_code[0]) { + case 'H': _glyph = L'\u210c'; break; + case 'I': _glyph = L'\u2111'; break; + case 'R': _glyph = L'\u211c'; break; + case 'Z': _glyph = L'\u2128'; break; + case 'C': _glyph = L'\u212d'; break; + default: _glyph = L'\U0001d504' + (_code[0] - 'A'); + } + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_REGULAR; + _glyph = L'\U0001d51e' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t::encode_math_fraktur_bold(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_BOLD; + _glyph = L'\U0001d56c' + (_code[0] - 'A'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_BOLD; + _glyph = L'\U0001d586' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t:: + encode_math_sans_serif_regular(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_REGULAR; + _glyph = L'\U0001d5a0' + (_code[0] - 'A'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_REGULAR; + _glyph = L'\U0001d5ba' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= '0' && _code[0] <= '9') { + _family = FAMILY_STIX_REGULAR; + _glyph = L'\U0001d7e2' + (_code[0] - '0'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t:: + encode_math_sans_serif_italic(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_ITALIC; + _glyph = L'\U0001d608' + (_code[0] - 'A'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_ITALIC; + _glyph = L'\U0001d622' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t:: + encode_math_sans_serif_bold(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_BOLD; + _glyph = L'\U0001d5d4' + (_code[0] - 'A'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_BOLD; + _glyph = L'\U0001d5ee' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= '0' && _code[0] <= '9') { + _family = FAMILY_STIX_BOLD; + _glyph = L'\U0001d7ec' + (_code[0] - '0'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t:: + encode_math_sans_serif_bold_italic(void) + { + if (_code.size() != 1) + return; + + if (_code[0] >= 'A' && _code[0] <= 'Z') { + _family = FAMILY_STIX_BOLD_ITALIC; + _glyph = L'\U0001d63c' + (_code[0] - 'A'); + _type = atom_t::TYPE_ORD; + } + else if (_code[0] >= 'a' && _code[0] <= 'z') { + _family = FAMILY_STIX_BOLD_ITALIC; + _glyph = L'\U0001d656' + (_code[0] - 'a'); + _type = atom_t::TYPE_ORD; + } + } + + void math_text_t::math_symbol_t::encode_math_alpha(void) + { + switch (_family) { + case FAMILY_MATH_BLACKBOARD_BOLD: + encode_math_blackboard_bold(); + break; + case FAMILY_MATH_SCRIPT_ITALIC: + encode_math_script_italic(); + break; + case FAMILY_MATH_SCRIPT_BOLD_ITALIC: + encode_math_script_bold_italic(); + break; + case FAMILY_MATH_FRAKTUR_REGULAR: + encode_math_fraktur_regular(); + break; + case FAMILY_MATH_FRAKTUR_BOLD: + encode_math_fraktur_bold(); + break; + case FAMILY_MATH_SANS_SERIF_REGULAR: + encode_math_sans_serif_regular(); + break; + case FAMILY_MATH_SANS_SERIF_ITALIC: + encode_math_sans_serif_italic(); + break; + case FAMILY_MATH_SANS_SERIF_BOLD: + encode_math_sans_serif_bold(); + break; + case FAMILY_MATH_SANS_SERIF_BOLD_ITALIC: + encode_math_sans_serif_bold_italic(); + break; + } + } + + void math_text_t::math_symbol_t::encode(void) + { + encode_character(); + encode_control_sequence(); + encode_math_alpha(); + math_italic_is_italic(); + if (_family > FAMILY_STIX_SIZE_5_REGULAR) { + std::cerr << __FILE__ << ':' << __LINE__ + << ": error: encoding results in a " + "nonphysical font family" << std::endl; + } + } + + bool math_text_t::math_symbol_t::bold(void) const + { + switch (_family) { + case FAMILY_BOLD: + case FAMILY_BOLD_ITALIC: + case FAMILY_STIX_BOLD: + case FAMILY_STIX_BOLD_ITALIC: + case FAMILY_STIX_SIZE_1_BOLD: + case FAMILY_STIX_SIZE_2_BOLD: + case FAMILY_STIX_SIZE_3_BOLD: + case FAMILY_STIX_SIZE_4_BOLD: + case FAMILY_MATH_BOLD_ITALIC: + case FAMILY_MATH_SCRIPT_BOLD_ITALIC: + case FAMILY_MATH_FRAKTUR_BOLD: + case FAMILY_MATH_BLACKBOARD_BOLD: + case FAMILY_MATH_SANS_SERIF_BOLD: + case FAMILY_MATH_SANS_SERIF_BOLD_ITALIC: + return true; + default: + return false; + } + } + +} diff --git a/builtins/libmathtext/mathtextparse.cc b/builtins/libmathtext/mathtextparse.cc new file mode 100644 index 0000000000000..9866f5a80f8fb --- /dev/null +++ b/builtins/libmathtext/mathtextparse.cc @@ -0,0 +1,457 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + + ///////////////////////////////////////////////////////////////// + + void math_text_t::field_t:: + parse_math_list(const std::vector &str_split, + const unsigned int default_family) + { +#if 0 + std::cerr << "parsing ["; + for (std::vector::const_iterator iterator = + str_split.begin(); + iterator != str_split.end(); iterator++) + std::cerr << '"' << *iterator << "\", "; + std::cerr << ']' << std::endl; +#endif + + // State of radical parsing + enum { + RADICAL_STATE_NONE = 0, + RADICAL_STATE_RADICAND, + RADICAL_STATE_OF, + RADICAL_STATE_INDEX + }; + + unsigned int family = default_family; + int level = 0; + int delimiter_level = 0; + std::vector buffer; +#if 1 + bool superscript = false; + bool subscript = false; + bool delimiter_right = false; + unsigned int radical_state = RADICAL_STATE_NONE; + std::vector radical_index; + bool horizontal_box = false; + + for (std::vector::const_iterator iterator = + str_split.begin(); + iterator != str_split.end(); iterator++) { + // ONLY LEVEL 0 superscript and subscript are interpreted, + // and they are ignored afterwards. + if (level == 0 && delimiter_level == 0) { + if ((*iterator)[0] == '^') { + superscript = true; + continue; + } + else if ((*iterator)[0] == '_') { + subscript = true; + continue; + } + else if (*iterator == "\\sqrt") { + radical_state = RADICAL_STATE_RADICAND; + radical_index = std::vector(); + continue; + } + else if (iterator->substr(0, 5) == "\\root") { + radical_state = RADICAL_STATE_INDEX; + continue; + } + else if (radical_state == RADICAL_STATE_INDEX && + *iterator == "\\of") { + radical_index = buffer; + buffer.clear(); + radical_state = RADICAL_STATE_RADICAND; + continue; + } + else if (iterator->substr(0, 5) == "\\hbox" || + iterator->substr(0, 5) == "\\text") { + horizontal_box = true; + continue; + } + + const char **lower; + +#include "table/mathfontch.h" + lower = std::lower_bound( + font_change_control_sequence, + font_change_control_sequence + nfont_change, + *iterator); + + if (lower < + font_change_control_sequence + nfont_change && + *lower == *iterator) { + const unsigned long index = + lower - font_change_control_sequence; + + family = font_change_family[index]; + continue; + } +#include "table/mathopstd.h" + lower = std::lower_bound( + operator_control_sequence, + operator_control_sequence + noperator, + *iterator); + if (lower < + operator_control_sequence + noperator && + *lower == *iterator) { + const unsigned long index = + lower - operator_control_sequence; + + if (operator_code_point[index] == L'\0') { + // Operator defined with \mathop + const field_t operator_math_list(field_t( + tex_split(operator_content[index]), + math_symbol_t::FAMILY_REGULAR)); + atom_t atom(atom_t::TYPE_OP, field_t( + operator_math_list)); + + atom._limits = operator_nolimits[index] ? + atom_t::LIMITS_NOLIMITS : + atom_t::LIMITS_DISPLAYLIMITS; + append(atom); + } + else { + // Operator defined with \mathchardef + const field_t operator_math_symbol( + math_symbol_t( + *iterator, + operator_code_point[index], + math_symbol_t::FAMILY_REGULAR)); + atom_t atom(atom_t::TYPE_OP, field_t( + operator_math_symbol)); + + atom._limits = operator_nolimits[index] ? + atom_t::LIMITS_NOLIMITS : + atom_t::LIMITS_DISPLAYLIMITS; + append(atom); + } + continue; + } + } + + if ((*iterator)[0] == '}') { + level--; + // When the level decreases to 0 here, the compound + // expression is complete, create a subfield and + // append it to the math list. + if (level == 0 && delimiter_level == 0) { + // Create subfields recursively + const field_t subfield(buffer, family); + + if (radical_state == RADICAL_STATE_RADICAND) { + atom_t atom(atom_t::TYPE_RAD, subfield); + + atom._index = field_t(radical_index, family); + append(item_t(atom)); + radical_state = RADICAL_STATE_NONE; + } + else + append(subfield, superscript, subscript); + buffer.clear(); + } + } + else if (*iterator == "\\right") { + delimiter_level--; + // When the delimtier level decreases to 0 here, the + // compound expression is complete, create a subfield + // and append it with the appropriate delimiter atoms + // to the math list. + if (level == 0 && delimiter_level == 0) { + delimiter_right = true; + continue; + } + } + + ///////////////////////////////////////////////////////// + +#if 0 + std::cerr << __FILE__ << ':' << __LINE__ + << ": L" << level << ", DL" + << delimiter_level << ", hbox = " + << horizontal_box << ", *iterator = " + << *iterator << std::endl; +#endif + + if (level > 0 || delimiter_level > 0 || + radical_state == RADICAL_STATE_INDEX) { + buffer.push_back(*iterator); + } + else if (delimiter_right) { + const std::string left = buffer.front(); + + buffer.erase(buffer.begin()); + + const field_t subfield(left, buffer, *iterator, + family); + + if (radical_state == RADICAL_STATE_RADICAND) { + atom_t atom(atom_t::TYPE_RAD, subfield); + + atom._index = field_t(radical_index, family); + append(item_t(atom)); + radical_state = RADICAL_STATE_NONE; + } + else + append(subfield, superscript, subscript); + buffer.clear(); + } + else if (horizontal_box) { + box_t box(math_text_t::utf8_cast(*iterator)); + + append(field_t(box), superscript, subscript); + } + else if ((*iterator)[0] != '{' && + (*iterator)[0] != '}' && + *iterator != "\\left" && + *iterator != "\\right") { + if (radical_state == RADICAL_STATE_RADICAND) { + const field_t subfield( + std::vector(1, *iterator), + family); + atom_t atom(atom_t::TYPE_RAD, subfield); + + atom._index = field_t(radical_index, family); + append(item_t(atom)); + } + // FIXME: This should be a true table + else if (*iterator == "\\over") { + append(item_t(item_t::TYPE_GENERALIZED_FRACTION, + 1.0F)); + } + else if (*iterator == "\\atop") { + append(item_t(item_t::TYPE_GENERALIZED_FRACTION, + 0.0F)); + } + // FIXME: This should be a true table + else if (*iterator == "\\!") { + append(item_t(item_t::TYPE_KERN, -3.0F)); + } + else if (*iterator == "\\,") { + append(item_t(item_t::TYPE_KERN, 3.0F)); + } + else if (*iterator == "\\:") { + append(item_t(item_t::TYPE_KERN, 4.0F)); + } + else if (*iterator == "\\;") { + append(item_t(item_t::TYPE_KERN, 5.0F)); + } + else if (*iterator == "\\quad") { + append(item_t(item_t::TYPE_KERN, 18.0F)); + } + else if (*iterator == "\\qquad") { + append(item_t(item_t::TYPE_KERN, 36.0F)); + } + else { + const math_symbol_t + math_symbol(*iterator, family); + + append(item_t::TYPE_ATOM, math_symbol, + superscript, subscript); + } + } + + if ((*iterator)[0] == '{') { + level++; + } + else if (*iterator == "\\left") { + // Since the actual delimiter follows, it is going to + // be appended to the buffer "automatically". + delimiter_level++; + } + // Reset superscript and subscript flags only for level 0 + if (level == 0 && delimiter_level == 0 && + (radical_state == RADICAL_STATE_RADICAND || + radical_state == RADICAL_STATE_NONE)) { + superscript = false; + subscript = false; + delimiter_right = false; + radical_state = RADICAL_STATE_NONE; + family = default_family; + horizontal_box = false; + } + } +#else + for (std::vector::const_iterator iterator = + str_split.begin(); + iterator != str_split.end(); iterator++) { + if ((*iterator)[0] == '}') { + level--; + + } + else if (*iterator == "\\right") { + delimiter_level--; + } + if ((*iterator)[0] == '{') { + level++; + } + else if (*iterator == "\\left") { + // Since the actual delimiter follows, it is going to + // be appended to the buffer "automatically". + delimiter_level++; + } + else if (level == 0 && delimiter_level == 0) { +#if 1 + std::cerr << __FILE__ << ':' << __LINE__ + << ": L" << level << ", DL" + << delimiter_level << ", *iterator = " + << *iterator << ", buffer = { "; + for (std::vector::const_iterator + buffer_iterator = buffer.begin(); + buffer_iterator != buffer.end(); buffer_iterator++) { + std::cerr << '"' << *buffer_iterator << "\" "; + } + std::cerr << '}' << std::endl; +#endif + buffer.clear(); + } + else { + buffer.push_back(*iterator); + } + } +#endif + } + + std::vector math_text_t:: + tex_split(const std::string &raw_code, const char escape_character) + { + std::string code = raw_code; + + for (std::string::iterator iterator = code.begin(); + iterator != code.end(); iterator++) { + if (*iterator == escape_character) { + *iterator = '\\'; + } + } + + std::vector ret; + + if (code.size() <= 0) { + return ret; + } + + size_t begin = 0; + size_t end = 1; + bool box = false; + + while (code[begin] == ' ') { + begin++; + } + while (begin < code.size()) { + end = begin + 1; + if (code[begin] == '\\') { + if (isalpha(code[end])) { + while (end < code.size() && isalpha(code[end])) { + end++; + } + } + else if (end < code.size()) { + end++; + } + +#include "table/mathbracketcs.h" + const char **lower = + std::lower_bound(bracket_control_sequence, + bracket_control_sequence + + nbracket_control_sequence, + code.substr(begin, + end - begin)); + + if (lower < bracket_control_sequence + + nbracket_control_sequence && + *lower == code.substr(begin, end - begin) && + end + 1 < code.size() && code[end] == '[') { + while (end < code.size() && code[end] != ']') { + end++; + } + if (end < code.size()) { + end++; + } + } + } + + std::string code_substr = + code.substr(begin, end - begin); + +#if 1 + if (code_substr == "\\hbox" || code_substr == "\\text") { + box = true; + } + else if (box) { + if (code[begin] == '{') { + for (unsigned int level = 1; + end < code.size() && level > 0; end++) { + if (code[end - 1] != '\\') { + switch (code[end]) { + case '{': level++; break; + case '}': level--; break; + } + } + } + code_substr = + code.substr(begin + 1, end - begin - 2); + } + else if (code[begin] == '\\' && + begin + 1 < code.size()) { + code_substr = code.substr(begin, 2); + } + else { + code_substr = code.substr(begin, 1); + } + // FIXME: Proper interpretation of escaped characters + box = false; + } +#endif + + ret.push_back(code_substr); + begin = end; + while (code[begin] == ' ') { + begin++; + } + } + + return ret; + } + + std::vector math_text_t:: + tex_replace(const std::vector &/*code*/) + { +#if 0 + static const size_t ncontrol_max = 256; + static const char *table[][ncontrol_max] = { + { "\\%", "\0", "\\root", "\1", "\\of", "\2", NULL }, + { "\\sqrt", "[]", "\1", "\\root", "\1", "\\of", "\2", NULL }, + { "\\frac", "\2", "{", "\1", "\\over", "\2", "}", NULL } + }; +#endif + + return std::vector(); + } + +} diff --git a/builtins/libmathtext/mathtextview.cc b/builtins/libmathtext/mathtextview.cc new file mode 100644 index 0000000000000..6780d5d0a9b84 --- /dev/null +++ b/builtins/libmathtext/mathtextview.cc @@ -0,0 +1,234 @@ +// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) +// 2008-2012 Yue Shi Lai +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public License +// as published by the Free Software Foundation; either version 2.1 of +// the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +// 02110-1301 USA + +#include +#include +#include + +///////////////////////////////////////////////////////////////////// + +namespace mathtext { + + ///////////////////////////////////////////////////////////////// + + void math_text_t:: + tree_view_prefix(const std::vector &branch, + const bool final) const + { + if (branch.size() > 0) { + std::cerr << ' '; + for (std::vector::const_iterator iterator = + branch.begin(); + iterator != branch.end(); iterator++) { + if (*iterator) { + if (iterator + 1 == branch.end()) { + if (final) + std::cerr << "\342\224\224\342\224\200 "; + else + std::cerr << "\342\224\234\342\224\200 "; + } + else + std::cerr << "\342\224\202 "; + } + else + if (iterator + 1 == branch.end()) + std::cerr << " "; + else + std::cerr << " "; + } + } + } + + void math_text_t::tree_view(const field_t &field, + std::vector &branch, + const bool final) const + { + switch (field._type) { + case field_t::TYPE_MATH_SYMBOL: + tree_view_prefix(branch, true); + std::cerr << "" << std::endl; + break; + case field_t::TYPE_BOX: + tree_view_prefix(branch, true); + std::cerr << "" << std::endl; + break; + case field_t::TYPE_MATH_LIST: + if (field._math_list.empty()) { + tree_view_prefix(branch, true); + std::cerr << "" << std::endl; + } + else { + tree_view_prefix(branch, false); + std::cerr << "" << std::endl; + + std::vector branch_copy = branch; + + branch_copy.back() = !final; + for (std::vector::const_iterator iterator = + field._math_list.begin(); + iterator != field._math_list.end(); iterator++) { + branch_copy.back() = !final; + branch_copy.push_back(true); + tree_view(*iterator, branch_copy, + iterator + 1 == field._math_list.end()); + branch_copy.pop_back(); + } + branch_copy.back() = !final; + tree_view_prefix(branch_copy, true); + std::cerr << "" << std::endl; + } + break; + default: + tree_view_prefix(branch, true); + std::cerr << "" << std::endl; + } + } + + void math_text_t::tree_view(const item_t &item, + std::vector &branch, + const bool final) const + { + std::vector branch_copy = branch; + + switch (item._type) { + case item_t::TYPE_ATOM: + tree_view_prefix(branch, final); + std::cerr << "" << std::endl; + branch_copy.back() = !final; + branch_copy.push_back(true); + tree_view(item._atom, branch_copy, final); + branch_copy.pop_back(); + tree_view_prefix(branch_copy, final); + std::cerr << "" << std::endl; + break; + case item_t::TYPE_BOUNDARY: + tree_view_prefix(branch, final); + std::cerr << "" << std::endl; + branch_copy.back() = !final; + branch_copy.push_back(true); + tree_view(item._atom, branch_copy, final); + branch_copy.pop_back(); + tree_view_prefix(branch_copy, final); + std::cerr << "" << std::endl; + break; + case item_t::TYPE_GENERALIZED_FRACTION: + tree_view_prefix(branch, final); + std::cerr << "" << std::endl; + break; + default: + tree_view_prefix(branch, final); + std::cerr << "" << std::endl; + } + } + + void math_text_t::tree_view(const atom_t &atom, + std::vector &branch, + const bool final) const + { + tree_view_prefix(branch, false); + std::cerr << ""; + switch (atom._type) { + case atom_t::TYPE_ORD: + std::cerr << "Ord"; + break; + case atom_t::TYPE_OP: + std::cerr << "Op"; + break; + case atom_t::TYPE_BIN: + std::cerr << "Bin"; + break; + case atom_t::TYPE_REL: + std::cerr << "Rel"; + break; + case atom_t::TYPE_OPEN: + std::cerr << "Open"; + break; + case atom_t::TYPE_CLOSE: + std::cerr << "Close"; + break; + case atom_t::TYPE_PUNCT: + std::cerr << "Punct"; + break; + case atom_t::TYPE_INNER: + std::cerr << "Inner"; + break; + case atom_t::TYPE_OVER: + std::cerr << "Over"; + break; + case atom_t::TYPE_UNDER: + std::cerr << "Under"; + break; + case atom_t::TYPE_ACC: + std::cerr << "Acc"; + break; + case atom_t::TYPE_RAD: + std::cerr << "Rad"; + break; + case atom_t::TYPE_VCENT: + std::cerr << "Vcent"; + break; + default: + std::cerr << "??" << atom._type; + break; + } + std::cerr << "" << std::endl; + + std::vector branch_copy = branch; + + if (!atom._nucleus.empty()) { + const bool way_final = atom._superscript.empty() && + atom._subscript.empty(); + + tree_view_prefix(branch, way_final); + std::cerr << "" << std::endl; + branch_copy.back() = !way_final; + branch_copy.push_back(true); + tree_view(atom._nucleus, branch_copy, final); + branch_copy.pop_back(); + tree_view_prefix(branch_copy, way_final); + std::cerr << "" << std::endl; + } + if (!atom._superscript.empty()) { + const bool way_final = atom._subscript.empty(); + + tree_view_prefix(branch, way_final); + std::cerr << "" << std::endl; + branch_copy.back() = !way_final; + branch_copy.push_back(true); + tree_view(atom._superscript, branch_copy, final); + branch_copy.pop_back(); + tree_view_prefix(branch_copy, way_final); + std::cerr << "" << std::endl; + } + if (!atom._subscript.empty()) { + tree_view_prefix(branch, true); + std::cerr << "" << std::endl; + branch_copy.back() = false; + branch_copy.push_back(true); + tree_view(atom._subscript, branch_copy, final); + branch_copy.pop_back(); + tree_view_prefix(branch_copy, true); + std::cerr << "" << std::endl; + } + } + +} diff --git a/graf2d/mathtext/src/table/adobeglyphlist.h b/builtins/libmathtext/table/adobeglyphlist.h similarity index 100% rename from graf2d/mathtext/src/table/adobeglyphlist.h rename to builtins/libmathtext/table/adobeglyphlist.h diff --git a/builtins/libmathtext/table/cffstdstr.h b/builtins/libmathtext/table/cffstdstr.h new file mode 100644 index 0000000000000..c4eaff6d4c5fb --- /dev/null +++ b/builtins/libmathtext/table/cffstdstr.h @@ -0,0 +1,79 @@ +static const size_t ncff_standard_string = 391; +static const char *cff_standard_string[ncff_standard_string] = { + ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", + "percent", "ampersand", "quoteright", "parenleft", "parenright", + "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", + "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "colon", "semicolon", "less", "equal", "greater", + "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", + "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", + "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", + "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", + "braceright", "asciitilde", "exclamdown", "cent", "sterling", + "fraction", "yen", "florin", "section", "currency", "quotesingle", + "quotedblleft", "guillemotleft", "guilsinglleft", + "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", + "periodcentered", "paragraph", "bullet", "quotesinglbase", + "quotedblbase", "quotedblright", "guillemotright", "ellipsis", + "perthousand", "questiondown", "grave", "acute", "circumflex", + "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", + "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", + "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", + "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", + "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", + "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", + "threequarters", "twosuperior", "registered", "minus", "eth", + "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", + "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", + "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", + "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", + "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", + "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", + "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", + "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", + "egrave", "iacute", "icircumflex", "idieresis", "igrave", + "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", + "otilde", "scaron", "uacute", "ucircumflex", "udieresis", + "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", + "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", + "ampersandsmall", "Acutesmall", "parenleftsuperior", + "parenrightsuperior", "twodotenleader", "onedotenleader", + "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", + "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", + "eightoldstyle", "nineoldstyle", "commasuperior", + "threequartersemdash", "periodsuperior", "questionsmall", + "asuperior", "bsuperior", "centsuperior", "dsuperior", + "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", + "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", + "ffl", "parenleftinferior", "parenrightinferior", + "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", + "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", + "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", + "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", + "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", + "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", + "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", + "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", + "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", + "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", + "oneeighth", "threeeighths", "fiveeighths", "seveneighths", + "onethird", "twothirds", "zerosuperior", "foursuperior", + "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", + "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", + "threeinferior", "fourinferior", "fiveinferior", "sixinferior", + "seveninferior", "eightinferior", "nineinferior", "centinferior", + "dollarinferior", "periodinferior", "commainferior", + "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", + "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", + "Egravesmall", "Eacutesmall", "Ecircumflexsmall", + "Edieresissmall", "Igravesmall", "Iacutesmall", + "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", + "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", + "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", + "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", + "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", + "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", + "Medium", "Regular", "Roman", "Semibold" +}; diff --git a/graf2d/mathtext/src/table/macintoshordering.h b/builtins/libmathtext/table/macintoshordering.h similarity index 100% rename from graf2d/mathtext/src/table/macintoshordering.h rename to builtins/libmathtext/table/macintoshordering.h diff --git a/graf2d/mathtext/src/table/mathbracketcs.h b/builtins/libmathtext/table/mathbracketcs.h similarity index 100% rename from graf2d/mathtext/src/table/mathbracketcs.h rename to builtins/libmathtext/table/mathbracketcs.h diff --git a/graf2d/mathtext/src/table/mathfontch.h b/builtins/libmathtext/table/mathfontch.h similarity index 100% rename from graf2d/mathtext/src/table/mathfontch.h rename to builtins/libmathtext/table/mathfontch.h diff --git a/graf2d/mathtext/src/table/mathfontparam.h b/builtins/libmathtext/table/mathfontparam.h similarity index 99% rename from graf2d/mathtext/src/table/mathfontparam.h rename to builtins/libmathtext/table/mathfontparam.h index de3cf46244784..32ca9794b9888 100644 --- a/graf2d/mathtext/src/table/mathfontparam.h +++ b/builtins/libmathtext/table/mathfontparam.h @@ -68,7 +68,8 @@ const float math_text_renderer_t::big_op_spacing_5 = 0.111111F; ///////////////////////////////////////////////////////////////////// // Implicit TFM Font Parameters const float math_text_renderer_t::radical_rule_thickness = 0.054F; -const float math_text_renderer_t::large_operator_display_scale = 1.4F; +const float math_text_renderer_t::large_operator_display_scale = + 1.4F; ///////////////////////////////////////////////////////////////////// // Text Mode Parameters diff --git a/graf2d/mathtext/src/table/mathglyphstd.h b/builtins/libmathtext/table/mathglyphstd.h similarity index 100% rename from graf2d/mathtext/src/table/mathglyphstd.h rename to builtins/libmathtext/table/mathglyphstd.h diff --git a/graf2d/mathtext/src/table/mathopstd.h b/builtins/libmathtext/table/mathopstd.h similarity index 100% rename from graf2d/mathtext/src/table/mathopstd.h rename to builtins/libmathtext/table/mathopstd.h diff --git a/graf2d/mathtext/src/table/mathspacing.h b/builtins/libmathtext/table/mathspacing.h similarity index 100% rename from graf2d/mathtext/src/table/mathspacing.h rename to builtins/libmathtext/table/mathspacing.h diff --git a/cmake/modules/SearchInstalledSoftware.cmake b/cmake/modules/SearchInstalledSoftware.cmake index 8eb3acdcdb463..e47944b7da470 100644 --- a/cmake/modules/SearchInstalledSoftware.cmake +++ b/cmake/modules/SearchInstalledSoftware.cmake @@ -1583,3 +1583,6 @@ endif() if(test_distrdf_dask) find_package(Dask 2022.08.1 REQUIRED) endif() + +add_subdirectory (builtins/libmathtext) # hard coded builtin needed for graf2d + diff --git a/documentation/doxygen/Doxyfile b/documentation/doxygen/Doxyfile index ea6c2bcdaf10f..a44844af4727e 100644 --- a/documentation/doxygen/Doxyfile +++ b/documentation/doxygen/Doxyfile @@ -1085,7 +1085,7 @@ EXCLUDE = ../../interpreter/ \ ../../core/lzma/ \ ../../core/newdelete/ \ ../../core/textinput/ \ - ../../graf2d/mathtext/ \ + ../../builtins/libmathtext/ \ ../../graf3d/ftgl/ \ ../../graf3d/x3d/ \ ../../net/rootd/ \ diff --git a/documentation/doxygen/makeinput.sh b/documentation/doxygen/makeinput.sh index f77839bf0e41b..f78e363c175b5 100755 --- a/documentation/doxygen/makeinput.sh +++ b/documentation/doxygen/makeinput.sh @@ -80,7 +80,7 @@ echo " ../../bindings/r/ \\" >> Doxyfile_INPUT # echo " ../../core/lzma/ \\" >> Doxyfile_INPUT # echo " ../../core/newdelete/ \\" >> Doxyfile_INPUT # echo " ../../core/textinput/ \\" >> Doxyfile_INPUT -# echo " ../../graf2d/mathtext/ \\" >> Doxyfile_INPUT +# echo " ../../builtins/libmathtext/ \\" >> Doxyfile_INPUT # echo " ../../graf3d/ftgl/ \\" >> Doxyfile_INPUT # echo " ../../graf3d/x3d/ \\" >> Doxyfile_INPUT # echo " ../../net/rootd/ \\" >> Doxyfile_INPUT diff --git a/graf2d/CMakeLists.txt b/graf2d/CMakeLists.txt index 1bc0302b8cba3..3fcb56483a917 100644 --- a/graf2d/CMakeLists.txt +++ b/graf2d/CMakeLists.txt @@ -11,7 +11,6 @@ endif() add_subdirectory(gpad) add_subdirectory(graf) add_subdirectory(postscript) -add_subdirectory(mathtext) if(WIN32) add_subdirectory(win32gdk) elseif(x11) diff --git a/graf2d/graf/src/TMathText.cxx b/graf2d/graf/src/TMathText.cxx index df299d45234ee..1bce566537aea 100644 --- a/graf2d/graf/src/TMathText.cxx +++ b/graf2d/graf/src/TMathText.cxx @@ -22,8 +22,8 @@ #include "TVirtualPS.h" #include "TText.h" -#include "../../../graf2d/mathtext/inc/mathtext.h" -#include "../../../graf2d/mathtext/inc/mathrender.h" +#include "mathtext/mathtext.h" +#include "mathtext/mathrender.h" /** \class TMathText \ingroup BasicGraphics @@ -246,10 +246,8 @@ class TMathTextRenderer : public TText, public TAttFill, upper_right_x <= advance ? 0.0F : std::max(0.0F, upper_right_x + margin - advance); const mathtext::bounding_box_t ret = - mathtext::bounding_box_t( - lower_left_x, lower_left_y, - upper_right_x, upper_right_y, - advance, italic_correction) * scale; + mathtext::bounding_box_t(lower_left_x * scale, lower_left_y * scale, upper_right_x * scale, + upper_right_y * scale, advance * scale, italic_correction * scale); current_x += ret.advance(); diff --git a/graf2d/mathtext/inc/fontembed.h b/graf2d/mathtext/inc/fontembed.h deleted file mode 100644 index 6bd5147aeaee1..0000000000000 --- a/graf2d/mathtext/inc/fontembed.h +++ /dev/null @@ -1,122 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -// Visual C++ 2008 doesn't have stdint.h -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif -#include -#include -#include -#include - -namespace mathtext { - - class font_embed_t { - private: - struct table_data_s { - char tag[4]; - std::vector data; - }; - static void subset_rename_otf_name_table( - struct table_data_s &table_data, uint8_t *glyph_usage); - static void subset_ttf_glyf_table( - struct table_data_s &table_data, uint8_t *glyph_usage); - static void subset_ttf_loca_table( - struct table_data_s &table_data, uint8_t *glyph_usage); - static void subset_ttf_post_table( - struct table_data_s &table_data, uint8_t *glyph_usage); - static void subset_otf_cff_table( - struct table_data_s &table_data, uint8_t *glyph_usage); - static void parse_ttf_encoding_subtable_format4( - std::map &cid_map, - const std::vector &font_data, - const size_t offset, const uint16_t length); - static unsigned int otf_check_sum( - const std::vector &table_data); - public: - // I/O - static std::vector read_font_data(FILE *); - static std::vector read_font_data(const std::string &filename); - // Font parsing - static bool parse_otf_cff_header( - std::string &font_name, unsigned short &cid_encoding_id, - unsigned int &cff_offset, unsigned int &cff_length, - const std::vector &font_data); - static bool parse_ttf_header( - std::string &font_name, double *font_bbox, - std::map &cid_map, - std::vector &char_strings, - const std::vector &font_data); - // Font subsetting - static std::vector subset_otf( - const std::vector &font_data, - const std::map &glyph_usage); - }; - - class font_embed_postscript_t : public font_embed_t { - public: - static void append_asciihex( - std::string &ascii, const uint8_t *buffer, - const size_t length); - static unsigned int ascii85_line_count( - const uint8_t *buffer, const size_t length); - static void append_ascii85( - std::string &ascii, const uint8_t *buffer, - const size_t length); - public: - static std::string font_embed_type_1( - std::string &font_name, - const std::vector &font_data); - static std::string font_embed_type_2( - std::string &font_name, - const std::vector &font_data); - static std::string font_embed_type_42( - std::string &font_name, - const std::vector &font_data); - }; - - class font_embed_pdf_t : public font_embed_t { - public: - static std::string font_embed_type_1( - std::string &font_name, - const std::vector &font_data); - static std::string font_embed_type_2( - std::string &font_name, - const std::vector &font_data); - static std::string font_embed_type_42( - std::string &font_name, - const std::vector &font_data); - }; - - class font_embed_svg_t : public font_embed_t { - static std::string font_embed_svg( - std::string &font_name, - const std::vector &font_data); - }; - -} diff --git a/graf2d/mathtext/inc/mathrender.h b/graf2d/mathtext/inc/mathrender.h deleted file mode 100644 index 4f020b5a763bd..0000000000000 --- a/graf2d/mathtext/inc/mathrender.h +++ /dev/null @@ -1,895 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#ifndef MATHRENDER_H_ -#define MATHRENDER_H_ - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -// Visual C++ 2008 doesn't have stdint.h -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef __int64 int64_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif -#include -#include -#include -#include -#include "mathtext.h" - -namespace mathtext { - - /** - * 2D point (and vector) - */ - class point_t { - private: - float _x[2]; - public: - inline point_t(void) : _x() - { - } - inline point_t(const point_t &point) - { - _x[0] = point._x[0]; - _x[1] = point._x[1]; - } - inline point_t(const float x0, const float y0) - { - _x[0] = x0; - _x[1] = y0; - } - inline point_t& operator=(const point_t &point) - { - _x[0] = point._x[0]; - _x[1] = point._x[1]; - return *this; - } - inline const float *x(void) const - { - return _x; - } - inline float *x(void) - { - return _x; - } - inline float operator[](const int n) const - { - return _x[n]; - } - inline float &operator[](const int n) - { - return _x[n]; - } - inline point_t operator+(const point_t &point) const - { - return point_t(_x[0] + point._x[0], - _x[1] + point._x[1]); - } - inline point_t operator-(const point_t &point) const - { - return point_t(_x[0] - point._x[0], - _x[1] - point._x[1]); - } - inline point_t operator+=(const point_t &point) - { - _x[0] += point._x[0]; - _x[1] += point._x[1]; - - return *this; - } - inline point_t operator-=(const point_t &point) - { - _x[0] -= point._x[0]; - _x[1] -= point._x[1]; - - return *this; - } - inline point_t operator*(const float scale) const - { - return point_t(_x[0] * scale, _x[1] * scale); - } - inline point_t operator/(const float scale) const - { - return point_t(_x[0] / scale, _x[1] / scale); - } - inline point_t operator*=(const float scale) - { - _x[0] *= scale; - _x[1] *= scale; - - return *this; - } - inline float dot(const point_t &point) const - { - return _x[0] * point._x[0] + _x[1] * point._x[1]; - } - inline float cross(const point_t &point) const - { - return _x[0] * point._x[1] - _x[1] * point._x[0]; - } - inline float norm_square(void) const - { - return _x[0] * _x[0] + _x[1] * _x[1]; - } - inline float norm(void) const - { - return sqrtf(norm_square()); - } - inline point_t unit_vector(void) const - { - return *this / norm(); - } - inline point_t rotate_cw(void) const - { - return point_t(_x[1], -_x[0]); - } - inline point_t rotate_ccw(void) const - { - return point_t(-_x[1], _x[0]); - } - inline bool operator==(const point_t &point) const - { - return _x[0] == point._x[0] && _x[1] == point._x[1]; - } - inline bool operator!=(const point_t &point) const - { - return _x[0] != point._x[0] || _x[1] != point._x[1]; - } - friend point_t operator*(const float scale, - const point_t &point); - operator std::string(void) const; - }; - - inline point_t operator*(const float scale, const point_t &point) - { - return point_t(scale * point._x[0], scale * point._x[1]); - } - - /** - * General 2D affine transform of the Adobe Imaging Model - * - * The n-D affine transform is generally represented by - * - * ( xt ) ( a0 a1 a2 ) ( x ) - * ( yt ) = ( a3 a4 a5 ) ( y ) - * ( 1 ) ( 0 0 1 ) ( 1 ) - * - * with (a0, a1, a3, a4) representing the linear component of the - * transform, i.e. rotation and scaling, while (a2, a5) is the - * translation vector - * - * @see Adobe Systems, Inc., PostScript Language Reference Manual - * (Addison-Wesley, Reading, MA, 1999), section 4.3.3, pp. - * 187-189. - * @see Adobe Systems, Inc., PDF Reference, 6th Edition, Version - * 1.7 (Adobe Systems, Inc., San Jose, CA, 2006), section - * 4.2.2-4.2.3, pp. 204-209. - */ - class affine_transform_t { - private: - float _a[6]; - public: - static const affine_transform_t identity; - static const affine_transform_t flip_y; - static affine_transform_t - translate(const float tx, const float ty); - static affine_transform_t - scale(const float sx, const float sy); - static affine_transform_t rotate(const float angle); - inline affine_transform_t( - const float a0, const float b, const float c, - const float d, const float tx, const float ty) - { - _a[0] = a0; - _a[1] = b; - _a[2] = c; - _a[3] = d; - _a[4] = tx; - _a[5] = ty; - } - inline const float *a(void) const - { - return _a; - } - inline float *a(void) - { - return _a; - } - inline float operator[](const int n) const - { - return _a[n]; - } - inline float &operator[](const int n) - { - return _a[n]; - } - inline affine_transform_t linear(void) const - { - return affine_transform_t( - _a[0], _a[1], _a[2], _a[3], 0.0F, 0.0F); - } - inline affine_transform_t translate(void) const - { - return affine_transform_t( - 1.0F, 0.0F, 0.0F, 1.0F, _a[4], _a[5]); - } - inline affine_transform_t operator*(const float s) const - { - return affine_transform_t( - _a[0] * s, _a[1] * s, _a[2] * s, _a[3] * s, - _a[4] * s, _a[5] * s); - } - inline affine_transform_t operator/(const float s) const - { - return affine_transform_t( - _a[0] / s, _a[1] / s, _a[2] / s, _a[3] / s, - _a[4] / s, _a[5] / s); - } - inline point_t operator*(const point_t x) const - { - return point_t( - _a[0] * x[0] + _a[2] * x[1] + _a[4], - _a[1] * x[0] + _a[3] * x[1] + _a[5]); - } - /** - * Returns the affine transform of b, i.e. the matrix-vector - * product (*this) (b^T, 1)^T, of the vector b - * - * @returns the affine transform of the vector b - */ - inline affine_transform_t - operator*(const affine_transform_t b) const - { - return affine_transform_t( - _a[0] * b._a[0] + _a[1] * b._a[2], - _a[0] * b._a[1] + _a[1] * b._a[3], - _a[2] * b._a[0] + _a[3] * b._a[2], - _a[2] * b._a[1] + _a[3] * b._a[3], - _a[4] * b._a[0] + _a[5] * b._a[2] + b._a[4], - _a[4] * b._a[1] + _a[5] * b._a[3] + b._a[5]); - } - /** - * Returns the determinant det(*this) of the affine transform - * - * @returns the determinant det(*this) of the affine transform - */ - inline float determinant(void) const - { - return _a[0] * _a[3] - _a[1] * _a[2]; - } - /** - * Returns the determinant (*this)^(-1) of the affine - * transform - * - * @returns the determinant (*this)^(-1) of the affine - * transform - */ - inline affine_transform_t inverse(void) const - { - return affine_transform_t( - _a[3], -_a[1], -_a[2], _a[0], - _a[2] * _a[5] - _a[3] * _a[4], - _a[1] * _a[4] - _a[0] * _a[5]) * - (1.0F / determinant()); - } - operator std::string(void) const; - }; - - /** - * General TeX bounding box - */ - // FIXME: The skewchar mechanism is missing - class bounding_box_t { - private: - point_t _lower_left; - point_t _upper_right; - float _advance; - float _italic_correction; - public: - inline bounding_box_t(void) : _lower_left(), _upper_right(), _advance(), _italic_correction() - { - } - inline bounding_box_t( - const point_t lower_left_0, const point_t upper_right_0, - const float advance_0, const float italic_correction_0) - : _lower_left(lower_left_0), _upper_right(upper_right_0), - _advance(advance_0), - _italic_correction(italic_correction_0) - { - } - inline bounding_box_t( - const float left_0, const float bottom_0, const float right_0, - const float top_0, const float advance_0, - const float italic_correction_0) - : _advance(advance_0), - _italic_correction(italic_correction_0) - { - _lower_left[0] = left_0; - _lower_left[1] = bottom_0; - _upper_right[0] = right_0; - _upper_right[1] = top_0; - } - inline point_t lower_left(void) const - { - return _lower_left; - } - inline point_t &lower_left(void) - { - return _lower_left; - } - inline point_t upper_right(void) const - { - return _upper_right; - } - inline point_t &upper_right(void) - { - return _upper_right; - } - inline float left(void) const - { - return _lower_left[0]; - } - inline float &left(void) - { - return _lower_left[0]; - } - inline float top(void) const - { - return _upper_right[1]; - } - inline float &top(void) - { - return _upper_right[1]; - } - inline float right(void) const - { - return _upper_right[0]; - } - inline float &right(void) - { - return _upper_right[0]; - } - inline float bottom(void) const - { - return _lower_left[1]; - } - inline float &bottom(void) - { - return _lower_left[1]; - } - inline float advance(void) const - { - return _advance; - } - inline float &advance(void) - { - return _advance; - } - inline float italic_correction(void) const - { - return _italic_correction; - } - inline float &italic_correction(void) - { - return _italic_correction; - } - inline float width(void) const - { - return _upper_right[0] - _lower_left[0]; - } - inline float height(void) const - { - return _upper_right[1] - _lower_left[1]; - } - inline float horizontal_center(void) const - { - return 0.5F * (_lower_left[0] + _upper_right[0]); - } - inline float vertical_center(void) const - { - return 0.5F * (_lower_left[1] + _upper_right[1]); - } - inline float ascent(void) const - { - return _upper_right[1]; - } - inline float descent(void) const - { - return -_lower_left[1]; - } - inline bounding_box_t - merge(const bounding_box_t &bounding_box) const - { - bounding_box_t ret; - - ret._lower_left[0] = - std::min(_lower_left[0], - bounding_box._lower_left[0]); - ret._lower_left[1] = - std::min(_lower_left[1], - bounding_box._lower_left[1]); - if(bounding_box._upper_right[0] > _upper_right[0]) { - ret._upper_right[0] = bounding_box._upper_right[0]; - ret._italic_correction = - bounding_box._italic_correction; - } - else { - ret._upper_right[0] = _upper_right[0]; - ret._italic_correction = _italic_correction; - } - ret._upper_right[1] = - std::max(_upper_right[1], - bounding_box._upper_right[1]); - ret._advance = - std::max(_upper_right[0] + _advance, - bounding_box._upper_right[0] + - bounding_box._advance) - - ret._upper_right[0]; - - return ret; - } - inline bounding_box_t operator+(const point_t &point) const - { - return bounding_box_t( - _lower_left + point, _upper_right + point, - _advance + point[0], _italic_correction); - } - inline bounding_box_t operator-(const point_t &point) const - { - return bounding_box_t( - _lower_left - point, _upper_right - point, - _advance - point[0], _italic_correction); - } - inline bounding_box_t operator+=(const point_t &point) - { - _lower_left += point; - _upper_right += point; - _advance += point[0]; - - return *this; - } - inline bounding_box_t operator-=(const point_t &point) - { - _lower_left -= point; - _upper_right -= point; - _advance -= point[0]; - - return *this; - } - inline bounding_box_t operator*(const float scale) const - { - return bounding_box_t( - _lower_left * scale, _upper_right * scale, - _advance * scale, _italic_correction * scale); - } - inline bounding_box_t operator*=(const float scale) - { - _lower_left *= scale; - _upper_right *= scale; - _advance *= scale; - _italic_correction *= scale; - - return *this; - } - friend bounding_box_t - operator+(const point_t &, const bounding_box_t &); - friend bounding_box_t - operator-(const point_t &, const bounding_box_t &); - friend bounding_box_t - operator*(const affine_transform_t &, - const bounding_box_t &); - }; - - inline bounding_box_t - operator+(const point_t &point, - const bounding_box_t &bounding_box) - { - return bounding_box_t( - point + bounding_box._lower_left, - point + bounding_box._upper_right, - point[0] + bounding_box._advance, - bounding_box._italic_correction); - } - - inline bounding_box_t - operator-(const point_t &point, - const bounding_box_t &bounding_box) - { - return bounding_box_t( - point - bounding_box._lower_left, - point - bounding_box._upper_right, - point[0] + bounding_box._advance, - bounding_box._italic_correction); - } - - inline bounding_box_t - operator*(const affine_transform_t &transform, - const bounding_box_t &bounding_box) - { - return bounding_box_t( - transform * bounding_box._lower_left, - transform * bounding_box._upper_right, - (transform * point_t(bounding_box._advance, 0))[0], - (transform * point_t( - bounding_box._italic_correction, 0))[0]); - } - -#ifdef __INTEL_COMPILER -#pragma warning(push) -#pragma warning(disable: 869) -#endif // __INTEL_COMPILER - /** - * Mathematical layout engine for formulae represented by - * math_text_t - * - * The class math_text_renderer_t is a layout engine based on - * TeX's conversion algorithm from a math list to a horizontal - * list. - * - * @see ISO/IEC JTC1/SC2/WG2, ISO/IEC 10646:2003/Amd.2:2006 (ISO, - * Geneva, 2006). - * @see D. E. Knuth, The TeXbook (Addision-Wesley, Cambridge, MA, - * 1986). - * @see D. E. Knuth, The METAFONTbook (Addision-Wesley, Cambridge, - * MA, 1986). - * @see W. Schmidt, The macro package lucimatx (2005), - * unpublished. - * @see W. Schmidt, Using the MathTime Professional II fonts with - * LaTeX (2006), unpublished. - * @see B. Beeton, A. Freytag, M. Sargent III, Unicode support for - * mathematics, Unicode Technical Report #25 - * @author Yue Shi Lai - * @version 1.0 - */ - class math_text_renderer_t { - public: - enum { - DIRECTION_LEFT_TO_RIGHT = 0, - DIRECTION_RIGHT_TO_LEFT, - DIRECTION_TOP_TO_BOTTOM - }; - enum { - MATH_STYLE_LATIN = 0, - MATH_STYLE_MAGHREB - }; - enum { - FAMILY_PLAIN = 0, - FAMILY_REGULAR, - FAMILY_ITALIC, - FAMILY_BOLD, - FAMILY_BOLD_ITALIC, - FAMILY_STIX_REGULAR, - FAMILY_STIX_ITALIC, - FAMILY_STIX_BOLD, - FAMILY_STIX_BOLD_ITALIC, - FAMILY_STIX_SIZE_1_REGULAR, - FAMILY_STIX_SIZE_1_BOLD, - FAMILY_STIX_SIZE_2_REGULAR, - FAMILY_STIX_SIZE_2_BOLD, - FAMILY_STIX_SIZE_3_REGULAR, - FAMILY_STIX_SIZE_3_BOLD, - FAMILY_STIX_SIZE_4_REGULAR, - FAMILY_STIX_SIZE_4_BOLD, - FAMILY_STIX_SIZE_5_REGULAR, - NFAMILY - }; - private: - ///////////////////////////////////////////////////////////// - // Font parameter - static const float script_ratio; - static const float script_script_ratio; - static const float thin_mu_skip; - static const float med_mu_skip; - static const float thick_mu_skip; - static const float delimiter_factor; - static const float delimiter_shortfall; - ///////////////////////////////////////////////////////////// - static const float num_1; - static const float num_2; - static const float num_3; - static const float denom_1; - static const float denom_2; - static const float sup_1; - static const float sup_2; - static const float sup_3; - static const float sub_1; - static const float sub_2; - static const float sup_drop; - static const float sub_drop; - static const float delim_1; - static const float delim_2; - static const float axis_height; - static const float default_rule_thickness; - static const float big_op_spacing_1; - static const float big_op_spacing_2; - static const float big_op_spacing_3; - static const float big_op_spacing_4; - static const float big_op_spacing_5; - ///////////////////////////////////////////////////////////// - static const float radical_rule_thickness; - static const float large_operator_display_scale; - ///////////////////////////////////////////////////////////// - static const float baselineskip_factor; - ///////////////////////////////////////////////////////////// - // Token - class math_token_t { - public: - point_t _offset; - bounding_box_t _bounding_box; - struct extension_t { - wchar_t _glyph; - unsigned int _family; - float _size; - }; - union { - unsigned int _style; - extension_t _extensible; - }; - float _delimiter_height; - inline math_token_t( - const bounding_box_t bounding_box, - const unsigned int style, - const float delimiter_height = 0.0F) - : _offset(0, 0), _bounding_box(bounding_box), - _style(style), _delimiter_height(delimiter_height) - { - } - inline math_token_t( - const point_t offset, - const bounding_box_t bounding_box, - const unsigned int style, - const float delimiter_height = 0.0F) - : _offset(offset), _bounding_box(bounding_box), - _style(style), _delimiter_height(delimiter_height) - { - } - inline math_token_t( - const bounding_box_t bounding_box, - const wchar_t glyph, const unsigned int family, - const float size) - : _offset(0, 0), _bounding_box(bounding_box), - _delimiter_height(0.0F) - { - _extensible._glyph = glyph; - _extensible._family = family; - _extensible._size = size; - } - inline math_token_t( - const point_t offset, - const bounding_box_t bounding_box, - const wchar_t glyph, const unsigned int family, - const float size) - : _offset(offset), _bounding_box(bounding_box), - _delimiter_height(0.0F) - { - _extensible._glyph = glyph; - _extensible._family = family; - _extensible._size = size; - } - }; - ///////////////////////////////////////////////////////////// - // Style test and change - float style_size(const unsigned int style) const; - bool is_display_style(const unsigned int style) const; - bool is_script_style(const unsigned int style) const; - unsigned int prime_style(const unsigned int style) const; - bool is_prime_style(const unsigned int style) const; - template - inline value_t - if_else_display(const unsigned int style, - const value_t display_value, - const value_t otherwise_value) const - { - switch(style) { - case math_text_t::item_t::STYLE_DISPLAY: - case math_text_t::item_t::STYLE_DISPLAY_PRIME: - return display_value; - default: - return otherwise_value; - } - } - unsigned int next_superscript_style(const unsigned int style) - const; - unsigned int next_subscript_style(const unsigned int style) - const; - unsigned int next_numerator_style(const unsigned int style) - const; - unsigned int next_denominator_style(const unsigned int style) - const; - ///////////////////////////////////////////////////////////// - float x_height(const unsigned int style); - float quad(const unsigned int style) const; - unsigned int - math_family(const math_text_t::math_symbol_t &math_symbol) - const; - void post_process_atom_type_initial(unsigned int &atom_type) - const; - void post_process_atom_type_interior( - unsigned int &previous_atom_type, - unsigned int &atom_type) - const; - bool valid_accent( - bool &vertical_alignment, - const std::vector::const_iterator & - iterator, - const std::vector::const_iterator & - math_list_end) const; - float kerning_mu(float amount) const; - float math_spacing( - unsigned int left_type, unsigned int right_type, - unsigned int style) const; - protected: - inline virtual affine_transform_t - transform_logical_to_pixel(void) const = 0; - virtual affine_transform_t - transform_pixel_to_logical(void) const = 0; - ///////////////////////////////////////////////////////////// - // Box rendering - bounding_box_t math_bounding_box( - const math_text_t::box_t &box, const unsigned int style); - void math_text( - const point_t origin, const math_text_t::box_t &box, - const unsigned int style, const bool render_structure); - ///////////////////////////////////////////////////////////// - // Symbol rendering - static bool is_wgl_4(const wchar_t c); - static bool is_left_to_right(const wchar_t c); - static bool is_right_to_left(const wchar_t c); - static bool is_top_to_bottom(const wchar_t c); - static bool is_cyrillic(const wchar_t c); - static bool is_cjk(const wchar_t c); - static bool is_cjk_punctuation_open(const wchar_t c); - static bool is_cjk_punctuation_closed(const wchar_t c); - bounding_box_t math_bounding_box( - const wchar_t &glyph, const unsigned int family, - const float size); - void math_text( - const point_t origin, const wchar_t &glyph, - const unsigned int family, const float size, - const bool render_structure); - bounding_box_t math_bounding_box( - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style); - void math_text( - const point_t origin, - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const bool render_structure); - ///////////////////////////////////////////////////////////// - // Extensible glyph rendering - void large_family( - unsigned long &nfamily, const unsigned int *&family, - const math_text_t::math_symbol_t &math_symbol) const; - void extensible_glyph( - wchar_t glyph[4], unsigned long &nrepeat, - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height); - std::vector math_tokenize( - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height); - bounding_box_t math_bounding_box( - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height); - void math_text( - const point_t origin, - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height, - const bool render_structure); - ///////////////////////////////////////////////////////////// - // Math list rendering - std::vector math_tokenize( - const std::vector::const_iterator & - math_list_begin, - const std::vector::const_iterator & - math_list_end, - unsigned int style); - bounding_box_t math_bounding_box( - const std::vector::const_iterator & - math_list_begin, - const std::vector::const_iterator & - math_list_end, - unsigned int style); - void math_text( - const point_t origin, - const std::vector::const_iterator & - math_list_begin, - const std::vector::const_iterator & - math_list_end, - const unsigned int style, const bool render_structure); - ///////////////////////////////////////////////////////////// - // Field rendering - bounding_box_t math_bounding_box( - const math_text_t::field_t &field, - const unsigned int style); - void math_text( - const point_t origin, const math_text_t::field_t &field, - const unsigned int style, const bool render_structure); - ///////////////////////////////////////////////////////////// - // Atom rendering - std::vector math_tokenize( - const math_text_t::atom_t &atom, unsigned int style); - bounding_box_t math_bounding_box( - const math_text_t::atom_t &atom, - const unsigned int style); - void math_text( - const point_t origin, const math_text_t::atom_t &atom, - const unsigned int style, const bool render_structure); - ///////////////////////////////////////////////////////////// - public: - ///////////////////////////////////////////////////////////// - // Constructor and destructor - inline math_text_renderer_t(void) - { - } - inline virtual ~math_text_renderer_t(void) - { - } - ///////////////////////////////////////////////////////////// - // Virtual functions - virtual float font_size( - const unsigned int family = FAMILY_PLAIN) const = 0; - virtual void set_font_size( - const float size, const unsigned int family) = 0; - inline virtual void set_font_size(const float size) = 0; - virtual void reset_font_size( - const unsigned int family) = 0; - virtual void point(const float x, const float y) = 0; - virtual void filled_rectangle( - const bounding_box_t &bounding_box) = 0; - virtual void rectangle( - const bounding_box_t &bounding_box) = 0; - virtual bounding_box_t bounding_box( - const std::wstring string, - const unsigned int family = FAMILY_PLAIN) = 0; - virtual void text_raw( - const float x, const float y, const std::wstring string, - const unsigned int family = FAMILY_PLAIN) = 0; - virtual void text_with_bounding_box( - const float x, const float y, const std::wstring string, - const unsigned int family = FAMILY_PLAIN) = 0; - ///////////////////////////////////////////////////////////// - // Interface - bounding_box_t bounding_box( - const math_text_t &math_text, - const bool display_style = false); - void text( - const float x, const float y, - const math_text_t &math_text, - const bool display_style = false); - ///////////////////////////////////////////////////////////// - inline float default_axis_height( - const bool /*display_style = false*/) const - { - return axis_height * style_size( - math_text_t::item_t::STYLE_TEXT); - } - ///////////////////////////////////////////////////////////// - }; -#ifdef __INTEL_COMPILER -#pragma warning(pop) -#endif // __INTEL_COMPILER - -} - -#endif // MATHRENDER_H_ diff --git a/graf2d/mathtext/inc/mathtext.h b/graf2d/mathtext/inc/mathtext.h deleted file mode 100644 index 4908cf58b5e02..0000000000000 --- a/graf2d/mathtext/inc/mathtext.h +++ /dev/null @@ -1,523 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#ifndef MATHTEXT_H_ -#define MATHTEXT_H_ - -#include -#include -#include - -namespace mathtext { - - class surface_t; - - /** - * Hierarchical representation of mathematical formulae - * - * The class math_text_t is a hierarchical representation of - * mathematical formulae similar to TeX's math list. - * - * Limitations: - * - * - Only (spacing) symbols and combining diacritical marks from - * TeX, AMS-TeX, LaTeX, AMS-LaTeX, and MathTime Professional II - * that are representable within ISO/IEC 10646:2003/Amd.2:2006 - * Universal Character Set can be accessed. - * - * - Illegal TeX syntax may result in not well defined behaviors. - * Most notably, `a^b^c' or `a_b_c' result in `a^c' and `a_c', - * i.e. the overwriting of the previous superscripts and - * subscripts, and `a \\atop b \\atop c' or `a \\over b \\over c' - * result in `a \\atop {b \\atop c}' and `a \\over {b \\over c}', i.e. - * a right associative interpretation. - * - * @see ISO/IEC JTC1/SC2/WG2, ISO/IEC 10646:2003/Amd.2:2006 (ISO, - * Geneva, 2006). - * @see D. E. Knuth, The TeXbook (Addision-Wesley, Cambridge, MA, - * 1986). - * @see D. E. Knuth, The METAFONTbook (Addision-Wesley, Cambridge, - * MA, 1986). - * @see B. Beeton, A. Freytag, M. Sargent III, Unicode support for - * mathematics, Unicode Technical Report #25 - * @author Yue Shi Lai - * @version 1.0 - */ - class math_text_t { - private: - /** - * Mathematical symbol - * - * The class math_symbol_t represents all (spacing) symbols - * and combining diacritical marks representable within - * ISO/IEC 10646:2003/Amd.2:2006 Universal Character Set from - * TeX, AMS-TeX, LaTeX, AMS-LaTeX, and MathTime Professional - * II. - * - * @author Yue Shi Lai - * @version 1.0 - */ - class math_symbol_t { - public: - enum { - FAMILY_PLAIN = 0, - // Math fonts start - FAMILY_REGULAR, - FAMILY_ITALIC, - FAMILY_BOLD, - FAMILY_BOLD_ITALIC, - FAMILY_STIX_REGULAR, - FAMILY_STIX_ITALIC, - FAMILY_STIX_BOLD, - FAMILY_STIX_BOLD_ITALIC, - FAMILY_STIX_SIZE_1_REGULAR, - FAMILY_STIX_SIZE_1_BOLD, - FAMILY_STIX_SIZE_2_REGULAR, - FAMILY_STIX_SIZE_2_BOLD, - FAMILY_STIX_SIZE_3_REGULAR, - FAMILY_STIX_SIZE_3_BOLD, - FAMILY_STIX_SIZE_4_REGULAR, - FAMILY_STIX_SIZE_4_BOLD, - FAMILY_STIX_SIZE_5_REGULAR, - // Below are virtual fonts for bookkeeping and do not - // have to correspond to a physical font available in - // surface_t. - // - // TeX combined styles - FAMILY_MATH_ITALIC, - FAMILY_MATH_BOLD_ITALIC, - // Mathematical Alphanumerical Symbols, mostly in the - // Unicode range U+1D500 - U+1D5FF - FAMILY_MATH_SCRIPT_ITALIC, - FAMILY_MATH_SCRIPT_BOLD_ITALIC, - FAMILY_MATH_FRAKTUR_REGULAR, - FAMILY_MATH_FRAKTUR_BOLD, - FAMILY_MATH_BLACKBOARD_BOLD, - FAMILY_MATH_SANS_SERIF_REGULAR, - FAMILY_MATH_SANS_SERIF_ITALIC, - FAMILY_MATH_SANS_SERIF_BOLD, - FAMILY_MATH_SANS_SERIF_BOLD_ITALIC, - FAMILY_MATH_MONOSPACE, - NFAMILY - }; - private: - /** - * Sets any family that is mathematical italic into the - * upright variant of the same weight, thus preventing - * them from converted into the italic form in the final - * step. - * - * @see void math_italic_is_italic(void) - */ - void math_italic_is_upright(void); - /** - * Sets any family that is mathematical italic into the - * italic variant of the same weight, usually used in the - * final step to convert all remaining character in - * mathematical italic into the italic form. - * - * @see void math_italic_is_upright(void) - */ - void math_italic_is_italic(void); - void encode_character(void); - void encode_control_sequence(void); - void encode_math_blackboard_bold(void); - void encode_math_script_italic(void); - void encode_math_script_bold_italic(void); - void encode_math_fraktur_regular(void); - void encode_math_fraktur_bold(void); - void encode_math_sans_serif_regular(void); - void encode_math_sans_serif_italic(void); - void encode_math_sans_serif_bold(void); - void encode_math_sans_serif_bold_italic(void); - void encode_math_alpha(void); - void encode(void); - public: - std::string _code; - unsigned int _family; - wchar_t _glyph; - unsigned int _type; - inline math_symbol_t(void) - : _family(FAMILY_PLAIN), _glyph(L'\0'), - _type(atom_t::TYPE_UNKNOWN) - { - } - inline math_symbol_t(std::string code, wchar_t glyph, - const unsigned int family) - : _code(code), _family(family), _glyph(glyph), - _type(atom_t::TYPE_UNKNOWN) - { - } - inline math_symbol_t(std::string code, - const unsigned int family) - : _code(code), _family(family), _glyph(0), - _type(atom_t::TYPE_UNKNOWN) - { - encode(); - } - inline bool is_combining_diacritical(void) const - { - // ISO/IEC JTC1/SC2/WG2 (2003), Annex B, but without - // the additional characters from the list - return - (_glyph >= L'\u0300' && _glyph <= L'\u036f') || - (_glyph >= L'\u20d0' && _glyph <= L'\u20ff') || - (_glyph >= L'\ufe20' && _glyph <= L'\ufe2f'); - } - bool bold(void) const; - }; - /** - * (Horizontal) Box - * - * @author Yue Shi Lai - * @version 1.0 - */ - class box_t { - public: - bool _vertical; - std::wstring _string; - box_t(void) - : _vertical(false), _string(L"") - { - } - box_t(std::wstring string) - : _vertical(false), _string(string) - { - } - }; - class atom_t; - class item_t; - /** - * Math field - * - * @author Yue Shi Lai - * @version 1.0 - */ - class field_t { - private: - void transform_script(void); - void append(const item_t &item); - void append(const field_t &field, const bool superscript, - const bool subscript); - void prepend(const unsigned int type, - const math_symbol_t &math_symbol); - void append(const unsigned int type, - const math_symbol_t &math_symbol, - const bool superscript, - const bool subscript); - void parse_math_list( - const std::vector &str_split, - const unsigned int default_family); - public: - enum { - // The explicit TYPE_EMPTY in TeX is represented here - // by an empty math list - TYPE_UNKNOWN = 0, - TYPE_MATH_SYMBOL, - TYPE_BOX, // unused - TYPE_MATH_LIST, - NTYPE - }; - unsigned int _type; - math_symbol_t _math_symbol; - box_t _box; - std::vector _math_list; - inline field_t(void) - : _type(TYPE_MATH_LIST) - { - // Empty math list == implicit TYPE_EMPTY - } - inline field_t(const math_symbol_t &math_symbol) - : _type(TYPE_MATH_SYMBOL), _math_symbol(math_symbol) - { - } - inline field_t(const box_t &box) - : _type(TYPE_BOX), _box(box) - { - } - inline field_t(const std::vector &math_list) - : _type(TYPE_MATH_LIST), _math_list(math_list) - { - } - field_t(const std::vector &str_split, - const unsigned int default_family); - field_t(const std::string &str_delimiter_left, - const std::vector &str_split, - const std::string &str_delimiter_right, - const unsigned int default_family); - inline bool empty(void) const - { - return _type == TYPE_MATH_LIST && _math_list.empty(); - } - bool generalized_fraction(void) const; - }; - /** - * Math atom - * - * @author Yue Shi Lai - * @version 1.0 - */ - class atom_t { - private: - void classify(void); - public: - // TeX's 13 types of math atom - enum { - TYPE_UNKNOWN = 0, - TYPE_ORD, - TYPE_OP, - TYPE_BIN, - TYPE_REL, - TYPE_OPEN, - TYPE_CLOSE, - TYPE_PUNCT, - TYPE_INNER, - TYPE_OVER, // not implemented - TYPE_UNDER, // not implemented - TYPE_ACC, - TYPE_RAD, - TYPE_VCENT, // unused - NTYPE - }; - enum { - LIMITS_UNKNOWN = 0, - LIMITS_LIMITS, - LIMITS_NOLIMITS, - LIMITS_DISPLAYLIMITS, - NLIMITS - }; - unsigned int _type; - // Fields - field_t _nucleus; - field_t _superscript; - field_t _subscript; - unsigned int _limits; - // Index the root with the radicand _nucleus, if _type == - // TYPE_RAD (while TeX uses absolute positioning for the - // index, it is not possible to represent it in an font - // independent way). - field_t _index; - inline atom_t(const unsigned int type, - const field_t &nucleus) - : _type(type), _nucleus(nucleus), - _limits(LIMITS_UNKNOWN) - { - } - inline atom_t(const unsigned int type, - const field_t &nucleus, - const unsigned int limits) - : _type(type), _nucleus(nucleus), _limits(limits) - { - } - inline atom_t(const field_t &nucleus) - : _nucleus(nucleus), _limits(false) - { - classify(); - } - inline atom_t(const field_t &nucleus, - const field_t &superscript, - const field_t &subscript) - : _nucleus(nucleus), _superscript(superscript), - _subscript(subscript), _limits(LIMITS_UNKNOWN) - { - classify(); - } - /** - * Returns true if the atom is of type Acc, or if it is a - * math symbol and its character representation is a - * combining diacritical mark within the ISO/IEC - * 10646:2003/Amd.2:2006 Universal Character Set, and - * false otherwise. - * - * @return true if the atom is of type Acc, or if it is a - * math symbol and its character representation is a - * combining diacritical mark within the ISO/IEC - * 10646:2003/Amd.2:2006 Universal Character Set, and - * false otherwise - */ - bool is_combining_diacritical(void) const; - /** - * Returns the interelement spacing between the given left - * and right atom types, and whether the present style is - * script or scriptscript, with 0, 1, 2, and 3 - * representing no space, \\thinkmuskip, \\medmuskip, and - * \\thickmuskip, respectively. - * - * TeX defaults to \\thinkmuskip to 3 mu, \\medmuskip to 4 - * mu, and \\thickmuskip to 5 mu, with 1 mu being 1/18 - * quad. - * - * @param[in] left_type left (enum) atom type - * @param[in] right_type right (enum) atom type - * @param[in] script boolean - * @return interelement spacing, with 0, 1, 2, and 3 - * representing no space, \\thinkmuskip, \\medmuskip, and - * \\thickmuskip, respectively - */ - static unsigned int - spacing(const unsigned int left_type, - const unsigned int right_type, const bool script); - }; - /** - * Math item - * - * @author Yue Shi Lai - * @version 1.0 - */ - class item_t { - public: - // TeX's 9 types of math item - enum { - TYPE_UNKNOWN = 0, - TYPE_ATOM, // implemented - TYPE_HORIZONTAL, // unused - TYPE_VERTICAL, // unused - TYPE_GLOB_OR_GLUE, // unused - TYPE_KERN, // implemented - TYPE_STYLE_CHANGE, // not implemented - TYPE_GENERALIZED_FRACTION, // not implemented - TYPE_BOUNDARY, // implemented - TYPE_FOUR_WAY_CHOICE, // unused - NTYPE - }; - // TeX's 8 math styles - enum { - STYLE_UNKNOWN = 0, - STYLE_SCRIPT_SCRIPT_PRIME, - STYLE_SCRIPT_SCRIPT, - STYLE_SCRIPT_PRIME, - STYLE_SCRIPT, - STYLE_TEXT_PRIME, - STYLE_TEXT, - STYLE_DISPLAY_PRIME, - STYLE_DISPLAY, - NSTYLE - }; - // TeX's left and right math boundary - enum { - BOUNDARY_UNKNOWN = 0, - BOUNDARY_LEFT, - BOUNDARY_RIGHT, - NBOUNDARY - }; - unsigned int _type; - atom_t _atom; - float _length; - unsigned int _style_change; - unsigned int _boundary; - inline item_t(const unsigned int type, - const float length = 0) - : _type(type), _atom(field_t()), _length(length), - _style_change(STYLE_UNKNOWN), - _boundary(BOUNDARY_UNKNOWN) - { - } - inline item_t(const atom_t &atom) - : _type(TYPE_ATOM), _atom(atom), _length(0), - _style_change(STYLE_UNKNOWN), - _boundary(BOUNDARY_UNKNOWN) - { - } - inline item_t(const unsigned int type, - const atom_t &atom) - : _type(type), _atom(atom), _length(0), - _style_change(STYLE_UNKNOWN), - _boundary(BOUNDARY_UNKNOWN) - { - } - bool operator==(const item_t &item) const; - }; - std::wstring _code; - field_t _math_list; - bool _render_structure; - ///////////////////////////////////////////////////////////// - void tree_view_prefix(const std::vector &branch, - const bool final) const; - void tree_view(const field_t &field, - std::vector &branch, const bool final) - const; - void tree_view(const item_t &item, std::vector &branch, - const bool final) const; - void tree_view(const atom_t &atom, std::vector &branch, - const bool final) const; - static std::wstring bad_cast(const std::string string); - static std::wstring utf8_cast(const std::string string); - ///////////////////////////////////////////////////////////// - static std::vector - tex_split(const std::string &raw_code, - const char escape_character = '\\'); - static std::vector - tex_replace(const std::vector &code); - field_t build_math_list(const std::vector & - code_split) const - { - return field_t(code_split, - math_symbol_t::FAMILY_MATH_ITALIC); - } - public: - math_text_t(void) - : _code(), _math_list(), _render_structure(false) - { - } - math_text_t(const std::string &code_string) - : _code(bad_cast(code_string)), _render_structure(false) - { - std::cerr << __FILE__ << ':' << __LINE__ << ": " << std::endl; - std::vector code_split = tex_split(code_string); - _math_list = build_math_list(code_split); - } - math_text_t(const char code_string[]) - : _code(bad_cast(code_string)), _render_structure(false) - { - std::vector code_split = tex_split(code_string); - _math_list = build_math_list(code_split); - } - inline std::wstring code(void) const - { - return _code; - } - inline bool render_structure(void) const - { - return _render_structure; - } - inline bool &render_structure(void) - { - return _render_structure; - } - bool well_formed(void) const; - inline bool empty(void) const - { - return _math_list.empty(); - } - inline void tree_view(void) const - { - std::vector branch; - tree_view(_math_list, branch, true); - } - friend class math_text_renderer_t; - }; - - /** - * Returns the TeX-formatted scientific representation of a real - * number - */ - extern std::string tex_form(const double x); - -} - -#endif // MATHTEXT_H_ diff --git a/graf2d/mathtext/src/fontembed.cxx b/graf2d/mathtext/src/fontembed.cxx deleted file mode 100644 index ce287335d1fe9..0000000000000 --- a/graf2d/mathtext/src/fontembed.cxx +++ /dev/null @@ -1,1188 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#include "../inc/fontembed.h" -#include -#include -#include -#ifdef WIN32 -#define snprintf _snprintf -#endif - -// ROOT integration -#include -#ifdef R__BYTESWAP -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1 -#endif // LITTLE_ENDIAN -#include "Byteswap.h" -#define bswap_16(x) Rbswap_16((x)) -#define bswap_32(x) Rbswap_32((x)) -#else // R__BYTESWAP -#ifdef LITTLE_ENDIAN -#undef LITTLE_ENDIAN -#endif // LITTLE_ENDIAN -#endif // R__BYTESWAP - -// References: -// -// Adobe Systems, Inc. and Microsoft Corp., OpenType specification -// (2002), version 1.4. -// -// Apple Computer, Inc., TrueType reference ranual (2002) -// -// Microsoft Corp., TrueType 1.0 font files: technical specification -// (1995), version 1.66 - -namespace mathtext { - - typedef int32_t fixed_t; - - void font_embed_t::parse_ttf_encoding_subtable_format4( - std::map &cid_map, - const std::vector &font_data, const size_t offset, - const uint16_t length) - { - cid_map.clear(); - - size_t offset_current = offset; - - struct ttf_encoding_subtable_format4_s { - uint16_t seg_count_x2; - uint16_t search_range; - uint16_t entry_selector; - uint16_t range_shift; - } encoding_subtable_format4; - - memcpy(&encoding_subtable_format4, - &font_data[offset_current], - sizeof(struct ttf_encoding_subtable_format4_s)); - offset_current += - sizeof(struct ttf_encoding_subtable_format4_s); -#ifdef LITTLE_ENDIAN - encoding_subtable_format4.seg_count_x2 = - bswap_16(encoding_subtable_format4.seg_count_x2); -#endif // LITTLE_ENDIAN - - const uint16_t seg_count = - encoding_subtable_format4.seg_count_x2 >> 1; - uint16_t *end_code = new uint16_t[seg_count]; - - memcpy(end_code, &font_data[offset_current], - seg_count * sizeof(uint16_t)); - offset_current += seg_count * sizeof(uint16_t); -#ifdef LITTLE_ENDIAN - for (uint16_t segment = 0; segment < seg_count; segment++) { - end_code[segment] = bswap_16(end_code[segment]); - } -#endif // LITTLE_ENDIAN - - uint16_t reserved_pad; - - memcpy(&reserved_pad, &font_data[offset_current], - sizeof(uint16_t)); - offset_current += sizeof(uint16_t); - - uint16_t *start_code = new uint16_t[seg_count]; - - memcpy(start_code, &font_data[offset_current], - seg_count * sizeof(uint16_t)); - offset_current += seg_count * sizeof(uint16_t); -#ifdef LITTLE_ENDIAN - for (uint16_t segment = 0; segment < seg_count; segment++) { - start_code[segment] = bswap_16(start_code[segment]); - } -#endif // LITTLE_ENDIAN - - uint16_t *id_delta = new uint16_t[seg_count]; - - memcpy(id_delta, &font_data[offset_current], - seg_count * sizeof(uint16_t)); - offset_current += seg_count * sizeof(uint16_t); -#ifdef LITTLE_ENDIAN - for (uint16_t segment = 0; segment < seg_count; segment++) { - id_delta[segment] = bswap_16(id_delta[segment]); - } -#endif // LITTLE_ENDIAN - - const uint16_t variable = - (length >> 1) - (seg_count << 2) - 8; - uint16_t *id_range_offset = - new uint16_t[seg_count + variable]; - - memcpy(id_range_offset, &font_data[offset_current], - (seg_count + variable) * sizeof(uint16_t)); - offset_current += (seg_count + variable) * sizeof(uint16_t); -#ifdef LITTLE_ENDIAN - for (uint16_t j = 0; j < seg_count + variable; j++) { - id_range_offset[j] = bswap_16(id_range_offset[j]); - } -#endif // LITTLE_ENDIAN - - for (uint16_t segment = 0; segment < seg_count; segment++) { - for (uint32_t code = start_code[segment]; - code <= end_code[segment]; code++) { - const uint16_t inner_offset = segment + - (id_range_offset[segment] >> 1) + - (code - start_code[segment]); - const uint16_t glyph_index = - id_range_offset[segment] == 0 ? - id_delta[segment] + code : - inner_offset >= seg_count + variable ? - 0 : id_range_offset[inner_offset]; - - cid_map[static_cast(code)] = glyph_index; - } - } - - delete [] end_code; - delete [] start_code; - delete [] id_delta; - delete [] id_range_offset; - } - - ///////////////////////////////////////////////////////////////////// - // Currently unfinished font subsetting code below - ///////////////////////////////////////////////////////////////////// - -#if 0 - // Rename: - // name - // Subset: - // glyf, loca, hmtx, vmtx, cmap, hdmx, VDMX, kern, LTSH, VORG - // Conditional subset: - // post 2.0 - // Remove completely: - // DSIG, BASE, GDEF, GPOS, GSUB, JSTF, EBDT, EBLC, EBSC - - void font_embed_t::subset_rename_otf_name_table( - struct table_data_s &table_data, - std::map glyph_usage) - { - // Prefix name IDs 1, 4, 6, 16, 19, 20, 21 - - // No platform ID other than 1 and 3 is permitted for the name - // table - - // Platform ID = 1: 1 byte - // Platform ID = 3: 2 byte - - // Reset UID 4,000,000 and 4,999,999 and XUID - } - - void font_embed_t::subset_ttf_glyf_table( - struct table_data_s &table_data, - std::map glyph_usage) - { - } - - void font_embed_t::subset_ttf_loca_table( - struct table_data_s &table_data, - std::map glyph_usage) - { - } - - void font_embed_t::subset_ttf_post_table( - struct table_data_s &table_data, - std::map glyph_usage) - { - } - - class cff_index_t { - public: - uint16_t count; - uint8_t off_size; - std::vector offset; - std::vector data; - cff_index_t(const uint8_t *input_data) - { - memcpy(&count, input_data, sizeof(uint16_t)); -#ifdef LITTLE_ENDIAN - count = bswap_16(count); -#endif // LITTLE_ENDIAN - memcpy(&off_size, input_data + sizeof(uint16_t), - sizeof(uint8_t)); - - if (!(off_size >= 1 && off_size < 5)) { - return; - } - - const uint8_t *input_data_offset = - input_data + sizeof(uint16_t) + sizeof(uint8_t); - - // The off by one or indexing from one convention in CFF - // is corrected here, i.e. the resulting offset table is - // zero-based, and not the CFF one. - - offset.reserve(count + 1); - switch (off_size) { - case 1: - for (size_t i = 0; i < count + 1; i++) { - offset.push_back(input_data_offset[i]); - } - break; - case 2: - for (size_t i = 0; i < count + 1; i++) { - offset.push_back(reinterpret_cast( - input_data_offset)[i]); -#ifdef LITTLE_ENDIAN - offset.back() = bswap_16(offset.back()); -#endif // LITTLE_ENDIAN - } - break; - case 3: - for (size_t i = 0; i < 3 * (count + 1); i += 3) { - const uint32_t value = - input_data_offset[3 * i] << 16 | - input_data_offset[3 * i + 1] << 8 | - input_data_offset[3 * i + 2]; - - offset.push_back(value); - } - break; - case 4: - for (size_t i = 0; i < count + 1; i++) { - offset.push_back(reinterpret_cast( - input_data_offset)[i]); -#ifdef LITTLE_ENDIAN - offset.back() = bswap_32(offset.back()); -#endif // LITTLE_ENDIAN - } - break; - } - - const uint8_t *input_data_data = - input_data_offset + off_size * (count + 1); - - data = std::vector(input_data_data, input_data_data - } - ~cff_index_t(void) - { - } - }; - - void font_embed_t::subset_otf_cff_table( - struct table_data_s &table_data, - std::map glyph_usage) - { - } -#endif - - uint32_t font_embed_t::otf_check_sum( - const std::vector &table_data) - { - const uint32_t *table = - reinterpret_cast(&(table_data[0])); - const uint32_t nword = table_data.size() >> 2; - uint32_t sum = 0; - - for (size_t i = 0; i < nword; i++) { -#ifdef LITTLE_ENDIAN - sum += bswap_32(table[i]); -#else // LITTLE_ENDIAN - sum += table[i]; -#endif // LITTLE_ENDIAN - } - - // Do not assume 0x00 padding and calculate partial uint32_t - // checksums directly. - const uint8_t *table_tail = - reinterpret_cast(&(table[nword])); - - switch(table_data.size() & 3U) { - case 3: sum += table_tail[2] << 8; - case 2: sum += table_tail[1] << 16; - case 1: sum += table_tail[0] << 24; break; - } - - return sum; - } - - std::vector font_embed_t::read_font_data( - FILE *fp) - { - std::vector font_data; - - if (fp == nullptr) { - return font_data; - } - if (fseek(fp, 0L, SEEK_SET) == -1) { - perror("fseek"); - return font_data; - } - if (fseek(fp, 0L, SEEK_END) == -1) { - perror("fseek"); - return font_data; - } - - const long length = ftell(fp); - - if (length == -1) { - perror("ftell"); - return font_data; - } - font_data.resize(length); - if (fseek(fp, 0L, SEEK_SET) == -1) { - perror("fseek"); - font_data.clear(); - return font_data; - } - if (fread(&font_data[0], sizeof(uint8_t), - length, fp) != static_cast(length)) { - perror("fread"); - font_data.clear(); - return font_data; - } - fseek(fp, 0L, SEEK_SET); - - return font_data; - } - - std::vector font_embed_t::read_font_data( - const std::string &filename) - { - FILE *fp = fopen(filename.c_str(), "r"); - std::vector font_data; - - if (fp == nullptr) { - perror("fopen"); - return font_data; - } - font_data = read_font_data(fp); - fclose(fp); - - return font_data; - } - - bool font_embed_t::parse_otf_cff_header( - std::string &font_name, unsigned short &cid_encoding_id, - unsigned int &cff_offset, unsigned int &cff_length, - const std::vector &font_data) - { - // OpenType file structure - struct otf_offset_table_s { - char sfnt_version[4]; - uint16_t num_tables; - uint16_t search_range; - uint16_t entry_selector; - uint16_t range_shift; - } offset_table; - - memcpy(&offset_table, &font_data[0], - sizeof(struct otf_offset_table_s)); - if (strncmp(offset_table.sfnt_version, "OTTO", 4) != 0) { - // Not a OpenType CFF/Type 2 font - return false; - } -#ifdef LITTLE_ENDIAN - offset_table.num_tables = bswap_16(offset_table.num_tables); -#endif // LITTLE_ENDIAN - - bool name_table_exists = false; - bool cff_table_exists = false; - uint32_t name_offset = 0; - - for (uint16_t i = 0; i < offset_table.num_tables; i++) { - struct otf_table_directory_s { - char tag[4]; - uint32_t check_sum; - uint32_t offset; - uint32_t length; - } table_directory; - - memcpy(&table_directory, - &font_data[sizeof(struct otf_offset_table_s) + i * - sizeof(struct otf_table_directory_s)], - sizeof(struct otf_table_directory_s)); -#ifdef LITTLE_ENDIAN - table_directory.offset = - bswap_32(table_directory.offset); - table_directory.length = - bswap_32(table_directory.length); -#endif // LITTLE_ENDIAN - if (strncmp(table_directory.tag, "name", 4) == 0) { - name_offset = table_directory.offset; - name_table_exists = true; - } - else if (strncmp(table_directory.tag, "CFF ", 4) == 0) { - cff_offset = table_directory.offset; - cff_length = table_directory.length; - cff_table_exists = true; - } - } - - if (!(name_table_exists && cff_table_exists)) { - return false; - } - - // name - - struct otf_naming_table_header_s { - uint16_t format; - uint16_t count; - uint16_t string_offset; - } naming_table_header; - - memcpy(&naming_table_header, &font_data[name_offset], - sizeof(struct otf_naming_table_header_s)); -#ifdef LITTLE_ENDIAN - naming_table_header.format = - bswap_16(naming_table_header.format); - naming_table_header.count = - bswap_16(naming_table_header.count); - naming_table_header.string_offset = - bswap_16(naming_table_header.string_offset); -#endif // LITTLE_ENDIAN - - cid_encoding_id = 0xffffU; - - for (uint16_t i = 0; i < naming_table_header.count; i++) { - struct otf_name_record_s { - uint16_t platform_id; - uint16_t encoding_id; - uint16_t language_id; - uint16_t name_id; - uint16_t length; - uint16_t offset; - } name_record; - const size_t base_offset = name_offset + - sizeof(struct otf_naming_table_header_s); - - memcpy(&name_record, - &font_data[base_offset + i * - sizeof(struct otf_name_record_s)], - sizeof(struct otf_name_record_s)); -#ifdef LITTLE_ENDIAN - name_record.platform_id = - bswap_16(name_record.platform_id); - name_record.encoding_id = - bswap_16(name_record.encoding_id); - name_record.name_id = bswap_16(name_record.name_id); -#endif // LITTLE_ENDIAN - if (name_record.platform_id == 1 && - name_record.encoding_id == 0 && - name_record.name_id == 6) { - // Postscript name in Mac OS Roman - // - // The font name in Mac OS Roman encoding is - // sufficient to obtain an ASCII PostScript name (and - // is required by OpenType specification), while the - // Windows platform uses a UCS-2 string that would - // require conversion. -#ifdef LITTLE_ENDIAN - name_record.length = bswap_16(name_record.length); - name_record.offset = bswap_16(name_record.offset); -#endif // LITTLE_ENDIAN - - char *buffer = new char[name_record.length + 1]; - - memcpy(buffer, - &font_data[name_offset + - naming_table_header.string_offset + - name_record.offset], - name_record.length); - buffer[name_record.length] = '\0'; - font_name = buffer; - - delete [] buffer; - } - if (name_record.platform_id == 1 && - name_record.name_id == 20) { - // PostScript CID findfont name - // - // encoding_id Macintosh CMap - // --------------------------- - // 1 83pv-RKSJ-H - // 2 B5pc-H - // 3 KSCpc-EUC-H - // 25 GBpc-EUC-H - cid_encoding_id = name_record.encoding_id; - // The actual Macintosh encoding CMap name is of no - // further use. Note that Adobe currently only - // actively maintains the Unicode based CMaps. - } - } - - return true; - } - - bool font_embed_t::parse_ttf_header( - std::string &font_name, double *font_bbox, - std::map &cid_map, - std::vector &char_strings, - const std::vector &font_data) - { - cid_map.clear(); - char_strings.clear(); - - struct ttf_offset_table_s { - fixed_t sfnt_version; - uint16_t num_tables; - uint16_t search_range; - uint16_t entry_selector; - uint16_t range_shift; - } offset_table; - - memcpy(&offset_table, &font_data[0], - sizeof(struct ttf_offset_table_s)); -#ifdef LITTLE_ENDIAN - offset_table.sfnt_version = - bswap_32(offset_table.sfnt_version); - offset_table.num_tables = bswap_16(offset_table.num_tables); -#endif // LITTLE_ENDIAN - if (offset_table.sfnt_version != 0x00010000) { - return false; - } - - size_t name_offset = 0; - //size_t name_length = 0; - size_t head_offset = 0; - //size_t head_length = 0; - size_t cmap_offset = 0; - //size_t cmap_length = 0; - size_t post_offset = 0; - //size_t post_length = 0; - - for (uint16_t i = 0; i < offset_table.num_tables; i++) { - struct ttf_table_directory_s { - char tag[4]; - uint32_t check_sum; - uint32_t offset; - uint32_t length; - } table_directory; - - memcpy(&table_directory, - &font_data[sizeof(struct ttf_offset_table_s) + i * - sizeof(struct ttf_table_directory_s)], - sizeof(struct ttf_table_directory_s)); -#ifdef LITTLE_ENDIAN - table_directory.offset = - bswap_32(table_directory.offset); - table_directory.length = - bswap_32(table_directory.length); -#endif // LITTLE_ENDIAN -#if 0 - fprintf(stderr, "%s:%d: tag = %c%c%c%c, offset = %u, " - "length = %u\n", __FILE__, __LINE__, - table_directory.tag[0], table_directory.tag[1], - table_directory.tag[2], table_directory.tag[3], - table_directory.offset, table_directory.length); -#endif - if (strncmp(table_directory.tag, "name", 4) == 0) { - name_offset = table_directory.offset; - //name_length = table_directory.length; - } - else if (strncmp(table_directory.tag, "head", 4) == 0) { - head_offset = table_directory.offset; - //head_length = table_directory.length; - } - else if (strncmp(table_directory.tag, "cmap", 4) == 0) { - cmap_offset = table_directory.offset; - //cmap_length = table_directory.length; - } - else if (strncmp(table_directory.tag, "post", 4) == 0) { - post_offset = table_directory.offset; - //post_length = table_directory.length; - } - } - - // name - - struct ttf_naming_table_header_s { - uint16_t format; - uint16_t count; - uint16_t string_offset; - } naming_table_header; - - memcpy(&naming_table_header, - &font_data[name_offset], - sizeof(struct ttf_naming_table_header_s)); -#ifdef LITTLE_ENDIAN - naming_table_header.format = - bswap_16(naming_table_header.format); - naming_table_header.count = - bswap_16(naming_table_header.count); - naming_table_header.string_offset = - bswap_16(naming_table_header.string_offset); -#endif // LITTLE_ENDIAN - - for (uint16_t i = 0; i < naming_table_header.count; i++) { - struct ttf_name_record_s { - uint16_t platform_id; - uint16_t encoding_id; - uint16_t language_id; - uint16_t name_id; - uint16_t length; - uint16_t offset; - } name_record; - - memcpy( - &name_record, - &font_data[name_offset + - sizeof(struct ttf_naming_table_header_s) + - i * sizeof(struct ttf_name_record_s)], - sizeof(struct ttf_name_record_s)); -#ifdef LITTLE_ENDIAN - name_record.platform_id = - bswap_16(name_record.platform_id); - name_record.encoding_id = - bswap_16(name_record.encoding_id); - name_record.name_id = bswap_16(name_record.name_id); -#endif // LITTLE_ENDIAN - // the font name in mac os roman encoding is good enough - // to obtain an ASCII post_script name, while the windows - // platform uses a utF-16 string that would require - // conversion. - if (name_record.platform_id == 1 && - name_record.encoding_id == 0 && - name_record.name_id == 6) { -#ifdef LITTLE_ENDIAN - name_record.length = bswap_16(name_record.length); - name_record.offset = bswap_16(name_record.offset); -#endif // LITTLE_ENDIAN - - char *buffer = new char[name_record.length + 1]; - - memcpy(buffer, - &font_data[name_offset + - naming_table_header.string_offset + - name_record.offset], - name_record.length * sizeof(char)); - buffer[name_record.length] = '\0'; - font_name = buffer; - - delete [] buffer; - } - else if (name_record.platform_id == 3 && - name_record.encoding_id == 1 && - name_record.name_id == 6) { -#ifdef LITTLE_ENDIAN - name_record.length = bswap_16(name_record.length); - name_record.offset = bswap_16(name_record.offset); -#endif // LITTLE_ENDIAN - - // Very ugly UCS-2 to ASCII conversion, but should - // work for most font names - char *buffer = - new char[(name_record.length >> 1) + 1]; - - for (uint16_t j = 0; j < (name_record.length >> 1); - j++) { - buffer[j] = - font_data[name_offset + - naming_table_header.string_offset + - name_record.offset + j * 2 + 1]; - } - buffer[name_record.length >> 1] = '\0'; - font_name = buffer; - - delete [] buffer; - } - } - - // head - - struct ttf_head_table_s { - fixed_t version; - fixed_t font_revision; - uint32_t check_sum_adjustment; - uint32_t magic_number; - uint16_t flags; - uint16_t units_per_em; - char created[8]; - char modified[8]; - int16_t x_min; - int16_t y_min; - int16_t x_max; - int16_t y_max; - uint16_t mac_style; - uint16_t lowest_rec_ppem; - int16_t font_direction_hint; - int16_t index_to_loc_format; - int16_t glyph_data_format; - } head_table; - - memcpy(&head_table, &font_data[head_offset], - sizeof(struct ttf_head_table_s)); -#ifdef LITTLE_ENDIAN - head_table.units_per_em = bswap_16(head_table.units_per_em); - head_table.x_min = bswap_16(head_table.x_min); - head_table.y_min = bswap_16(head_table.y_min); - head_table.x_max = bswap_16(head_table.x_max); - head_table.y_max = bswap_16(head_table.y_max); -#endif // LITTLE_ENDIAN - - font_bbox[0] = - (double)head_table.x_min / head_table.units_per_em; - font_bbox[1] = - (double)head_table.y_min / head_table.units_per_em; - font_bbox[2] = - (double)head_table.x_max / head_table.units_per_em; - font_bbox[3] = - (double)head_table.y_max / head_table.units_per_em; - - // post - - struct ttf_post_script_table_s { - fixed_t format_type; - fixed_t italic_angle; - int16_t underline_position; - int16_t underline_thickness; - uint32_t is_fixed_pitch; - uint32_t min_mem_type42; - uint32_t max_mem_type42; - uint32_t min_mem_type1; - uint32_t max_mem_type1; - } post_script_table; - - memcpy(&post_script_table, - &font_data[post_offset], - sizeof(struct ttf_post_script_table_s)); - -#ifdef LITTLE_ENDIAN - post_script_table.format_type = - bswap_32(post_script_table.format_type); - post_script_table.min_mem_type42 = - bswap_32(post_script_table.min_mem_type42); - post_script_table.max_mem_type42 = - bswap_32(post_script_table.max_mem_type42); -#endif // LITTLE_ENDIAN - - size_t offset_current = post_offset; - -#if 0 - if (post_script_table.format_type == 0x00010000) { - // Exactly the 258 glyphs in the standard Macintosh glyph - // set - } -#endif - if (post_script_table.format_type == 0x00020000) { - // Version required by TrueType-based fonts to be used on - // Windows - // - // numberOfGlyphs, glyphNameIndex[numGlyphs], - // names[numberNewGlyphs] table - - uint16_t num_glyphs; - - memcpy(&num_glyphs, - &font_data[post_offset + - sizeof(struct ttf_post_script_table_s)], - sizeof(uint16_t)); -#ifdef LITTLE_ENDIAN - num_glyphs = bswap_16(num_glyphs); -#endif // LITTLE_ENDIAN - - uint16_t *glyph_name_index = new uint16_t[num_glyphs]; - - memcpy(glyph_name_index, - &font_data[post_offset + - sizeof(struct ttf_post_script_table_s) + - sizeof(uint16_t)], - num_glyphs * sizeof(uint16_t)); -#ifdef LITTLE_ENDIAN - for (uint16_t i = 0; i < num_glyphs; i++) { - glyph_name_index[i] = bswap_16(glyph_name_index[i]); - } -#endif // LITTLE_ENDIAN - - size_t max_glyph_name_index = 0; - for (int i = num_glyphs - 1; i >= 0; i--) { - if (glyph_name_index[i] > max_glyph_name_index) { - max_glyph_name_index = glyph_name_index[i]; - } - } - - std::string *glyph_name = - new std::string[max_glyph_name_index - 258 + 1]; - - offset_current += - sizeof(struct ttf_post_script_table_s) + - (num_glyphs + 1) * sizeof(uint16_t); - for (uint16_t i = 0; i <= max_glyph_name_index - 258; i++) { - uint8_t length; - - memcpy(&length, &font_data[offset_current], - sizeof(uint8_t)); - offset_current += sizeof(uint8_t); - - char *buffer = new char[length + 1UL]; - - memcpy(buffer, &font_data[offset_current], - length * sizeof(uint8_t)); - offset_current += length * sizeof(uint8_t); - buffer[length] = '\0'; - glyph_name[i] = buffer; - - delete [] buffer; - } - - char_strings.resize(num_glyphs); -#include "table/macintoshordering.h" - for (uint16_t glyph = 0; glyph < num_glyphs; glyph++) { - char_strings[glyph] = glyph_name_index[glyph] >= 258 ? - glyph_name[glyph_name_index[glyph] - 258].c_str() : - macintosh_ordering[glyph_name_index[glyph]]; - } - - delete [] glyph_name_index; - delete [] glyph_name; - } - else if (post_script_table.format_type == 0x00030000) { - // No PostScript name information is provided for the - // glyphs - - // Do nothing, cid_map will be initialized with standard - // Adobe glyph names once cmap is read - } - else { - fprintf(stderr, "%s:%d: unsupported post table format " - "0x%08x\n", __FILE__, __LINE__, - post_script_table.format_type); - - return false; - } -#if 0 - if (post_script_table.format_type == 0x00025000) { - // Pure subset/simple reordering of the standard Macintosh - // glyph set. Deprecated as of OpenType Specification v1.3 - // - // numberOfGlyphs, offset[numGlyphs] - return false; - } -#endif - - // cmap - - struct ttf_mapping_table_s { - uint16_t version; - uint16_t num_encoding_tables; - } mapping_table; - - memcpy(&mapping_table, &font_data[cmap_offset], - sizeof(struct ttf_mapping_table_s)); -#ifdef LITTLE_ENDIAN - mapping_table.num_encoding_tables = - bswap_16(mapping_table.num_encoding_tables); -#endif // LITTLE_ENDIAN - - uint32_t *subtable_offset = - new uint32_t[mapping_table.num_encoding_tables]; - - for (uint16_t i = 0; - i < mapping_table.num_encoding_tables; i++) { - struct ttf_encoding_table_s { - uint16_t platform_id; - uint16_t encoding_id; - uint32_t offset; - } encoding_table; - - memcpy( - &encoding_table, - &font_data[cmap_offset + - sizeof(struct ttf_mapping_table_s) + - i * sizeof(struct ttf_encoding_table_s)], - sizeof(struct ttf_encoding_table_s)); -#ifdef LITTLE_ENDIAN - encoding_table.platform_id = - bswap_16(encoding_table.platform_id); - encoding_table.encoding_id = - bswap_16(encoding_table.encoding_id); - encoding_table.offset = bswap_32(encoding_table.offset); -#endif // LITTLE_ENDIAN - subtable_offset[i] = cmap_offset + encoding_table.offset; - } - - int priority_max = 0; - - for (uint16_t i = 0; - i < mapping_table.num_encoding_tables; i++) { - struct ttf_encoding_subtable_common_s { - uint16_t format; - uint16_t length; - uint16_t language; - } encoding_subtable_common; - - memcpy(&encoding_subtable_common, - &font_data[subtable_offset[i]], - sizeof(struct ttf_encoding_subtable_common_s)); -#ifdef LITTLE_ENDIAN - encoding_subtable_common.format = - bswap_16(encoding_subtable_common.format); - encoding_subtable_common.length = - bswap_16(encoding_subtable_common.length); - encoding_subtable_common.language = - bswap_16(encoding_subtable_common.language); -#endif // LITTLE_ENDIAN - - offset_current = subtable_offset[i] + - sizeof(struct ttf_encoding_subtable_common_s); -#if 0 - fprintf(stderr, "%s:%d: encoding_subtable_common.format " - "= %hu\n", __FILE__, __LINE__, - encoding_subtable_common.format); - fprintf(stderr, "%s:%d: encoding_subtable_common.length " - "= %hu\n", __FILE__, __LINE__, - encoding_subtable_common.length); - fprintf(stderr, "%s:%d: encoding_subtable_common.language " - "= %hu\n", __FILE__, __LINE__, - encoding_subtable_common.language); -#endif - - int priority; - - switch(encoding_subtable_common.format) { - ///////////////////////////////////////////////////// - // 8 and 16 bit mappings - // Priority range 1, 3..5 (2 reserved for format 13) - case 0: - priority = 1; - // Byte encoding table - break; - case 2: - // High-byte mapping through table - priority = 3; - break; - case 4: - // Segment mapping to delta values - priority = 5; -#if 0 - fprintf(stderr, "%s:%d: priority = %d, priority_max " - "= %d\n", __FILE__, __LINE__, priority, - priority_max); -#endif - if (priority_max <= priority) { - parse_ttf_encoding_subtable_format4( - cid_map, font_data, offset_current, - encoding_subtable_common.length); - priority_max = priority; - } - break; - case 6: - // Trimmed table mapping - priority = 5; - break; - ///////////////////////////////////////////////////// - // 32-bit mappings - // Priority range 6..9 (2 reserved for format 13) - case 8: - // Mixed 16-bit and 32-bit coverage - priority = 6; - break; - case 10: - // Trimmed array - priority = 6; - break; - case 12: - // Segmented coverage - priority = 6; - break; - case 13: - // Last resort font - priority = 2; - break; - case 14: - // Unicode variation sequences - priority = 9; - break; - default: - delete [] subtable_offset; - return false; - } - } - - delete [] subtable_offset; - - // Regenerate cid_map from the Adobe glyph list - - if (char_strings.empty() && !cid_map.empty()) { - char_strings.resize(cid_map.size()); - for (std::map::const_iterator iterator = cid_map.begin(); - iterator != cid_map.end(); ++iterator) { - if (iterator->second < char_strings.size()) { -#include "table/adobeglyphlist.h" - - const wchar_t *lower = - std::lower_bound( - adobe_glyph_ucs, - adobe_glyph_ucs + nadobe_glyph, - iterator->first); - // The longest Adobe glyph name is 20 characters - // long (0x03b0 = upsilondieresistonos) - char buf[21]; - - if (iterator->first == L'\uffff') { - strncpy(buf, ".notdef", 8); - } - else if (lower < adobe_glyph_ucs + nadobe_glyph && - *lower == iterator->first) { - const size_t index = - lower - adobe_glyph_ucs; - - snprintf(buf, 21, "%s", adobe_glyph_name[index]); - } - else { - snprintf(buf, 21, "uni%04X", iterator->first); - } - char_strings[iterator->second] = buf; - } - } - } - - return true; - } - -#if 0 - std::vector font_embed_t::subset_otf( - const std::vector &font_data, - const std::map &glyph_usage) - { - std::vector retval; - struct otf_offset_table_s { - char sfnt_version[4]; - uint16_t num_tables; - uint16_t search_range; - uint16_t entry_selector; - uint16_t range_shift; - } offset_table; - - memcpy(&offset_table, &font_data[0], - sizeof(struct otf_offset_table_s)); - if (strncmp(offset_table.sfnt_version, "OTTO", 4) != 0 || - strncmp(offset_table.sfnt_version, "\0\1\0\0", 4) != 0) { - // Neither a OpenType, nor TrueType font -#if 0 - fprintf(stderr, "%s:%d: error: unknown sfnt_version = " - "0x%02x%02x%02x%02x\n", __FILE__, __LINE__, - offset_table.sfnt_version[0], - offset_table.sfnt_version[1], - offset_table.sfnt_version[2], - offset_table.sfnt_version[3]); -#endif - return retval; - } -#ifdef LITTLE_ENDIAN - offset_table.num_tables = bswap_16(offset_table.num_tables); -#endif // LITTLE_ENDIAN - - struct otf_table_directory_s { - char tag[4]; - uint32_t check_sum; - uint32_t offset; - uint32_t length; - }; - struct table_data_s *table_data = - new struct table_data_s[offset_table.num_tables]; - - for (uint16_t i = 0; i < offset_table.num_tables; i++) { - struct otf_table_directory_s table_directory; - - memcpy(&table_directory, - &font_data[sizeof(struct otf_offset_table_s) + i * - sizeof(struct otf_table_directory_s)], - sizeof(struct otf_table_directory_s)); -#ifdef LITTLE_ENDIAN - table_directory.offset = - bswap_32(table_directory.offset); - table_directory.length = - bswap_32(table_directory.length); -#endif // LITTLE_ENDIAN -#if 0 - fprintf(stderr, "%s:%d: tag = %c%c%c%c, offset = %u, " - "length = %u\n", __FILE__, __LINE__, - table_directory.tag[0], table_directory.tag[1], - table_directory.tag[2], table_directory.tag[3], - table_directory.offset, table_directory.length); -#endif - memcpy(table_data[i].tag, table_directory.tag, - 4 * sizeof(char)); - table_data[i].data.resize(table_directory.length); - memcpy(&(table_data[i].data[0]), - &font_data[table_directory.offset], - table_directory.length); - } - - size_t size_count; - - size_count = sizeof(struct otf_offset_table_s) + - offset_table.num_tables * - sizeof(struct otf_table_directory_s); - for (size_t i = 0; i < offset_table.num_tables; i++) { - size_count += table_data[i].data.size(); - } - - size_t offset_current = sizeof(struct otf_offset_table_s); - size_t offset_check_sum_adjustment = 0; - bool head_table_exists = false; - - retval.resize(size_count); - memcpy(&retval[0], &font_data[0], - sizeof(struct otf_offset_table_s)); - for (size_t i = 0; i < offset_table.num_tables; i++) { - struct otf_table_directory_s table_directory; - const bool head_table = - strncmp(table_directory.tag, "head", 4) == 0; - - memcpy(table_directory.tag, table_data[i].tag, - 4 * sizeof(char)); - if (head_table) { - // Reset checkSumAdjustment in order to calculate the - // check sum of the head table - offset_check_sum_adjustment = 2 * sizeof(fixed_t); - *reinterpret_cast(&(table_data[i].data[ - offset_check_sum_adjustment])) = 0U; - // Change the offset for checkSumAdjustment to the - // global indexing - offset_check_sum_adjustment += offset_current; - head_table_exists = true; - } - table_directory.check_sum = - otf_check_sum(table_data[i].data); - table_directory.offset = size_count; - table_directory.length = table_data[i].data.size(); - - memcpy(&retval[offset_current], &table_directory, - sizeof(struct otf_table_directory_s)); - size_count += table_data[i].data.size(); - offset_current += sizeof(struct otf_table_directory_s); - } - - for (size_t i = 0; i < offset_table.num_tables; i++) { - memcpy(&retval[offset_current], &(table_data[i].data[0]), - table_data[i].data.size()); - offset_current += table_data[i].data.size(); - - const size_t padding_size = - (4U - table_data[i].data.size()) & 3U; - - memset(&retval[offset_current], '\0', padding_size); - offset_current += padding_size; - } - - if (head_table_exists) { - // Set checkSumAdjustment in the head table - *reinterpret_cast(&(retval[ - offset_check_sum_adjustment])) = - 0xb1b0afbaU - otf_check_sum(retval); - } - - return retval; - } -#endif - - } diff --git a/graf2d/mathtext/src/mathrender.cxx b/graf2d/mathtext/src/mathrender.cxx deleted file mode 100644 index 1e3db4db747cc..0000000000000 --- a/graf2d/mathtext/src/mathrender.cxx +++ /dev/null @@ -1,714 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -/// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -/// 2008-2012 Yue Shi Lai -/// -/// This library is free software; you can redistribute it and/or -/// modify it under the terms of the GNU Lesser General Public License -/// as published by the Free Software Foundation; either version 2.1 of -/// the License, or (at your option) any later version. -/// -/// This library is distributed in the hope that it will be useful, but -/// WITHOUT ANY WARRANTY; without even the implied warranty of -/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -/// Lesser General Public License for more details. -/// -/// You should have received a copy of the GNU Lesser General Public -/// License along with this library; if not, write to the Free Software -/// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -/// 02110-1301 USA - -#ifdef WIN32 -// On Windows, Disable the warning: -// "characters beyond first in wide-character constant ignored" -#pragma warning( push ) -#pragma warning( disable : 4066) -#endif - -#include -#include -#include -#include "../inc/mathrender.h" - - -//////////////////////////////////////////////////////////////////////////////// - -namespace mathtext { - - -//////////////////////////////////////////////////////////////////////////////// - - point_t::operator std::string(void) const - { - std::stringstream stream; - - stream << '(' << _x[0] << ", " << _x[1] << ')'; - - return stream.str(); - } - - const affine_transform_t affine_transform_t::identity = - affine_transform_t(1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F); - const affine_transform_t affine_transform_t::flip_y = - affine_transform_t(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F); - - -//////////////////////////////////////////////////////////////////////////////// - - affine_transform_t affine_transform_t:: - translate(const float tx, const float ty) - { - return affine_transform_t(1.0F, 0.0F, 0.0F, 1.0F, tx, ty); - } - - -//////////////////////////////////////////////////////////////////////////////// - - affine_transform_t affine_transform_t:: - scale(const float sx, const float sy) - { - return affine_transform_t(sx, 0.0F, 0.0F, sy, 0.0F, 0.0F); - } - - -//////////////////////////////////////////////////////////////////////////////// - - affine_transform_t affine_transform_t::rotate(const float angle) - { - float sin_angle; - float cos_angle; - - sin_angle = sin(angle); - cos_angle = cos(angle); - - return affine_transform_t(cos_angle, sin_angle, - -sin_angle, cos_angle, 0, 0); - } - - -//////////////////////////////////////////////////////////////////////////////// - - affine_transform_t::operator std::string(void) const - { - std::stringstream stream; - - stream << '(' << _a[0] << ", " << _a[1] << ", 0)" << std::endl; - stream << '(' << _a[2] << ", " << _a[3] << ", 0)" << std::endl; - stream << '(' << _a[4] << ", " << _a[5] << ", 1)"; - - return stream.str(); - } - -#ifdef __INTEL_COMPILER -#pragma warning(push) -#pragma warning(disable: 869) -#endif // __INTEL_COMPILER - - -//////////////////////////////////////////////////////////////////////////////// - - bool math_text_renderer_t::is_cyrillic(const wchar_t c) - { - return c >= L'\u0400' && c <= L'\u052f'; - } - - -//////////////////////////////////////////////////////////////////////////////// - - bool math_text_renderer_t::is_cjk(const wchar_t c) - { - return - // Acceleration when most characters are below the CJK - // Radicals Supplement - c >= L'\u2e80' && - (// CJK Radicals Supplement ... Yi Radicals - (/* c >= L'\u2e80' && */ c <= L'\ua4cf') || - // Modifier Tone Letters - (c >= L'\ua700' && c <= L'\ua71f') || - // Hangul Syllables - (c >= L'\uac00' && c <= L'\ud7af') || - // CJK Compatibility Ideographs - (c >= L'\uf900' && c <= L'\ufaff') || - // Vertical Forms - (c >= L'\ufe10' && c <= L'\ufe1f') || - // CJK Compatibility Forms - (c >= L'\ufe30' && c <= L'\ufe4f') || - // Halfwidth and Fullwidth Forms - (c >= L'\uff00' && c <= L'\uffef') || - // CJK Unified Ideographs, Extension B - (c >= L'\U00020000' && c <= L'\U0002a6df') || - // CJK Unified Ideographs, Extension C - (c >= L'\U0002a700' && c <= L'\U0002b73f') || - // CJK Compatibility Ideographs - (c >= L'\U0002f800' && c <= L'\U0002fa1f')); - } - - -#if 0 -//////////////////////////////////////////////////////////////////////////////// - - bool math_text_renderer_t::is_wgl_4(const wchar_t c) - { - return true; - } -#endif - - -//////////////////////////////////////////////////////////////////////////////// -/// @see http://www.w3.org/International/questions/qa-scripts -/// @see http://www.unicode.org/reports/tr9/tr9-21.html - - bool math_text_renderer_t::is_right_to_left(const wchar_t c) - { - return - (// Hebrew ... N'Ko - (c >= L'\u0590' && c <= L'\u07ff') || - // Tifinagh - (c >= L'\u2d30' && c <= L'\u2d7f') || - // Hebrew Presentation Forms ... Arabic Presentation - // Forms A - (c >= L'\ufb1d' && c <= L'\ufdff') || - // Arabic Presentation Forms B - (c >= L'\ufb1d' && c <= L'\ufb4f')); - } - - -#if 0 -//////////////////////////////////////////////////////////////////////////////// - - bool math_text_renderer_t::is_cjk_punctuation_open(const wchar_t c) - { - return false; - } - - -//////////////////////////////////////////////////////////////////////////////// - - bool math_text_renderer_t::is_cjk_punctuation_closed(const wchar_t c) - { - return false; - } -#endif - - -//////////////////////////////////////////////////////////////////////////////// - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const math_text_t::box_t &box, - const unsigned int style) - { - set_font_size(style_size(style), FAMILY_REGULAR); - - const bounding_box_t box_bounding_box = - bounding_box(box._string, FAMILY_REGULAR); - - reset_font_size(FAMILY_REGULAR); - - return box_bounding_box; - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, - const math_text_t::box_t &box, - const unsigned int style, - const bool render_structure) - { - if (render_structure) { - // Nothing - } - set_font_size(style_size(style), FAMILY_REGULAR); - text_raw(origin[0], origin[1], box._string, FAMILY_REGULAR); - reset_font_size(FAMILY_REGULAR); - } -#ifdef __INTEL_COMPILER -#pragma warning(pop) -#endif // __INTEL_COMPILER - - -//////////////////////////////////////////////////////////////////////////////// - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const wchar_t &glyph, - const unsigned int family, const float size) - { - set_font_size(size, family); - - const std::wstring string = std::wstring(1, glyph); - const bounding_box_t math_symbol_bounding_box = - bounding_box(string, family); - - reset_font_size(family); - - return math_symbol_bounding_box; - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, const wchar_t &glyph, - const unsigned int family, const float size, - const bool render_structure) - { - set_font_size(size, family); - - const std::wstring string = std::wstring(1, glyph); - - if(render_structure) { - text_with_bounding_box(origin[0], origin[1], string, - family); - } - else { - text_raw(origin[0], origin[1], string, family); - } - reset_font_size(family); - } - - -//////////////////////////////////////////////////////////////////////////////// - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const math_text_t::math_symbol_t &math_symbol, - const unsigned int style) - { - const unsigned int family = math_family(math_symbol); - const float size = style_size(style); - - return math_bounding_box(math_symbol._glyph, family, size); - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, - const bool render_structure) - { - const unsigned int family = math_family(math_symbol); - const float size = style_size(style); - - math_text(origin, math_symbol._glyph, family, size, - render_structure); - } - - -//////////////////////////////////////////////////////////////////////////////// - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height) - { - std::vector token = - math_tokenize(math_symbol, style, height); - - if(token.empty()) - return bounding_box_t(0, 0, 0, 0, 0, 0); - - std::vector::const_iterator iterator = - token.begin(); - bounding_box_t ret = iterator->_offset + - iterator->_bounding_box; - - for (; iterator != token.end(); ++iterator) - ret = ret.merge(iterator->_offset + - iterator->_bounding_box); - - return ret; - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height, - const bool render_structure) - { - std::vector token = - math_tokenize(math_symbol, style, height); - - for (std::vector::const_iterator iterator = token.begin(); iterator != token.end(); ++iterator) - math_text(origin + - transform_pixel_to_logical().linear() * - iterator->_offset, - iterator->_extensible._glyph, - iterator->_extensible._family, - iterator->_extensible._size, render_structure); - } - - -//////////////////////////////////////////////////////////////////////////////// -/// A field can be a math symbol or a math list - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const std::vector:: - const_iterator &math_list_begin, - const std::vector:: - const_iterator &math_list_end, - unsigned int style) - { - std::vector token = - math_tokenize(math_list_begin, math_list_end, style); - - if(token.empty()) - return bounding_box_t(0, 0, 0, 0, 0, 0); - - std::vector::const_iterator iterator = - token.begin(); - bounding_box_t ret = iterator->_offset + - iterator->_bounding_box; - - for (; iterator != token.end(); ++iterator) - ret = ret.merge(iterator->_offset + - iterator->_bounding_box); - - return ret; - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, - const std::vector:: - const_iterator &math_list_begin, - const std::vector:: - const_iterator &math_list_end, - const unsigned int style, - const bool render_structure) - { - if(render_structure) { - point(origin[0], origin[1]); - rectangle(origin + - math_bounding_box(math_list_begin, - math_list_end, style)); - } - - std::vector::const_iterator - math_list_begin_interior = math_list_begin; - std::vector::const_iterator - math_list_end_interior = math_list_end; - bool delimiter = false; - - if(math_list_begin->_type == - math_text_t::item_t::TYPE_BOUNDARY && - (math_list_end - 1)->_type == - math_text_t::item_t::TYPE_BOUNDARY) { - ++math_list_begin_interior; - --math_list_end_interior; - delimiter = true; - } - - std::vector token = - math_tokenize(math_list_begin, math_list_end, style); - std::vector::const_iterator token_iterator = - token.begin(); - - if(delimiter) { - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - math_list_begin->_atom._nucleus._math_symbol, - style, token_iterator->_delimiter_height, - render_structure); - ++token_iterator; - } - - static const math_text_t::item_t fraction_item = - math_text_t::item_t::TYPE_GENERALIZED_FRACTION; - const std::vector::const_iterator - fraction_iterator = - std::find(math_list_begin_interior, - math_list_end_interior, fraction_item); - - if(fraction_iterator != math_list_end_interior) { - const float thickness = fraction_iterator->_length * - default_rule_thickness * style_size(style); - - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - fraction_iterator + 1, math_list_end_interior, - token_iterator->_style, - render_structure); - ++token_iterator; - if(thickness > 0) { - filled_rectangle( - origin + - transform_pixel_to_logical().linear() * - (token_iterator->_offset + - token_iterator->_bounding_box)); - ++token_iterator; - } - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - math_list_begin_interior, fraction_iterator, - token_iterator->_style, - render_structure); - ++token_iterator; - } - else - // Incrementally process a math list - for (std::vector::const_iterator iterator = math_list_begin_interior; - iterator != math_list_end_interior; ++iterator) { - switch(iterator->_type) { - case math_text_t::item_t::TYPE_ATOM: - if(render_structure) - rectangle(origin + - transform_pixel_to_logical().linear() * - (token_iterator->_offset + - token_iterator->_bounding_box)); - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - iterator->_atom, - token_iterator->_style, - render_structure); - ++token_iterator; - break; - } - // math_text_t::item_t::TYPE_KERN can be ignored - } - - if(delimiter) - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - (math_list_end - 1)-> - _atom._nucleus._math_symbol, - token_iterator->_style, - token_iterator->_delimiter_height, - render_structure); - } - - -//////////////////////////////////////////////////////////////////////////////// - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const math_text_t::field_t &field, - const unsigned int style) - { - switch(field._type) { - case math_text_t::field_t::TYPE_MATH_SYMBOL: - return math_bounding_box(field._math_symbol, style); - break; - case math_text_t::field_t::TYPE_BOX: - return math_bounding_box(field._box, style); - break; - case math_text_t::field_t::TYPE_MATH_LIST: - return math_bounding_box(field._math_list.begin(), - field._math_list.end(), style); - break; - default: - return bounding_box_t(0, 0, 0, 0, 0, 0); - } - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, - const math_text_t::field_t &field, - const unsigned int style, const bool render_structure) - { - switch(field._type) { - case math_text_t::field_t::TYPE_MATH_SYMBOL: - math_text(origin, field._math_symbol, style, - render_structure); - break; - case math_text_t::field_t::TYPE_BOX: - math_text(origin, field._box, style, render_structure); - break; - case math_text_t::field_t::TYPE_MATH_LIST: - math_text(origin, field._math_list.begin(), - field._math_list.end(), style, - render_structure); - break; - } - } - - -//////////////////////////////////////////////////////////////////////////////// -/// TeX algorithm for (three-way) atoms: -/// -/// See Knuth, The TeXbook (1986), pp. 445f. - - bounding_box_t math_text_renderer_t:: - math_bounding_box(const math_text_t::atom_t &atom, - const unsigned int style) - { - std::vector token = - math_tokenize(atom, style); - - if(token.empty()) - return bounding_box_t(0, 0, 0, 0, 0, 0); - - std::vector::const_iterator iterator = - token.begin(); - bounding_box_t ret = iterator->_offset + - iterator->_bounding_box; - - for (; iterator != token.end(); ++iterator) - ret = ret.merge(iterator->_offset + - iterator->_bounding_box); - - return ret; - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - math_text(const point_t origin, - const math_text_t::atom_t &atom, - const unsigned int style, - const bool render_structure) - { - const float x = origin[0]; - const float y = origin[1]; - - if(render_structure) { - point(x, y); - rectangle(point_t(x, y) + - math_bounding_box(atom, style)); - } - - std::vector token = - math_tokenize(atom, style); - std::vector::const_iterator token_iterator = - token.begin(); - - bounding_box_t nucleus_bounding_box; - - // Rule 11 - if(atom._type == math_text_t::atom_t::TYPE_RAD) { - if(!atom._index.empty()) { - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._index, token_iterator->_style, - render_structure); - ++token_iterator; - } - - const math_text_t::math_symbol_t - symbol_surd("\\surd", style); - - // Surd - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - symbol_surd, token_iterator->_style, - token_iterator->_delimiter_height, - render_structure); - ++token_iterator; - // Rule with clearance - filled_rectangle( - origin + transform_pixel_to_logical().linear() * - (token_iterator->_offset + - token_iterator->_bounding_box)); - // Skip the clearance token, too - token_iterator += 2; - } - if(atom._type == math_text_t::atom_t::TYPE_OP && - atom._nucleus._type == - math_text_t::field_t::TYPE_MATH_SYMBOL) - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._nucleus._math_symbol._glyph, - FAMILY_STIX_REGULAR, - style_size(style) * if_else_display(style, - large_operator_display_scale, 1.0F), - render_structure); - else - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._nucleus, token_iterator->_style, - render_structure); - - if(atom._superscript.empty() && atom._subscript.empty()) - return; - - ++token_iterator; - - if(atom._superscript.empty()) { - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._subscript, token_iterator->_style, - render_structure); - return; - } - if(atom._subscript.empty()) { - math_text(origin + - transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._superscript, token_iterator->_style, - render_structure); - return; - } - math_text(origin + transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._superscript, token_iterator->_style, - render_structure); - ++token_iterator; - math_text(origin + transform_pixel_to_logical().linear() * - token_iterator->_offset, - atom._subscript, token_iterator->_style, - render_structure); - } - - -//////////////////////////////////////////////////////////////////////////////// - - bounding_box_t math_text_renderer_t:: - bounding_box(const math_text_t &textbb, const bool display_style) - { - if(!textbb.well_formed()) - bounding_box(L"*** invalid: " + textbb.code()); - - const unsigned int initial_style = display_style ? - math_text_t::item_t::STYLE_DISPLAY : - math_text_t::item_t::STYLE_TEXT; - - return math_bounding_box(textbb._math_list._math_list, - initial_style); - } - - -//////////////////////////////////////////////////////////////////////////////// - - void math_text_renderer_t:: - text(const float x, const float y, const math_text_t &texti, - const bool display_style) - { - if(!texti.well_formed()) { - text_raw(x, y, L"*** invalid: " + texti.code()); - } - - const unsigned int initial_style = display_style ? - math_text_t::item_t::STYLE_DISPLAY : - math_text_t::item_t::STYLE_TEXT; - - if(texti._render_structure) { - point(x, y); - rectangle(point_t(x, y) + math_bounding_box( - texti._math_list._math_list, initial_style)); - } - math_text(point_t(x, y), texti._math_list._math_list, - initial_style, texti._render_structure); - } - -} -#ifdef WIN32 -#pragma warning( pop ) -#endif diff --git a/graf2d/mathtext/src/mathrenderstyle.cxx b/graf2d/mathtext/src/mathrenderstyle.cxx deleted file mode 100644 index 4efa8d2e7675f..0000000000000 --- a/graf2d/mathtext/src/mathrenderstyle.cxx +++ /dev/null @@ -1,474 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#include -#include "../inc/mathrender.h" - -///////////////////////////////////////////////////////////////////// - -namespace mathtext { - - ///////////////////////////////////////////////////////////////// - - float math_text_renderer_t:: - style_size(const unsigned int style) const - { - // Intel C++ Compiler 10.1 chokes on this if declared static - // const and using -O1: - const float size[math_text_t::item_t::NSTYLE - 1] = { - script_script_ratio, script_script_ratio, - script_ratio, script_ratio, 1.0F, 1.0F, 1.0F, 1.0F - }; - - if(style == math_text_t::item_t::STYLE_UNKNOWN || - style >= math_text_t::item_t::NSTYLE) - return font_size(); - - return size[style - 1] * font_size(); - } - - bool math_text_renderer_t:: - is_display_style(const unsigned int style) const - { - switch(style) { - case math_text_t::item_t::STYLE_DISPLAY: - case math_text_t::item_t::STYLE_DISPLAY_PRIME: - return true; - default: - return false; - } - } - - bool math_text_renderer_t:: - is_script_style(const unsigned int style) const - { - switch(style) { - case math_text_t::item_t::STYLE_SCRIPT: - case math_text_t::item_t::STYLE_SCRIPT_PRIME: - case math_text_t::item_t::STYLE_SCRIPT_SCRIPT: - case math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME: - return true; - default: - return false; - } - } - - unsigned int math_text_renderer_t:: - prime_style(const unsigned int style) const - { - switch(style) { - case math_text_t::item_t::STYLE_DISPLAY: - return math_text_t::item_t::STYLE_DISPLAY_PRIME; - case math_text_t::item_t::STYLE_TEXT: - return math_text_t::item_t::STYLE_TEXT_PRIME; - case math_text_t::item_t::STYLE_SCRIPT: - return math_text_t::item_t::STYLE_SCRIPT_PRIME; - case math_text_t::item_t::STYLE_SCRIPT_SCRIPT: - return math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME; - default: - return style; - } - } - - bool math_text_renderer_t:: - is_prime_style(const unsigned int style) const - { - switch(style) { - case math_text_t::item_t::STYLE_DISPLAY_PRIME: - case math_text_t::item_t::STYLE_TEXT_PRIME: - case math_text_t::item_t::STYLE_SCRIPT_PRIME: - case math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME: - return true; - default: - return false; - } - } - - // Knuth, The TeXbook (1986), p. 441 - - unsigned int math_text_renderer_t:: - next_superscript_style(const unsigned int style) const - { - switch(style) { - case math_text_t::item_t::STYLE_DISPLAY: - case math_text_t::item_t::STYLE_TEXT: - return math_text_t::item_t::STYLE_SCRIPT; - case math_text_t::item_t::STYLE_DISPLAY_PRIME: - case math_text_t::item_t::STYLE_TEXT_PRIME: - return math_text_t::item_t::STYLE_SCRIPT_PRIME; - case math_text_t::item_t::STYLE_SCRIPT: - case math_text_t::item_t::STYLE_SCRIPT_SCRIPT: - return math_text_t::item_t::STYLE_SCRIPT_SCRIPT; - case math_text_t::item_t::STYLE_SCRIPT_PRIME: - case math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME: - return math_text_t::item_t::STYLE_SCRIPT_SCRIPT_PRIME; - default: - return style; - } - } - - unsigned int math_text_renderer_t:: - next_subscript_style(const unsigned int style) const - { - return prime_style(next_superscript_style(style)); - } - - unsigned int math_text_renderer_t:: - next_numerator_style(const unsigned int style) const - { - switch(style) { - case math_text_t::item_t::STYLE_DISPLAY: - return math_text_t::item_t::STYLE_TEXT; - case math_text_t::item_t::STYLE_DISPLAY_PRIME: - return math_text_t::item_t::STYLE_TEXT_PRIME; - default: - return next_superscript_style(style); - } - } - - unsigned int math_text_renderer_t:: - next_denominator_style(const unsigned int style) const - { - return if_else_display( - style, - static_cast( - math_text_t::item_t::STYLE_TEXT_PRIME), - next_subscript_style(style)); - } - - // The most elementary building block is the math symbol - float math_text_renderer_t::x_height(const unsigned int style) - { - const unsigned int family = FAMILY_ITALIC; - const float size = style_size(style); - - set_font_size(size, family); - - bounding_box_t math_symbol_bounding_box = - bounding_box(L"x", family); - - reset_font_size(family); - - return math_symbol_bounding_box.ascent(); - } - - float math_text_renderer_t::quad(const unsigned int style) - const - { - const float size = style_size(style); - - return size; - } - - void math_text_renderer_t:: - post_process_atom_type_initial(unsigned int &atom_type) const - { - // Rule 5, initial atom - if(atom_type == math_text_t::atom_t::TYPE_BIN) - atom_type = math_text_t::atom_t::TYPE_ORD; - } - - void math_text_renderer_t:: - post_process_atom_type_interior(unsigned int & - previous_atom_type, - unsigned int &atom_type) const - { - // Rule 5, interior/final atom - if(atom_type == math_text_t::atom_t::TYPE_BIN) - switch(previous_atom_type) { - case math_text_t::atom_t::TYPE_BIN: - case math_text_t::atom_t::TYPE_OP: - case math_text_t::atom_t::TYPE_REL: - case math_text_t::atom_t::TYPE_OPEN: - case math_text_t::atom_t::TYPE_PUNCT: - atom_type = math_text_t::atom_t::TYPE_ORD; - break; - } - // Rule 6 - else if(previous_atom_type == math_text_t::atom_t::TYPE_BIN) - switch(atom_type) { - case math_text_t::atom_t::TYPE_REL: - case math_text_t::atom_t::TYPE_CLOSE: - case math_text_t::atom_t::TYPE_PUNCT: - previous_atom_type = math_text_t::atom_t::TYPE_ORD; - break; - } - } - - bool math_text_renderer_t:: - valid_accent(bool &vertical_alignment, - const std::vector:: - const_iterator &iterator, - const std::vector:: - const_iterator &math_list_end) - const - { - if(iterator->_atom._type == math_text_t::atom_t::TYPE_ACC) { - std::vector::const_iterator - iterator_next = iterator + 1; - - vertical_alignment = true; - return iterator_next != math_list_end && - iterator_next->_type == - math_text_t::item_t::TYPE_ATOM; - } - else if(iterator->_atom.is_combining_diacritical()) { - std::vector::const_iterator - iterator_next = iterator + 1; - - vertical_alignment = false; - return iterator_next != math_list_end && - iterator_next->_type == - math_text_t::item_t::TYPE_ATOM; - } - else - return false; - } - - float math_text_renderer_t::kerning_mu(const float amount) const - { - // Rule 2 - return amount / 18.0F * font_size(); - } - - float math_text_renderer_t:: - math_spacing(unsigned int left_type, unsigned int right_type, - unsigned int style) const - { - const unsigned int left_type_modified = - left_type <= (unsigned int) math_text_t::atom_t::TYPE_INNER ? - left_type : (unsigned int) math_text_t::atom_t::TYPE_ORD; - const unsigned int right_type_modified = - right_type <= (unsigned int) math_text_t::atom_t::TYPE_INNER ? - right_type : (unsigned int) math_text_t::atom_t::TYPE_ORD; - const unsigned int space = math_text_t::atom_t:: - spacing(left_type_modified, right_type_modified, - is_script_style(style)); - float mu_skip; - - switch(space) { - case 1: mu_skip = thin_mu_skip; break; - case 2: mu_skip = med_mu_skip; break; - case 3: mu_skip = thick_mu_skip; break; - default: mu_skip = 0.0F; - } - - return kerning_mu(mu_skip); - } - - unsigned int math_text_renderer_t:: - math_family(const math_text_t::math_symbol_t &math_symbol) const - { - // Use the text font for Latin, Greek, Cyrillic and the minus - // sign, and STIX for everything else. - if(math_symbol._glyph <= L'\u017e' || - (math_symbol._glyph >= L'\u0384' && - math_symbol._glyph <= L'\u03ce') || - (math_symbol._glyph >= L'\u0400' && - math_symbol._glyph <= L'\u052f') || - math_symbol._glyph == L'\u2212') { - return math_symbol._family; - } - else { - switch(math_symbol._family) { - case FAMILY_REGULAR: - return FAMILY_STIX_REGULAR; - case FAMILY_ITALIC: - return FAMILY_STIX_ITALIC; - case FAMILY_BOLD: - return FAMILY_STIX_BOLD; - case FAMILY_BOLD_ITALIC: - return FAMILY_STIX_BOLD_ITALIC; - case FAMILY_STIX_REGULAR: - case FAMILY_STIX_ITALIC: - case FAMILY_STIX_BOLD: - case FAMILY_STIX_BOLD_ITALIC: - case FAMILY_STIX_SIZE_1_REGULAR: - case FAMILY_STIX_SIZE_1_BOLD: - case FAMILY_STIX_SIZE_2_REGULAR: - case FAMILY_STIX_SIZE_2_BOLD: - case FAMILY_STIX_SIZE_3_REGULAR: - case FAMILY_STIX_SIZE_3_BOLD: - case FAMILY_STIX_SIZE_4_REGULAR: - case FAMILY_STIX_SIZE_4_BOLD: - case FAMILY_STIX_SIZE_5_REGULAR: - return math_symbol._family; - default: - return FAMILY_STIX_REGULAR; - } - } - } - - void math_text_renderer_t:: - large_family(unsigned long &nfamily, const unsigned int *&family, - const math_text_t::math_symbol_t &math_symbol) const - { - static const unsigned long nlarge_family = 5; - static const unsigned int - large_family_regular[nlarge_family] = { - FAMILY_STIX_REGULAR, - FAMILY_STIX_SIZE_1_REGULAR, - FAMILY_STIX_SIZE_2_REGULAR, - FAMILY_STIX_SIZE_3_REGULAR, - FAMILY_STIX_SIZE_4_REGULAR, - }; - static const unsigned int - large_family_bold[nlarge_family] = { - FAMILY_STIX_BOLD, - FAMILY_STIX_SIZE_1_BOLD, - FAMILY_STIX_SIZE_2_BOLD, - FAMILY_STIX_SIZE_3_BOLD, - FAMILY_STIX_SIZE_4_BOLD, - }; - - nfamily = nlarge_family; - family = math_symbol.bold() ? - large_family_bold : large_family_regular; - } - - void math_text_renderer_t:: - extensible_glyph(wchar_t glyph[4], unsigned long &nrepeat, - const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height) - { - // See Knuth, The METAFONTbook (1986), p. 318 - enum { - GLYPH_TOP = 0, - GLYPH_MIDDLE, - GLYPH_BOTTOM, - GLYPH_REPEATABLE, - NGLYPH - }; - - switch(math_symbol._glyph) { - case L'(': - glyph[GLYPH_TOP] = L'\u239b'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u239d'; - glyph[GLYPH_REPEATABLE] = L'\u239c'; - break; - case L')': - glyph[GLYPH_TOP] = L'\u239e'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u23a0'; - glyph[GLYPH_REPEATABLE] = L'\u239f'; - break; - case L'[': - glyph[GLYPH_TOP] = L'\u23a1'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u23a3'; - glyph[GLYPH_REPEATABLE] = L'\u23a2'; - break; - case L']': - glyph[GLYPH_TOP] = L'\u23a4'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u23a6'; - glyph[GLYPH_REPEATABLE] = L'\u23a5'; - break; - case L'{': - glyph[GLYPH_TOP] = L'\u23a7'; - glyph[GLYPH_MIDDLE] = L'\u23a8'; - glyph[GLYPH_BOTTOM] = L'\u23a9'; - glyph[GLYPH_REPEATABLE] = L'\u23aa'; - break; - case L'|': - glyph[GLYPH_TOP] = math_symbol._glyph; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = math_symbol._glyph; - glyph[GLYPH_REPEATABLE] = math_symbol._glyph; - break; - case L'}': - glyph[GLYPH_TOP] = L'\u23ab'; - glyph[GLYPH_MIDDLE] = L'\u23ac'; - glyph[GLYPH_BOTTOM] = L'\u23ad'; - glyph[GLYPH_REPEATABLE] = L'\u23aa'; - break; -#if 0 - // FIXME: \lmoustache, \rmoustache, \radical require - // horizontal offsets - case L'\u211a': // \lmoustache - glyph[GLYPH_TOP] = L'\0'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u23b7'; - glyph[GLYPH_REPEATABLE] = L'\u23b9'; - break; - case L'\u23b0': // \rmoustache - glyph[GLYPH_TOP] = L'\u239b'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u23a0'; - glyph[GLYPH_REPEATABLE] = L'\u239c'; - break; - case L'\u23b1': // \radical - glyph[GLYPH_TOP] = L'\u239e'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\u239d'; - glyph[GLYPH_REPEATABLE] = L'\u239f'; - break; -#endif - default: - glyph[GLYPH_TOP] = L'\0'; - glyph[GLYPH_MIDDLE] = L'\0'; - glyph[GLYPH_BOTTOM] = L'\0'; - glyph[GLYPH_REPEATABLE] = L'\0'; - } - - const unsigned int family = math_symbol._glyph == L'|' ? - FAMILY_STIX_REGULAR : FAMILY_STIX_SIZE_1_REGULAR; - const float size = style_size(style); - - if(glyph[GLYPH_REPEATABLE] != L'\0') { - bounding_box_t bounding_box_sum(0, 0, 0, 0, 0, 0); - float current_y = 0; - - for(unsigned long i = GLYPH_TOP; i <= GLYPH_BOTTOM; - i++) { - if(glyph[i] != L'\0') { - bounding_box_t glyph_bounding_box = - math_bounding_box(glyph[i], family, size); - - current_y += glyph_bounding_box.descent(); - bounding_box_sum = bounding_box_sum. - merge(point_t(0, current_y) + - glyph_bounding_box); - current_y += glyph_bounding_box.ascent(); - } - } - - const bounding_box_t bounding_box_repeatable = - math_bounding_box(glyph[GLYPH_REPEATABLE], family, - size); - const float remaining_height = - height - bounding_box_sum.height(); - unsigned long repeat_ratio = 0; - if (bounding_box_repeatable.height() !=0) { - repeat_ratio = - (unsigned long)ceil( - remaining_height / - bounding_box_repeatable.height()); - } - nrepeat = glyph[GLYPH_MIDDLE] == L'\0' ? - repeat_ratio : ((repeat_ratio + 1UL) >> 1); - } - else - nrepeat = 0; - } - - // Font parameters -#include "table/mathfontparam.h" - -} diff --git a/graf2d/mathtext/src/mathrendertoken.cxx b/graf2d/mathtext/src/mathrendertoken.cxx deleted file mode 100644 index 420c4aa0da7a9..0000000000000 --- a/graf2d/mathtext/src/mathrendertoken.cxx +++ /dev/null @@ -1,897 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#include -#include "../inc/mathrender.h" - -///////////////////////////////////////////////////////////////////// - -namespace mathtext { - - ///////////////////////////////////////////////////////////////// - // Math List Tokenization - - std::vector - math_text_renderer_t:: - math_tokenize(const math_text_t::math_symbol_t &math_symbol, - const unsigned int style, const float height) - { - if(math_symbol._glyph == L'.') - return std::vector(); - - enum { - GLYPH_TOP = 0, - GLYPH_MIDDLE, - GLYPH_BOTTOM, - GLYPH_REPEATABLE, - NGLYPH - }; - const unsigned int family = math_family(math_symbol); - const float size = style_size(style); - const bounding_box_t normal_bounding_box = - math_bounding_box(math_symbol._glyph, family, size); - - if(normal_bounding_box.height() >= height) { - const math_token_t token(normal_bounding_box, - math_symbol._glyph, family, - size); - - return std::vector(1, token); - } - - unsigned long nmath_symbol_large_family; - const unsigned int *math_symbol_large_family; - - large_family(nmath_symbol_large_family, - math_symbol_large_family, math_symbol); - - for(unsigned int i = 0; i < nmath_symbol_large_family; i++) { - const bounding_box_t large_bounding_box = - math_bounding_box(math_symbol._glyph, - math_symbol_large_family[i], size); - - if(large_bounding_box.height() >= height) { - const math_token_t token(large_bounding_box, - math_symbol._glyph, - math_symbol_large_family[i], - size); - - return std::vector(1, token); - } - } - - // Extensible glyph after the TFM charlist mechanism, see - // Knuth, The METAFONTbook (1986), p. 317f. - - wchar_t glyph[NGLYPH]; - unsigned long nrepeat; - - extensible_glyph(glyph, nrepeat, math_symbol, style, height); - - if(glyph[GLYPH_BOTTOM] != L'\0' && - glyph[GLYPH_REPEATABLE] != L'\0') { - static const unsigned int extensible_family = - math_symbol._glyph == L'|' ? FAMILY_STIX_REGULAR : - FAMILY_STIX_SIZE_1_REGULAR; - const bounding_box_t bounding_box_bottom = - math_bounding_box(glyph[GLYPH_BOTTOM], - extensible_family, size); - std::vector token_list; - - token_list.push_back(math_token_t( - bounding_box_bottom, glyph[GLYPH_BOTTOM], - extensible_family, size)); - float current_y = 0; - - current_y += bounding_box_bottom.ascent(); - for(unsigned long i = 0; i < nrepeat; i++) { - const bounding_box_t bounding_box_repeatable = - math_bounding_box(glyph[GLYPH_REPEATABLE], - extensible_family, size); - - current_y += bounding_box_repeatable.descent(); - token_list.push_back(math_token_t( - point_t(0, current_y), bounding_box_repeatable, - glyph[GLYPH_REPEATABLE], extensible_family, - size)); - current_y += bounding_box_repeatable.ascent(); - } - if(glyph[GLYPH_MIDDLE] != L'\0') { - const bounding_box_t bounding_box_middle = - math_bounding_box(glyph[GLYPH_MIDDLE], - extensible_family, size); - - current_y += bounding_box_middle.descent(); - token_list.push_back(math_token_t( - point_t(0, current_y), bounding_box_middle, - glyph[GLYPH_MIDDLE], extensible_family, size)); - current_y += bounding_box_middle.ascent(); - for(unsigned long i = 0; i < nrepeat; i++) { - const bounding_box_t bounding_box_repeatable = - math_bounding_box(glyph[GLYPH_REPEATABLE], - extensible_family, size); - - current_y += bounding_box_repeatable.descent(); - token_list.push_back(math_token_t( - point_t(0, current_y), - bounding_box_repeatable, - glyph[GLYPH_REPEATABLE], extensible_family, - size)); - current_y += bounding_box_repeatable.ascent(); - } - } - - const bounding_box_t bounding_box_top = - math_bounding_box(glyph[GLYPH_TOP], - extensible_family, size); - - current_y += bounding_box_top.descent(); - token_list.push_back(math_token_t( - point_t(0, current_y), bounding_box_top, - glyph[GLYPH_TOP], extensible_family, size)); - - return token_list; - } - - const math_token_t token(normal_bounding_box, - math_symbol._glyph, family, size); - - return std::vector(1, token); - } - - std::vector - math_text_renderer_t:: - math_tokenize(const std::vector:: - const_iterator &math_list_begin, - const std::vector:: - const_iterator &math_list_end, - const unsigned int style) - { - const float size = style_size(style); - const float style_axis_height = axis_height * size; - unsigned int previous_atom_type = - math_text_t::atom_t::TYPE_UNKNOWN; - float current_x = 0; - bool has_accent = false; - - // Rule 19 - std::vector::const_iterator - math_list_begin_interior = math_list_begin; - std::vector::const_iterator - math_list_end_interior = math_list_end; - static const math_text_t::item_t fraction_item = - math_text_t::item_t::TYPE_GENERALIZED_FRACTION; - const std::vector::const_iterator - fraction_iterator = - std::find(math_list_begin_interior, - math_list_end_interior, fraction_item); - const bool generalized_fraction = - fraction_iterator != math_list_end_interior; - bool delimiter = false; - float delimiter_height = 0.f; - bounding_box_t bounding_box_delimiter_left(0, 0, 0, 0, 0, 0); - bounding_box_t bounding_box_delimiter_right(0, 0, 0, 0, 0, 0); - - if(math_list_begin->_type == - math_text_t::item_t::TYPE_BOUNDARY && - (math_list_end - 1)->_type == - math_text_t::item_t::TYPE_BOUNDARY) { - ++math_list_begin_interior; - --math_list_end_interior; - delimiter = true; - - const bounding_box_t bounding_box_interior = - math_bounding_box(math_list_begin_interior, - math_list_end_interior, style); - const float extension = - std::max(bounding_box_interior.ascent() - - style_axis_height, - bounding_box_interior.descent() + - style_axis_height); - - delimiter_height = extension * 0.002F * delimiter_factor; - if(generalized_fraction) - // Rule 15e - delimiter_height = std::max(delimiter_height, - if_else_display(style, delim_1, delim_2) * size); - - bounding_box_delimiter_left = - math_bounding_box(math_list_begin->_atom. - _nucleus._math_symbol, - style, delimiter_height); - bounding_box_delimiter_right = - math_bounding_box((math_list_end - 1)->_atom. - _nucleus._math_symbol, - style, delimiter_height); - } - - std::vector token_list; - - if(delimiter) { - // Standard advance mode - - // post_process_atom_type_initial(atom_type) is not - // necessary, since the current item is guaranteed not to - // be of type Bin. - - // FIXME: Must be in starting style. - - const float shift_delimiter_left = style_axis_height - - bounding_box_delimiter_left.vertical_center(); - - token_list.push_back(math_token_t( - point_t(current_x, shift_delimiter_left), - bounding_box_delimiter_left, style, - delimiter_height)); - - current_x += bounding_box_delimiter_left.advance(); - previous_atom_type = math_list_begin->_atom._type; - } - - if(generalized_fraction) { - // Rule 15a, 15b - const float thickness = fraction_iterator->_length * - default_rule_thickness * size; - const bounding_box_t numerator_bounding_box = - math_bounding_box(math_list_begin_interior, - fraction_iterator, - next_numerator_style(style)); - const bounding_box_t denominator_bounding_box = - math_bounding_box(fraction_iterator + 1, - math_list_end_interior, - next_denominator_style(style)); - const float min_shift_up = - if_else_display(style, num_1, - thickness > 0 ? num_2 : num_3) * - size; - const float min_shift_down = - if_else_display(style, denom_1, denom_2) * size; - float shift_up; - float shift_down; - - if(thickness <= 0) { - // Rule 15c (\atop) - const float min_clearance = - if_else_display(style, 7.0F, 3.0F) * - default_rule_thickness * size; - const float actual_clearance = - (min_shift_up - - numerator_bounding_box.descent()) - - (denominator_bounding_box.ascent() - - min_shift_down); - - if(actual_clearance < min_clearance) { - const float difference = 0.5F * - (min_clearance - actual_clearance); - - shift_up = min_shift_up + difference; - shift_down = min_shift_down + difference; - } - else { - shift_up = min_shift_up; - shift_down = min_shift_down; - } - } - else { - // Rule 15d (\over) - const float min_bar_clearance = - if_else_display(style, 3.0F, 1.0F) * thickness; - const float actual_numerator_clearance = - (min_shift_up - - numerator_bounding_box.descent()) - - (style_axis_height + 0.5F * thickness); - const float actual_denominator_clearance = - (style_axis_height - 0.5F * thickness) - - (denominator_bounding_box.ascent() - - min_shift_down); - - if(actual_numerator_clearance < - min_bar_clearance) { - const float difference = - (min_bar_clearance - - actual_numerator_clearance); - - shift_up = min_shift_up + difference; - } - else - shift_up = min_shift_up; - if(actual_denominator_clearance < - min_bar_clearance) { - const float difference = - (min_bar_clearance - - actual_denominator_clearance); - - shift_down = min_shift_down + difference; - } - else - shift_down = min_shift_down; - } - - const float horizontal_center_difference = - numerator_bounding_box.horizontal_center() - - denominator_bounding_box.horizontal_center(); - float horizontal_shift_numerator; - float horizontal_shift_denominator; - - if(horizontal_center_difference > 0) { - horizontal_shift_numerator = 0; - horizontal_shift_denominator = - horizontal_center_difference; - } - else { - horizontal_shift_numerator = - -horizontal_center_difference; - horizontal_shift_denominator = 0; - } - - token_list.push_back(math_token_t( - point_t(current_x + horizontal_shift_denominator, - -shift_down), - denominator_bounding_box, - next_denominator_style(style))); - if(thickness > 0) { -#if 0 - const float constrained_thickness = - std::max(1.0F, thickness); -#endif - const float left = - std::min(numerator_bounding_box.left(), - denominator_bounding_box.left()); - const float right = - std::max(numerator_bounding_box.right(), - denominator_bounding_box.right()); - - token_list.push_back(math_token_t( - point_t(current_x + left, - style_axis_height - 0.5F * thickness), - bounding_box_t(0, 0, right - left, thickness, - 0, 0), - style)); - } - token_list.push_back(math_token_t( - point_t(current_x + horizontal_shift_numerator, - shift_up), - numerator_bounding_box, - next_numerator_style(style))); - - const float advance = - std::max(horizontal_shift_numerator + - numerator_bounding_box.left() + - numerator_bounding_box.right(), - horizontal_shift_denominator + - denominator_bounding_box.left() + - denominator_bounding_box.right()); - - current_x += advance; - } - else - // Incrementally process a math list - for (std::vector::const_iterator iterator = math_list_begin_interior; - iterator != math_list_end_interior; ++iterator) { - unsigned int atom_type; - bounding_box_t item_bounding_box; - unsigned int current_style = has_accent ? - prime_style(style) : style; - bool accent; - bool vertical_alignment; - - switch(iterator->_type) { - case math_text_t::item_t::TYPE_ATOM: - atom_type = iterator->_atom._type; - item_bounding_box = - math_bounding_box(iterator->_atom, - current_style); - accent = valid_accent(vertical_alignment, - iterator, math_list_end); - if(accent) { - // Accent advance mode - const std::vector:: - const_iterator iterator_next = - iterator + 1; - const bounding_box_t next_item_bounding_box = - math_bounding_box(iterator_next->_atom, - style); - const float horizontal_shift = - (iterator == math_list_begin ? 0.0F : - math_spacing(previous_atom_type, - atom_type, style)) + - next_item_bounding_box. - horizontal_center() + - 0.5F * next_item_bounding_box. - italic_correction() - - item_bounding_box.horizontal_center(); - const float vertical_shift = - vertical_alignment ? - std::max(0.0F, - next_item_bounding_box.ascent() - - x_height(style)) : 0.0F; - - token_list.push_back(math_token_t( - point_t(current_x + horizontal_shift, - vertical_shift), - item_bounding_box, style)); - has_accent = true; - } - else { - // Standard advance mode - if(iterator == math_list_begin) - post_process_atom_type_initial(atom_type); - else { - post_process_atom_type_interior( - previous_atom_type, atom_type); - - const float horizontal_shift = - math_spacing(previous_atom_type, - atom_type, - current_style); - - current_x += - horizontal_shift; - } - - token_list.push_back(math_token_t( - point_t(current_x, 0), item_bounding_box, - current_style)); - current_x += item_bounding_box.advance(); - has_accent = false; - previous_atom_type = atom_type; - } - break; - case math_text_t::item_t::TYPE_KERN: - // Rule 2 - current_x += kerning_mu(iterator->_length); - break; - } - } - - // Rule 19 (again) - if(delimiter) { - unsigned int atom_type = - (math_list_end - 1)->_atom._type; - // Standard advance mode - - // FIXME: Must be in starting style. - - post_process_atom_type_interior(previous_atom_type, - atom_type); - - const float horizontal_shift = - math_spacing(previous_atom_type, atom_type, style); - - current_x += horizontal_shift; - - const float shift_delimiter_right = style_axis_height - - bounding_box_delimiter_right.vertical_center(); - - token_list.push_back(math_token_t( - point_t(current_x, shift_delimiter_right), - bounding_box_delimiter_right, style, - delimiter_height)); - } - - return token_list; - } - - std::vector - math_text_renderer_t:: - math_tokenize(const math_text_t::atom_t &atom, - const unsigned int style) - { - const float size = style_size(style); - std::vector token_list; - bounding_box_t nucleus_bounding_box; - float current_x = 0; - float nucleus_shift_up = 0; - - // Rule 11 - if(atom._type == math_text_t::atom_t::TYPE_RAD) { - float style_radical_rule_thickness = - default_rule_thickness * size; - const float min_clearance = - style_radical_rule_thickness + 0.25F * - if_else_display(style, x_height(style), - style_radical_rule_thickness); - const bounding_box_t bounding_box_radicand = - math_bounding_box(atom._nucleus, - prime_style(style)); - const float min_delimiter_height = - bounding_box_radicand.height() + min_clearance + - style_radical_rule_thickness; - const math_text_t::math_symbol_t - symbol_surd("\\surd", style); - const bounding_box_t bounding_box_surd = - math_bounding_box(symbol_surd, style, - min_delimiter_height); - const float surd_intrinsic_shift_down = - bounding_box_surd.ascent() - - style_radical_rule_thickness; - const float modified_descent = - bounding_box_surd.descent() + - surd_intrinsic_shift_down; - const float clearance = modified_descent > - bounding_box_radicand.height() + min_clearance ? - 0.5F * (min_clearance + modified_descent - - bounding_box_radicand.height()) : - min_clearance; - - if(!atom._index.empty()) { - // The positive space of 5 mu to the index is hard - // wired in plain.tex - current_x += (5.0F / 18.0F) * size; - - const bounding_box_t bounding_box_index = - math_bounding_box(atom._index, - math_text_t::item_t::STYLE_SCRIPT_SCRIPT); - const float radical_height = - (std::max(math_bounding_box( - atom._index, prime_style(style)).ascent(), - bounding_box_radicand.ascent() + - clearance + - 2.0F * style_radical_rule_thickness) - - std::max(math_bounding_box( - atom._index, prime_style(style)).descent(), - bounding_box_radicand.descent())); - - nucleus_bounding_box = - point_t(current_x, 0.6F * radical_height) + - math_bounding_box( - atom._index, - math_text_t::item_t::STYLE_SCRIPT_SCRIPT); - token_list.push_back(math_token_t( - point_t(current_x, 0.6F * radical_height), - bounding_box_index, - math_text_t::item_t::STYLE_SCRIPT_SCRIPT)); - // The negative space of 10 mu to the surd is hard - // wired in plain.tex - current_x += bounding_box_index.advance() - - (10.0F / 18.0F) * size; - } - - const float radicand_ascent_clearance = - bounding_box_radicand.ascent() + clearance; - - nucleus_bounding_box = nucleus_bounding_box.merge( - point_t(current_x, - radicand_ascent_clearance - - surd_intrinsic_shift_down) + - bounding_box_surd); - token_list.push_back(math_token_t( - point_t(current_x, - radicand_ascent_clearance - - surd_intrinsic_shift_down), - bounding_box_surd, style, min_delimiter_height)); - current_x += bounding_box_surd.advance(); - - const float constrained_thickness = -#if 0 - // Pixel height constraint - std::max(1.0F, style_radical_rule_thickness) -#else - style_radical_rule_thickness -#endif - ; - static const float surd_rule_correction_x = -1.5F; - static const float surd_rule_correction_y = -0.5F; - - const point_t origin_rule = - point_t(current_x, radicand_ascent_clearance); - const bounding_box_t bounding_box_rule = - bounding_box_t(surd_rule_correction_x * - constrained_thickness, - surd_rule_correction_y * - constrained_thickness, - bounding_box_radicand.advance(), - (surd_rule_correction_y + 1.0F) * - constrained_thickness, - 0, 0); - - nucleus_bounding_box = nucleus_bounding_box.merge( - origin_rule + bounding_box_rule); - token_list.push_back(math_token_t( - origin_rule, bounding_box_rule, style)); - - const bounding_box_t bounding_box_clearance = - bounding_box_t(0, -2.0F * constrained_thickness, - bounding_box_radicand.advance(), - constrained_thickness, - 0, 0); - - nucleus_bounding_box = nucleus_bounding_box.merge( - origin_rule + bounding_box_clearance); - token_list.push_back(math_token_t( - origin_rule, bounding_box_clearance, style)); - - const point_t origin_radicand = point_t(current_x, 0); - - nucleus_bounding_box = nucleus_bounding_box.merge( - origin_radicand + bounding_box_radicand); - token_list.push_back(math_token_t( - origin_radicand, bounding_box_radicand, - prime_style(style))); - current_x += bounding_box_radicand.advance(); - } - else if(atom._type == math_text_t::atom_t::TYPE_OP) { - const bool limits = - atom._limits == math_text_t::atom_t::LIMITS_LIMITS || - (atom._limits == - math_text_t::atom_t::LIMITS_DISPLAYLIMITS && - is_display_style(style)); - - if(atom._nucleus._type == - math_text_t::field_t::TYPE_MATH_SYMBOL) { - // Rule 13 - nucleus_bounding_box = math_bounding_box( - atom._nucleus._math_symbol._glyph, - FAMILY_STIX_REGULAR, - size * if_else_display(style, - large_operator_display_scale, 1.0F)); - nucleus_shift_up = - axis_height * size - - nucleus_bounding_box.vertical_center(); - if(limits && atom._subscript.empty()) - nucleus_bounding_box.advance() += - nucleus_bounding_box.italic_correction(); - } - else - nucleus_bounding_box = - math_bounding_box(atom._nucleus, style); - - if(limits && !(atom._superscript.empty() && - atom._subscript.empty())) { - // Rule 13a - const unsigned int superscript_style = - next_superscript_style(style); - const unsigned int subscript_style = - next_subscript_style(style); - - if(atom._superscript.empty()) { - const bounding_box_t subscript_bounding_box = - math_bounding_box(atom._subscript, - subscript_style); - const float shift_right = - nucleus_bounding_box.horizontal_center() - - subscript_bounding_box.horizontal_center() - - 0.5F * - nucleus_bounding_box.italic_correction(); - const float clearance = - std::max(big_op_spacing_2 * size, - big_op_spacing_4 * size - - subscript_bounding_box.ascent()); - const float shift_down = - nucleus_bounding_box.descent() + clearance + - subscript_bounding_box.ascent() - - nucleus_shift_up; - - if(shift_right >= 0) { - token_list.push_back(math_token_t( - point_t(0, nucleus_shift_up), - nucleus_bounding_box, style)); - token_list.push_back(math_token_t( - point_t(shift_right, -shift_down), - subscript_bounding_box, - subscript_style)); - } - else { - token_list.push_back(math_token_t( - point_t(-shift_right, - nucleus_shift_up), - nucleus_bounding_box, style)); - token_list.push_back(math_token_t( - point_t(0, -shift_down), - subscript_bounding_box, - subscript_style)); - } - return token_list; - } - if(atom._subscript.empty()) { - const bounding_box_t superscript_bounding_box = - math_bounding_box(atom._superscript, - superscript_style); - const float shift_right = - nucleus_bounding_box.horizontal_center() - - superscript_bounding_box. - horizontal_center() + 0.5F * - nucleus_bounding_box.italic_correction(); - const float clearance = - std::max(big_op_spacing_1 * size, - big_op_spacing_3 * size - - superscript_bounding_box.descent()); - const float shift_up = - nucleus_bounding_box.ascent() + clearance + - superscript_bounding_box.descent() + - nucleus_shift_up; - - if(shift_right >= 0) { - token_list.push_back(math_token_t( - point_t(0, nucleus_shift_up), - nucleus_bounding_box, style)); - token_list.push_back(math_token_t( - point_t(shift_right, shift_up), - superscript_bounding_box, - superscript_style)); - } - else { - token_list.push_back(math_token_t( - point_t(-shift_right, - nucleus_shift_up), - nucleus_bounding_box, style)); - token_list.push_back(math_token_t( - point_t(0, shift_up), - superscript_bounding_box, - superscript_style)); - } - return token_list; - } - const bounding_box_t superscript_bounding_box = - math_bounding_box(atom._superscript, - superscript_style); - const bounding_box_t subscript_bounding_box = - math_bounding_box(atom._subscript, - subscript_style); - const float shift_right_superscript = - nucleus_bounding_box.horizontal_center() - - superscript_bounding_box.horizontal_center() + - 0.5F * nucleus_bounding_box.italic_correction(); - const float shift_right_subscript = - nucleus_bounding_box.horizontal_center() - - subscript_bounding_box.horizontal_center() - - 0.5F * nucleus_bounding_box.italic_correction(); - const float clearance_superscript = - std::max(big_op_spacing_1 * size, - big_op_spacing_3 * size - - superscript_bounding_box.descent()); - const float clearance_subscript = - std::max(big_op_spacing_2 * size, - big_op_spacing_4 * size - - subscript_bounding_box.ascent()); - const float shift_up = - nucleus_bounding_box.ascent() + - clearance_superscript + - superscript_bounding_box.descent() + - nucleus_shift_up; - const float shift_down = - nucleus_bounding_box.descent() + - clearance_subscript + - subscript_bounding_box.ascent() - - nucleus_shift_up; - const float min_shift_right = - std::min(0.0F, std::min(shift_right_superscript, - shift_right_subscript)); - - token_list.push_back(math_token_t( - point_t(-min_shift_right, - nucleus_shift_up), - nucleus_bounding_box, style)); - token_list.push_back(math_token_t( - point_t(shift_right_superscript - - min_shift_right, - shift_up), - superscript_bounding_box, - superscript_style)); - token_list.push_back(math_token_t( - point_t(shift_right_subscript - - min_shift_right, - -shift_down), - subscript_bounding_box, - subscript_style)); - return token_list; - } - - // \nolimits or nucleus only - token_list.push_back(math_token_t( - point_t(0, nucleus_shift_up), - nucleus_bounding_box, style)); - current_x += nucleus_bounding_box.advance(); - } - else { // Neither Rad nor Op - nucleus_bounding_box = - math_bounding_box(atom._nucleus, style); - token_list.push_back(math_token_t( - nucleus_bounding_box, style)); - current_x += nucleus_bounding_box.advance(); - } - - if(atom._superscript.empty() && atom._subscript.empty()) - return token_list; - - const float current_x_italic_corrected = current_x + - nucleus_bounding_box.italic_correction(); - const float nucleus_size = size; - const unsigned int superscript_style = - next_superscript_style(style); - const unsigned int subscript_style = - next_subscript_style(style); - const float superscript_size = style_size(superscript_style); - const float subscript_size = style_size(subscript_style); - // Rule 18a - const float min_shift_up = nucleus_bounding_box.ascent() - - superscript_size * sup_drop; - const float min_shift_down = nucleus_bounding_box.descent() + - subscript_size * sub_drop; - - // Rule 18b - if(atom._superscript.empty()) { - const bounding_box_t subscript_bounding_box = - math_bounding_box(atom._subscript, subscript_style); - const float shift_down = - std::max(std::max(min_shift_down, - nucleus_size * sub_1), - subscript_bounding_box.ascent() - - 0.8F * x_height(subscript_style)); - token_list.push_back(math_token_t( - point_t(current_x, nucleus_shift_up - shift_down), - subscript_bounding_box, subscript_style)); - return token_list; - } - // Rule 18c - const bounding_box_t superscript_bounding_box = - math_bounding_box(atom._superscript, superscript_style); - const float min_shift_up_2 = nucleus_size * - (style == math_text_t::item_t::STYLE_DISPLAY ? - sup_1 : is_prime_style(style) ? sup_3 : sup_2); - float shift_up = - std::max(std::max(min_shift_up, min_shift_up_2), - superscript_bounding_box.descent() + - 0.2F * x_height(superscript_style)); - // Rule 18d - if(atom._subscript.empty()) { - token_list.push_back(math_token_t( - point_t(current_x_italic_corrected, - nucleus_shift_up + shift_up), - superscript_bounding_box, superscript_style)); - return token_list; - } - - // Still rule 18d - float shift_down = - std::max(min_shift_down, nucleus_size * sub_2); - // Rule 18e - const bounding_box_t subscript_bounding_box = - math_bounding_box(atom._subscript, subscript_style); - - if((shift_up - superscript_bounding_box.descent()) - - (subscript_bounding_box.ascent() - shift_down) < - 4.0F * default_rule_thickness * - nucleus_size) { - shift_down = 4.0F * default_rule_thickness * - nucleus_size + subscript_bounding_box.ascent() + - superscript_bounding_box.descent() - shift_up; - - const float superscript_adjustment = - 0.8F * x_height(superscript_style) - - (shift_up - superscript_bounding_box.descent()); - - if(superscript_adjustment > 0) { - shift_up += superscript_adjustment; - shift_down -= superscript_adjustment; - } - } - // Rule 18f - token_list.push_back(math_token_t( - point_t(current_x_italic_corrected, - nucleus_shift_up + shift_up), - superscript_bounding_box, superscript_style)); - token_list.push_back(math_token_t( - point_t(current_x, - nucleus_shift_up - shift_down), - subscript_bounding_box, subscript_style)); - - return token_list; - } - -} diff --git a/graf2d/mathtext/src/mathtext.cxx b/graf2d/mathtext/src/mathtext.cxx deleted file mode 100644 index e0039a8aac832..0000000000000 --- a/graf2d/mathtext/src/mathtext.cxx +++ /dev/null @@ -1,348 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#include "../inc/mathtext.h" -#include - -///////////////////////////////////////////////////////////////////// - -namespace mathtext { - - ///////////////////////////////////////////////////////////////// - - void math_text_t::field_t::transform_script(void) - { - const unsigned long size = _math_list.size(); - - if(size < 2) - return; - - std::vector::reverse_iterator last = - _math_list.rbegin(); - std::vector::reverse_iterator second_last = - last + 1; - - if(last->_type == item_t::TYPE_ATOM && - second_last->_type == item_t::TYPE_ATOM && - second_last->_atom._type == atom_t::TYPE_ACC && - !(last->_atom._superscript.empty() && - last->_atom._subscript.empty())) { - // Rule 12 - atom_t atom = field_t(); - - atom._nucleus._math_list.push_back(*second_last); - atom._nucleus._math_list.push_back(*last); - atom._superscript = - atom._nucleus._math_list.back()._atom._superscript; - atom._subscript = - atom._nucleus._math_list.back()._atom._subscript; - atom._nucleus._math_list.back()._atom._superscript = - field_t(); - atom._nucleus._math_list.back()._atom._subscript = - field_t(); - _math_list.pop_back(); - _math_list.pop_back(); - _math_list.push_back(item_t(atom)); - } - } - - void math_text_t::field_t::append(const item_t &item) - { - _math_list.push_back(item); - } - - // FIXME: Check for malformed "..._a^b_c" (instead of just - // overwriting) - void math_text_t::field_t:: - append(const field_t &field, const bool superscript, - const bool subscript) - { - if((superscript || subscript) && _math_list.empty()) - _math_list.push_back(item_t(field_t())); - - if(superscript) { - _math_list.back()._atom._superscript = field; - transform_script(); - } - else if(subscript) { - _math_list.back()._atom._subscript = field; - transform_script(); - } - else - append(item_t(item_t::TYPE_ATOM, atom_t(field))); - } - - void math_text_t::field_t:: - prepend(const unsigned int type, - const math_symbol_t &math_symbol) - { - _math_list.insert(_math_list.begin(), - item_t(type, - atom_t(field_t(math_symbol)))); - } - - void math_text_t::field_t:: - append(const unsigned int type, const math_symbol_t &math_symbol, - const bool superscript, const bool subscript) - { - if((superscript || subscript) && _math_list.empty()) - _math_list.push_back(item_t(field_t())); - - if(superscript) { - _math_list.back()._atom._superscript = - field_t(math_symbol); - transform_script(); - } - else if(subscript) { - _math_list.back()._atom._subscript = - field_t(math_symbol); - transform_script(); - } - else - append(item_t(type, atom_t(field_t(math_symbol)))); - } - - math_text_t::field_t:: - field_t(const std::vector &str_split, - const unsigned int default_family) - : _type(TYPE_MATH_LIST) - { - parse_math_list(str_split, default_family); - } - - math_text_t::field_t:: - field_t(const std::string &str_delimiter_left, - const std::vector &str_split, - const std::string &str_delimiter_right, - const unsigned int default_family) - : _type(TYPE_MATH_LIST) - { - parse_math_list(str_split, default_family); - - const math_symbol_t - symbol_left(str_delimiter_left, default_family); - - prepend(item_t::TYPE_BOUNDARY, symbol_left); - - const math_symbol_t - symbol_right(str_delimiter_right, default_family); - - append(item_t::TYPE_BOUNDARY, symbol_right, false, false); - } - - bool math_text_t::field_t::generalized_fraction(void) const - { - if(_type == TYPE_MATH_LIST) - for (std::vector::const_iterator iterator = _math_list.begin(); iterator != _math_list.end(); - ++iterator) - if(iterator->_type == - item_t::TYPE_GENERALIZED_FRACTION) - return true; - return false; - } - - void math_text_t::atom_t::classify(void) - { - // Only nucleus affects the atom type (Knuth, The TeXbook, - // 1986, p. 171) - if(_nucleus._type == field_t::TYPE_MATH_SYMBOL) - _type = _nucleus._math_symbol._type; - else if(_nucleus.generalized_fraction()) - _type = atom_t::TYPE_INNER; - else - // FIXME: Does TeX flatten compound expressions before - // classify them? - _type = TYPE_ORD; - } - - bool math_text_t::atom_t::is_combining_diacritical(void) const - { - return _nucleus._type == field_t::TYPE_MATH_SYMBOL && - _nucleus._math_symbol.is_combining_diacritical(); - } - - unsigned int math_text_t::atom_t:: - spacing(const unsigned int left_type, - const unsigned int right_type, const bool script) - { -#include "table/mathspacing.h" - // Since we only handle atom types upto Inner, the upper bound - // is type <= TYPE_INNER and not type < NTYPE. - if(left_type == TYPE_UNKNOWN || left_type > TYPE_INNER || - right_type == TYPE_UNKNOWN || right_type > TYPE_INNER) { - // Invalid - return 0; - } - - int index = ((left_type - TYPE_ORD) << 3) + - (right_type - TYPE_ORD); - int space = spacing_table[index]; - - if(space == nvr) { - // Invalid - return 0; - } - // Interpret the \nonscript sign, which denotes spaces that - // should be ignored within the script (and scriptscript) - // style. - if(space < 0) - space = script ? 0 : -space; - - return space; - } - - bool math_text_t::item_t::operator==(const item_t &item) const - { - switch(_type) { - case TYPE_GENERALIZED_FRACTION: - return item._type == TYPE_GENERALIZED_FRACTION; - break; - default: - return false; - } - } - - std::wstring math_text_t::bad_cast(const std::string string) - { - std::wstring wstring; - - for (std::string::const_iterator iterator = string.begin(); iterator != string.end(); ++iterator) { - wstring.push_back(*iterator); - } - - return wstring; - } - - std::wstring math_text_t::utf8_cast(const std::string string) - { - std::wstring wstring; - - for(std::string::const_iterator iterator = string.begin(); - iterator != string.end();) { - wchar_t c; - - // Skip over byte ordering marks - if((unsigned char)(*iterator) == 0xef) { - ++iterator; - if((unsigned char)(*iterator) == 0xbb) { - ++iterator; - if((unsigned char)(*iterator) == 0xbf) { - ++iterator; - } - } - } - if((*iterator & 0xf0) == 0xf0) { - c = (*iterator & 0x7) << 18; - ++iterator; - if((*iterator & 0xc0) != 0x80) { - continue; - } - c |= (*iterator & 0x3f) << 12; - ++iterator; - if((*iterator & 0xc0) != 0x80) { - continue; - } - c |= (*iterator & 0x3f) << 6; - ++iterator; - if((*iterator & 0xc0) != 0x80) { - continue; - } - c |= (*iterator & 0x3f); - ++iterator; - } - else if((*iterator & 0xe0) == 0xe0) { - c = (*iterator & 0xf) << 12; - ++iterator; - if((*iterator & 0xc0) != 0x80) { - continue; - } - c |= (*iterator & 0x3f) << 6; - ++iterator; - if((*iterator & 0xc0) != 0x80) { - continue; - } - c |= (*iterator & 0x3f); - ++iterator; - } - else if((*iterator & 0xc0) == 0xc0) { - c = (*iterator & 0x1f) << 6; - ++iterator; - if((*iterator & 0xc0) != 0x80) { - continue; - } - c |= (*iterator & 0x3f); - ++iterator; - } - else if((*iterator & 0x80) == 0x0) { - c = (*iterator & 0x7f); - ++iterator; - } - else { - ++iterator; - continue; - } - wstring.push_back(c); - } - - return wstring; - } - -#if 0 - std::wstring math_text_t::gb_18030_cast( - const std::string string) - { - } - - std::wstring math_text_t::shift_jis_x_0213_cast( - const std::string string) - { - } - - std::wstring math_text_t::euc_jis_x_0213_cast( - const std::string string) - { - } - - std::wstring math_text_t::ks_x_2901_cast( - const std::string string) - { - } -#endif - - // Apply JIS X 4051:2004 - - bool math_text_t::well_formed(void) const - { - if(_math_list._type != field_t::TYPE_MATH_LIST) - return false; - return true; - } - -#if 0 - std::string tex_form(const double x) - { - std::string retval; - - switch(std::fpclassify(x)) { - default: - return retval; - } - } -#endif - -} diff --git a/graf2d/mathtext/src/mathtextencode.cxx b/graf2d/mathtext/src/mathtextencode.cxx deleted file mode 100644 index ed38dd2344e81..0000000000000 --- a/graf2d/mathtext/src/mathtextencode.cxx +++ /dev/null @@ -1,437 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#ifdef WIN32 -// On Windows, Disable the warning: -// "characters beyond first in wide-character constant ignored" -#pragma warning( push ) -#pragma warning( disable : 4066) -#endif - -#include -#include -#include -#include "../inc/mathtext.h" - -///////////////////////////////////////////////////////////////////// - -namespace mathtext { - - ///////////////////////////////////////////////////////////////// - - // For the symbol classification, see Knuth, The TeXbook (1986), - // pp. 434ff. - - void math_text_t::math_symbol_t::math_italic_is_upright(void) - { - if(_family == FAMILY_MATH_ITALIC) { - _family = FAMILY_REGULAR; - } - else if(_family == FAMILY_MATH_BOLD_ITALIC) { - _family = FAMILY_BOLD; - } - } - - void math_text_t::math_symbol_t::math_italic_is_italic(void) - { - if(_family == FAMILY_MATH_ITALIC) { - _family = FAMILY_ITALIC; - } - else if(_family == FAMILY_MATH_BOLD_ITALIC) { - _family = FAMILY_BOLD_ITALIC; - } - } - - void math_text_t::math_symbol_t::encode_character(void) - { - if(_code.size() != 1) - return; - - // Character encoding for plain characters (not a TeX control - // sequence) - switch(_code[0]) { - case '|': - case '/': - case '.': - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_ORD; - break; - case '+': - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_BIN; - break; - case '-': - math_italic_is_upright(); - _glyph = L'\u2212'; - _type = atom_t::TYPE_BIN; - break; - case '*': - math_italic_is_upright(); - _glyph = L'\u2217'; - _type = atom_t::TYPE_BIN; - break; - case '<': - case '=': - case '>': - case ':': - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_REL; - break; - case '(': - case '[': - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_OPEN; - break; - case '!': - case '?': - case ')': - case ']': - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_CLOSE; - break; - case ',': - case ';': - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_PUNCT; - break; - default: - if((_code[0] >= 'A' && _code[0] <= 'Z') || - (_code[0] >= 'a' && _code[0] <= 'z')) { - _glyph = _code[0]; - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= '0' && _code[0] <= '9') { - math_italic_is_upright(); - _glyph = _code[0]; - _type = atom_t::TYPE_ORD; - } - } - } - - void math_text_t::math_symbol_t::encode_control_sequence(void) - { - // Character encoding for TeX control sequences -#include "table/mathglyphstd.h" - const char **lower = - std::lower_bound(glyph_control_sequence, - glyph_control_sequence + nglyph, - _code); - - if(lower < glyph_control_sequence + nglyph && -#ifdef WIN32 - strncmp(*lower, _code.c_str(), _code.size()) == 0 -#else // WIN32 - *lower == _code -#endif // WIN32 - ) { - const unsigned long index = - lower - glyph_control_sequence; - - if(glyph_upright[index]) - math_italic_is_upright(); - _glyph = glyph_code_point[index]; - _type = glyph_type[index]; - } - } - - void math_text_t::math_symbol_t::encode_math_blackboard_bold(void) - { - if(_code.size() != 1) { - return; - } - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_REGULAR; - switch(_code[0]) { - case 'C': _glyph = L'\u2102'; break; - case 'H': _glyph = L'\u210d'; break; - case 'N': _glyph = L'\u2115'; break; - case 'P': _glyph = L'\u2119'; break; - case 'Q': _glyph = L'\u211a'; break; - case 'R': _glyph = L'\u211d'; break; - case 'Z': _glyph = L'\u2124'; break; - default: _glyph = L'\U0001d538' + (_code[0] - 'A'); - } - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_REGULAR; - _glyph = L'\U0001d552' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= '0' && _code[0] <= '9') { - _family = FAMILY_STIX_REGULAR; - _glyph = L'\U0001d7d8' + (_code[0] - '0'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t::encode_math_script_italic(void) - { - if(_code.size() != 1) { - return; - } - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_ITALIC; - switch(_code[0]) { - case 'H': _glyph = L'\u210b'; break; - case 'I': _glyph = L'\u2110'; break; - case 'L': _glyph = L'\u2112'; break; - case 'P': _glyph = L'\u2118'; break; - case 'R': _glyph = L'\u211b'; break; - case 'B': _glyph = L'\u212c'; break; - case 'E': _glyph = L'\u2130'; break; - case 'F': _glyph = L'\u2131'; break; - case 'M': _glyph = L'\u2133'; break; - default: _glyph = L'\U0001d49c' + (_code[0] - 'A'); - } - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_ITALIC; - switch(_code[0]) { - case 'g': _glyph = L'\u210a'; break; - case 'l': _glyph = L'\u2113'; break; - case 'e': _glyph = L'\u212f'; break; - case 'o': _glyph = L'\u2134'; break; - default: _glyph = L'\U0001d4b6' + (_code[0] - 'a'); - } - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t::encode_math_script_bold_italic(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_BOLD_ITALIC; - _glyph = L'\U0001d49c' + (_code[0] - 'A'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_BOLD_ITALIC; - _glyph = L'\U0001d4b6' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t::encode_math_fraktur_regular(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_REGULAR; - switch(_code[0]) { - case 'H': _glyph = L'\u210c'; break; - case 'I': _glyph = L'\u2111'; break; - case 'R': _glyph = L'\u211c'; break; - case 'Z': _glyph = L'\u2128'; break; - case 'C': _glyph = L'\u212d'; break; - default: _glyph = L'\U0001d504' + (_code[0] - 'A'); - } - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_REGULAR; - _glyph = L'\U0001d51e' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t::encode_math_fraktur_bold(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_BOLD; - _glyph = L'\U0001d56c' + (_code[0] - 'A'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_BOLD; - _glyph = L'\U0001d586' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t:: - encode_math_sans_serif_regular(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_REGULAR; - _glyph = L'\U0001d5a0' + (_code[0] - 'A'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_REGULAR; - _glyph = L'\U0001d5ba' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= '0' && _code[0] <= '9') { - _family = FAMILY_STIX_REGULAR; - _glyph = L'\U0001d7e2' + (_code[0] - '0'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t:: - encode_math_sans_serif_italic(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_ITALIC; - _glyph = L'\U0001d608' + (_code[0] - 'A'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_ITALIC; - _glyph = L'\U0001d622' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t:: - encode_math_sans_serif_bold(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_BOLD; - _glyph = L'\U0001d5d4' + (_code[0] - 'A'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_BOLD; - _glyph = L'\U0001d5ee' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= '0' && _code[0] <= '9') { - _family = FAMILY_STIX_BOLD; - _glyph = L'\U0001d7ec' + (_code[0] - '0'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t:: - encode_math_sans_serif_bold_italic(void) - { - if(_code.size() != 1) - return; - - if(_code[0] >= 'A' && _code[0] <= 'Z') { - _family = FAMILY_STIX_BOLD_ITALIC; - _glyph = L'\U0001d63c' + (_code[0] - 'A'); - _type = atom_t::TYPE_ORD; - } - else if(_code[0] >= 'a' && _code[0] <= 'z') { - _family = FAMILY_STIX_BOLD_ITALIC; - _glyph = L'\U0001d656' + (_code[0] - 'a'); - _type = atom_t::TYPE_ORD; - } - } - - void math_text_t::math_symbol_t::encode_math_alpha(void) - { - switch(_family) { - case FAMILY_MATH_BLACKBOARD_BOLD: - encode_math_blackboard_bold(); - break; - case FAMILY_MATH_SCRIPT_ITALIC: - encode_math_script_italic(); - break; - case FAMILY_MATH_SCRIPT_BOLD_ITALIC: - encode_math_script_bold_italic(); - break; - case FAMILY_MATH_FRAKTUR_REGULAR: - encode_math_fraktur_regular(); - break; - case FAMILY_MATH_FRAKTUR_BOLD: - encode_math_fraktur_bold(); - break; - case FAMILY_MATH_SANS_SERIF_REGULAR: - encode_math_sans_serif_regular(); - break; - case FAMILY_MATH_SANS_SERIF_ITALIC: - encode_math_sans_serif_italic(); - break; - case FAMILY_MATH_SANS_SERIF_BOLD: - encode_math_sans_serif_bold(); - break; - case FAMILY_MATH_SANS_SERIF_BOLD_ITALIC: - encode_math_sans_serif_bold_italic(); - break; - } - } - - void math_text_t::math_symbol_t::encode(void) - { - encode_character(); - encode_control_sequence(); - encode_math_alpha(); - math_italic_is_italic(); - if(_family > FAMILY_STIX_SIZE_5_REGULAR) { - std::cerr << __FILE__ << ':' << __LINE__ - << ": error: encoding results in a " - "nonphysical font family" << std::endl; - } - } - - bool math_text_t::math_symbol_t::bold(void) const - { - switch(_family) { - case FAMILY_BOLD: - case FAMILY_BOLD_ITALIC: - case FAMILY_STIX_BOLD: - case FAMILY_STIX_BOLD_ITALIC: - case FAMILY_STIX_SIZE_1_BOLD: - case FAMILY_STIX_SIZE_2_BOLD: - case FAMILY_STIX_SIZE_3_BOLD: - case FAMILY_STIX_SIZE_4_BOLD: - case FAMILY_MATH_BOLD_ITALIC: - case FAMILY_MATH_SCRIPT_BOLD_ITALIC: - case FAMILY_MATH_FRAKTUR_BOLD: - case FAMILY_MATH_BLACKBOARD_BOLD: - case FAMILY_MATH_SANS_SERIF_BOLD: - case FAMILY_MATH_SANS_SERIF_BOLD_ITALIC: - return true; - default: - return false; - } - } - -} -#ifdef WIN32 -#pragma warning( pop ) -#endif diff --git a/graf2d/mathtext/src/mathtextparse.cxx b/graf2d/mathtext/src/mathtextparse.cxx deleted file mode 100644 index 8ead42e68a44f..0000000000000 --- a/graf2d/mathtext/src/mathtextparse.cxx +++ /dev/null @@ -1,456 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#include -#include -#include -#include -#include "../inc/mathtext.h" - -///////////////////////////////////////////////////////////////////// - -namespace mathtext { - - ///////////////////////////////////////////////////////////////// - - void math_text_t::field_t:: - parse_math_list(const std::vector &str_split, - const unsigned int default_family) - { -#if 0 - std::cerr << "parsing ["; - for(std::vector::const_iterator iterator = - str_split.begin(); - iterator != str_split.end(); iterator++) - std::cerr << '"' << *iterator << "\", "; - std::cerr << ']' << std::endl; -#endif - - // State of radical parsing - enum { - RADICAL_STATE_NONE = 0, - RADICAL_STATE_RADICAND, - RADICAL_STATE_OF, - RADICAL_STATE_INDEX - }; - - unsigned int family = default_family; - int level = 0; - int delimiter_level = 0; - std::vector buffer; -#if 1 - bool superscript = false; - bool subscript = false; - bool delimiter_right = false; - unsigned int radical_state = RADICAL_STATE_NONE; - std::vector radical_index; - bool horizontal_box = false; - - for (std::vector::const_iterator iterator = str_split.begin(); iterator != str_split.end(); - ++iterator) { - // ONLY LEVEL 0 superscript and subscript are interpreted, - // and they are ignored afterwards. - if(level == 0 && delimiter_level == 0) { - if((*iterator)[0] == '^') { - superscript = true; - continue; - } - else if((*iterator)[0] == '_') { - subscript = true; - continue; - } - else if(*iterator == "\\sqrt") { - radical_state = RADICAL_STATE_RADICAND; - radical_index = std::vector(); - continue; - } - else if(iterator->substr(0, 5) == "\\root") { - radical_state = RADICAL_STATE_INDEX; - continue; - } - else if(radical_state == RADICAL_STATE_INDEX && - *iterator == "\\of") { - radical_index = buffer; - buffer.clear(); - radical_state = RADICAL_STATE_RADICAND; - continue; - } - else if(iterator->substr(0, 5) == "\\hbox" || - iterator->substr(0, 5) == "\\text") { - horizontal_box = true; - continue; - } - - const char **lower; - -#include "table/mathfontch.h" - lower = std::lower_bound( - font_change_control_sequence, - font_change_control_sequence + nfont_change, - *iterator); - - if(lower < - font_change_control_sequence + nfont_change && - *lower == *iterator) { - const unsigned long index = - lower - font_change_control_sequence; - - family = font_change_family[index]; - continue; - } -#include "table/mathopstd.h" - lower = std::lower_bound( - operator_control_sequence, - operator_control_sequence + noperator, - *iterator); - if(lower < - operator_control_sequence + noperator && - *lower == *iterator) { - const unsigned long index = - lower - operator_control_sequence; - - if(operator_code_point[index] == L'\0') { - // Operator defined with \mathop - const field_t operator_math_list(field_t( - tex_split(operator_content[index]), - math_symbol_t::FAMILY_REGULAR)); - atom_t atom(atom_t::TYPE_OP, field_t( - operator_math_list)); - - atom._limits = operator_nolimits[index] ? - atom_t::LIMITS_NOLIMITS : - atom_t::LIMITS_DISPLAYLIMITS; - append(atom); - } - else { - // Operator defined with \mathchardef - const field_t operator_math_symbol( - math_symbol_t( - *iterator, - operator_code_point[index], - math_symbol_t::FAMILY_REGULAR)); - atom_t atom(atom_t::TYPE_OP, field_t( - operator_math_symbol)); - - atom._limits = operator_nolimits[index] ? - atom_t::LIMITS_NOLIMITS : - atom_t::LIMITS_DISPLAYLIMITS; - append(atom); - } - continue; - } - } - - if((*iterator)[0] == '}') { - level--; - // When the level decreases to 0 here, the compound - // expression is complete, create a subfield and - // append it to the math list. - if(level == 0 && delimiter_level == 0) { - // Create subfields recursively - const field_t subfield(buffer, family); - - if(radical_state == RADICAL_STATE_RADICAND) { - atom_t atom(atom_t::TYPE_RAD, subfield); - - atom._index = field_t(radical_index, family); - append(item_t(atom)); - radical_state = RADICAL_STATE_NONE; - } - else - append(subfield, superscript, subscript); - buffer.clear(); - } - } - else if(*iterator == "\\right") { - delimiter_level--; - // When the delimtier level decreases to 0 here, the - // compound expression is complete, create a subfield - // and append it with the appropriate delimiter atoms - // to the math list. - if(level == 0 && delimiter_level == 0) { - delimiter_right = true; - continue; - } - } - - ///////////////////////////////////////////////////////// - -#if 0 - std::cerr << __FILE__ << ':' << __LINE__ - << ": L" << level << ", DL" - << delimiter_level << ", hbox = " - << horizontal_box << ", *iterator = " - << *iterator << std::endl; -#endif - - if(level > 0 || delimiter_level > 0 || - radical_state == RADICAL_STATE_INDEX) { - buffer.push_back(*iterator); - } - else if(delimiter_right) { - const std::string left = buffer.front(); - - buffer.erase(buffer.begin()); - - const field_t subfield(left, buffer, *iterator, - family); - - if(radical_state == RADICAL_STATE_RADICAND) { - atom_t atom(atom_t::TYPE_RAD, subfield); - - atom._index = field_t(radical_index, family); - append(item_t(atom)); - radical_state = RADICAL_STATE_NONE; - } - else - append(subfield, superscript, subscript); - buffer.clear(); - } - else if(horizontal_box) { - box_t box(math_text_t::utf8_cast(*iterator)); - - append(field_t(box), superscript, subscript); - } - else if((*iterator)[0] != '{' && - (*iterator)[0] != '}' && - *iterator != "\\left" && - *iterator != "\\right") { - if(radical_state == RADICAL_STATE_RADICAND) { - const field_t subfield( - std::vector(1, *iterator), - family); - atom_t atom(atom_t::TYPE_RAD, subfield); - - atom._index = field_t(radical_index, family); - append(item_t(atom)); - } - // FIXME: This should be a true table - else if(*iterator == "\\over") { - append(item_t(item_t::TYPE_GENERALIZED_FRACTION, - 1.0F)); - } - else if(*iterator == "\\atop") { - append(item_t(item_t::TYPE_GENERALIZED_FRACTION, - 0.0F)); - } - // FIXME: This should be a true table - else if(*iterator == "\\!") { - append(item_t(item_t::TYPE_KERN, -3.0F)); - } - else if(*iterator == "\\,") { - append(item_t(item_t::TYPE_KERN, 3.0F)); - } - else if(*iterator == "\\:") { - append(item_t(item_t::TYPE_KERN, 4.0F)); - } - else if(*iterator == "\\;") { - append(item_t(item_t::TYPE_KERN, 5.0F)); - } - else if(*iterator == "\\quad") { - append(item_t(item_t::TYPE_KERN, 18.0F)); - } - else if(*iterator == "\\qquad") { - append(item_t(item_t::TYPE_KERN, 36.0F)); - } - else { - const math_symbol_t - math_symbol(*iterator, family); - - append(item_t::TYPE_ATOM, math_symbol, - superscript, subscript); - } - } - - if((*iterator)[0] == '{') { - level++; - } - else if(*iterator == "\\left") { - // Since the actual delimiter follows, it is going to - // be appended to the buffer "automatically". - delimiter_level++; - } - // Reset superscript and subscript flags only for level 0 - if(level == 0 && delimiter_level == 0 && - (radical_state == RADICAL_STATE_RADICAND || - radical_state == RADICAL_STATE_NONE)) { - superscript = false; - subscript = false; - delimiter_right = false; - radical_state = RADICAL_STATE_NONE; - family = default_family; - horizontal_box = false; - } - } -#else - for(std::vector::const_iterator iterator = - str_split.begin(); - iterator != str_split.end(); iterator++) { - if((*iterator)[0] == '}') { - level--; - - } - else if(*iterator == "\\right") { - delimiter_level--; - } - if((*iterator)[0] == '{') { - level++; - } - else if(*iterator == "\\left") { - // Since the actual delimiter follows, it is going to - // be appended to the buffer "automatically". - delimiter_level++; - } - else if(level == 0 && delimiter_level == 0) { -#if 1 - std::cerr << __FILE__ << ':' << __LINE__ - << ": L" << level << ", DL" - << delimiter_level << ", *iterator = " - << *iterator << ", buffer = { "; - for(std::vector::const_iterator - buffer_iterator = buffer.begin(); - buffer_iterator != buffer.end(); buffer_iterator++) { - std::cerr << '"' << *buffer_iterator << "\" "; - } - std::cerr << '}' << std::endl; -#endif - buffer.clear(); - } - else { - buffer.push_back(*iterator); - } - } -#endif - } - - std::vector math_text_t:: - tex_split(const std::string &raw_code, const char escape_character) - { - std::string code = raw_code; - - for (std::string::iterator iterator = code.begin(); iterator != code.end(); ++iterator) { - if(*iterator == escape_character) { - *iterator = '\\'; - } - } - - std::vector ret; - - if(code.empty()) { - return ret; - } - - size_t begin = 0; - size_t end = 1; - bool box = false; - - while (code[begin] == ' ') { - begin++; - } - while (begin < code.size()) { - end = begin + 1; - if(code[begin] == '\\') { - if(isalpha(code[end])) { - while(end < code.size() && isalpha(code[end])) { - end++; - } - } - else if(end < code.size()) { - end++; - } - -#include "table/mathbracketcs.h" - const char **lower = - std::lower_bound(bracket_control_sequence, - bracket_control_sequence + - nbracket_control_sequence, - code.substr(begin, - end - begin)); - - if(lower < bracket_control_sequence + - nbracket_control_sequence && - *lower == code.substr(begin, end - begin) && - end + 1 < code.size() && code[end] == '[') { - while(end < code.size() && code[end] != ']') { - end++; - } - if(end < code.size()) { - end++; - } - } - } - - std::string code_substr = - code.substr(begin, end - begin); - -#if 1 - if(code_substr == "\\hbox" || code_substr == "\\text") { - box = true; - } - else if(box) { - if(code[begin] == '{') { - for(unsigned int level = 1; - end < code.size() && level > 0; end++) { - if(code[end - 1] != '\\') { - switch(code[end]) { - case '{': level++; break; - case '}': level--; break; - } - } - } - code_substr = - code.substr(begin + 1, end - begin - 2); - } - else if(code[begin] == '\\' && - begin + 1 < code.size()) { - code_substr = code.substr(begin, 2); - } - else { - code_substr = code.substr(begin, 1); - } - // FIXME: Proper interpretation of escaped characters - box = false; - } -#endif - - ret.push_back(code_substr); - begin = end; - while( begin math_text_t:: - tex_replace(const std::vector &/*code*/) - { -#if 0 - static const size_t ncontrol_max = 256; - static const char *table[][ncontrol_max] = { - { "\\%", "\0", "\\root", "\1", "\\of", "\2", NULL }, - { "\\sqrt", "[]", "\1", "\\root", "\1", "\\of", "\2", NULL }, - { "\\frac", "\2", "{", "\1", "\\over", "\2", "}", NULL } - }; -#endif - - return std::vector(); - } - -} diff --git a/graf2d/mathtext/src/mathtextview.cxx b/graf2d/mathtext/src/mathtextview.cxx deleted file mode 100644 index 65fb0abb827dc..0000000000000 --- a/graf2d/mathtext/src/mathtextview.cxx +++ /dev/null @@ -1,231 +0,0 @@ -// mathtext - A TeX/LaTeX compatible rendering library. Copyright (C) -// 2008-2012 Yue Shi Lai -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public License -// as published by the Free Software Foundation; either version 2.1 of -// the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -// 02110-1301 USA - -#include -#include -#include "../inc/mathtext.h" - -///////////////////////////////////////////////////////////////////// - -namespace mathtext { - - ///////////////////////////////////////////////////////////////// - - void math_text_t:: - tree_view_prefix(const std::vector &branch, - const bool final) const - { - if(!branch.empty()) { - std::cerr << ' '; - for (std::vector::const_iterator iterator = branch.begin(); iterator != branch.end(); ++iterator) { - if(*iterator) { - if(iterator + 1 == branch.end()) { - if(final) - std::cerr << "\342\224\224\342\224\200 "; - else - std::cerr << "\342\224\234\342\224\200 "; - } - else - std::cerr << "\342\224\202 "; - } - else - if(iterator + 1 == branch.end()) - std::cerr << " "; - else - std::cerr << " "; - } - } - } - - void math_text_t::tree_view(const field_t &field, - std::vector &branch, - const bool final) const - { - switch(field._type) { - case field_t::TYPE_MATH_SYMBOL: - tree_view_prefix(branch, true); - std::cerr << "" << std::endl; - break; - case field_t::TYPE_BOX: - tree_view_prefix(branch, true); - std::cerr << "" << std::endl; - break; - case field_t::TYPE_MATH_LIST: - if(field._math_list.empty()) { - tree_view_prefix(branch, true); - std::cerr << "" << std::endl; - } - else { - tree_view_prefix(branch, false); - std::cerr << "" << std::endl; - - std::vector branch_copy = branch; - - branch_copy.back() = !final; - for (std::vector::const_iterator iterator = field._math_list.begin(); - iterator != field._math_list.end(); ++iterator) { - branch_copy.back() = !final; - branch_copy.push_back(true); - tree_view(*iterator, branch_copy, - iterator + 1 == field._math_list.end()); - branch_copy.pop_back(); - } - branch_copy.back() = !final; - tree_view_prefix(branch_copy, true); - std::cerr << "" << std::endl; - } - break; - default: - tree_view_prefix(branch, true); - std::cerr << "" << std::endl; - } - } - - void math_text_t::tree_view(const item_t &item, - std::vector &branch, - const bool final) const - { - std::vector branch_copy = branch; - - switch(item._type) { - case item_t::TYPE_ATOM: - tree_view_prefix(branch, final); - std::cerr << "" << std::endl; - branch_copy.back() = !final; - branch_copy.push_back(true); - tree_view(item._atom, branch_copy, final); - branch_copy.pop_back(); - tree_view_prefix(branch_copy, final); - std::cerr << "" << std::endl; - break; - case item_t::TYPE_BOUNDARY: - tree_view_prefix(branch, final); - std::cerr << "" << std::endl; - branch_copy.back() = !final; - branch_copy.push_back(true); - tree_view(item._atom, branch_copy, final); - branch_copy.pop_back(); - tree_view_prefix(branch_copy, final); - std::cerr << "" << std::endl; - break; - case item_t::TYPE_GENERALIZED_FRACTION: - tree_view_prefix(branch, final); - std::cerr << "" << std::endl; - break; - default: - tree_view_prefix(branch, final); - std::cerr << "" << std::endl; - } - } - - void math_text_t::tree_view(const atom_t &atom, - std::vector &branch, - const bool final) const - { - tree_view_prefix(branch, false); - std::cerr << ""; - switch(atom._type) { - case atom_t::TYPE_ORD: - std::cerr << "Ord"; - break; - case atom_t::TYPE_OP: - std::cerr << "Op"; - break; - case atom_t::TYPE_BIN: - std::cerr << "Bin"; - break; - case atom_t::TYPE_REL: - std::cerr << "Rel"; - break; - case atom_t::TYPE_OPEN: - std::cerr << "Open"; - break; - case atom_t::TYPE_CLOSE: - std::cerr << "Close"; - break; - case atom_t::TYPE_PUNCT: - std::cerr << "Punct"; - break; - case atom_t::TYPE_INNER: - std::cerr << "Inner"; - break; - case atom_t::TYPE_OVER: - std::cerr << "Over"; - break; - case atom_t::TYPE_UNDER: - std::cerr << "Under"; - break; - case atom_t::TYPE_ACC: - std::cerr << "Acc"; - break; - case atom_t::TYPE_RAD: - std::cerr << "Rad"; - break; - case atom_t::TYPE_VCENT: - std::cerr << "Vcent"; - break; - default: - std::cerr << "??" << atom._type; - break; - } - std::cerr << "" << std::endl; - - std::vector branch_copy = branch; - - if(!atom._nucleus.empty()) { - const bool way_final = atom._superscript.empty() && - atom._subscript.empty(); - - tree_view_prefix(branch, way_final); - std::cerr << "" << std::endl; - branch_copy.back() = !way_final; - branch_copy.push_back(true); - tree_view(atom._nucleus, branch_copy, final); - branch_copy.pop_back(); - tree_view_prefix(branch_copy, way_final); - std::cerr << "" << std::endl; - } - if(!atom._superscript.empty()) { - const bool way_final = atom._subscript.empty(); - - tree_view_prefix(branch, way_final); - std::cerr << "" << std::endl; - branch_copy.back() = !way_final; - branch_copy.push_back(true); - tree_view(atom._superscript, branch_copy, final); - branch_copy.pop_back(); - tree_view_prefix(branch_copy, way_final); - std::cerr << "" << std::endl; - } - if(!atom._subscript.empty()) { - tree_view_prefix(branch, true); - std::cerr << "" << std::endl; - branch_copy.back() = false; - branch_copy.push_back(true); - tree_view(atom._subscript, branch_copy, final); - branch_copy.pop_back(); - tree_view_prefix(branch_copy, true); - std::cerr << "" << std::endl; - } - } - -} diff --git a/graf2d/postscript/src/TPostScript.cxx b/graf2d/postscript/src/TPostScript.cxx index 6b406a4fff1a2..a6580c4eb6f63 100644 --- a/graf2d/postscript/src/TPostScript.cxx +++ b/graf2d/postscript/src/TPostScript.cxx @@ -250,7 +250,7 @@ To change the color model use `gStyle->SetColorModelPS(c)`. #include "TSystem.h" #include "TEnv.h" -#include "../../../graf2d/mathtext/inc/fontembed.h" +#include "mathtext/fontembed.h" // to scale fonts to the same size as the old TT version const Float_t kScale = 0.93376068;