From 5be8ee5c0ed921ac0eac2591098e02c3be9bc57c Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 11 Nov 2010 04:48:08 +0000 Subject: [PATCH] Update libass to d8a0fe5984d9bc6d7827026215d21ada3dda7b71 and update LICENSE to reflect that libass is now ISCL Originally committed to SVN as r4839. --- aegisub/LICENCE | 2 +- aegisub/libass/COPYING | 348 +--------- aegisub/libass/Makefile.am | 1 + aegisub/libass/ass.c | 104 ++- aegisub/libass/ass.h | 47 +- aegisub/libass/ass_bitmap.c | 49 +- aegisub/libass/ass_bitmap.h | 23 +- aegisub/libass/ass_cache.c | 29 +- aegisub/libass/ass_cache.h | 22 +- aegisub/libass/ass_drawing.c | 59 +- aegisub/libass/ass_drawing.h | 7 +- aegisub/libass/ass_font.c | 230 +++++-- aegisub/libass/ass_font.h | 24 +- aegisub/libass/ass_fontconfig.c | 126 +++- aegisub/libass/ass_fontconfig.h | 22 +- aegisub/libass/ass_library.c | 29 +- aegisub/libass/ass_library.h | 22 +- aegisub/libass/ass_parse.c | 65 +- aegisub/libass/ass_render.c | 1047 +++++++++++++------------------ aegisub/libass/ass_render.h | 26 +- aegisub/libass/ass_render_api.c | 139 ++++ aegisub/libass/ass_strtod.c | 4 +- aegisub/libass/ass_types.h | 22 +- aegisub/libass/ass_utils.c | 23 +- aegisub/libass/ass_utils.h | 22 +- 25 files changed, 1188 insertions(+), 1304 deletions(-) create mode 100644 aegisub/libass/ass_render_api.c diff --git a/aegisub/LICENCE b/aegisub/LICENCE index 83d7c2391..db85fd642 100644 --- a/aegisub/LICENCE +++ b/aegisub/LICENCE @@ -34,7 +34,7 @@ The following directories and file are covered by their respective licenses as follows: libass/ - - GPL see libass/COPYING. + - ISC license. See libass/COPYING. libffms/ - MIT license. diff --git a/aegisub/libass/COPYING b/aegisub/libass/COPYING index d511905c1..8351a30e3 100644 --- a/aegisub/libass/COPYING +++ b/aegisub/libass/COPYING @@ -1,339 +1,11 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. - Copyright (C) 1989, 1991 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. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, 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 or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -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 give any other recipients of the Program a copy of this License -along with the Program. - -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 Program or any portion -of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -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 Program, 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 Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) 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; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, 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 executable. However, as a -special exception, the source code 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. - -If distribution of executable or 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 counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program 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. - - 5. 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 Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program 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 to -this License. - - 7. 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 Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program 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 Program. - -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. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program 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. - - 9. The Free Software Foundation may publish revised and/or new versions -of the 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 Program -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 Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, 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 - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), 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 Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. 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 program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program 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 General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; 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. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/aegisub/libass/Makefile.am b/aegisub/libass/Makefile.am index 8a990787e..a5705da1f 100644 --- a/aegisub/libass/Makefile.am +++ b/aegisub/libass/Makefile.am @@ -16,6 +16,7 @@ libass_aegisub_a_SOURCES = \ ass_library.c \ ass_parse.c \ ass_render.c \ + ass_render_api.c \ ass_strtod.c \ ass_utils.c diff --git a/aegisub/libass/ass.c b/aegisub/libass/ass.c index 6becb39e8..368377251 100644 --- a/aegisub/libass/ass.c +++ b/aegisub/libass/ass.c @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" @@ -23,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +37,8 @@ #include "ass_utils.h" #include "ass_library.h" +#define ass_atof(STR) (ass_strtod((STR),NULL)) + typedef enum { PST_UNKNOWN = 0, PST_INFO, @@ -62,26 +63,22 @@ void ass_free_track(ASS_Track *track) int i; if (track->parser_priv) { - if (track->parser_priv->fontname) - free(track->parser_priv->fontname); - if (track->parser_priv->fontdata) - free(track->parser_priv->fontdata); + free(track->parser_priv->fontname); + free(track->parser_priv->fontdata); free(track->parser_priv); } - if (track->style_format) - free(track->style_format); - if (track->event_format) - free(track->event_format); + free(track->style_format); + free(track->event_format); if (track->styles) { for (i = 0; i < track->n_styles; ++i) ass_free_style(track, i); - free(track->styles); } + free(track->styles); if (track->events) { for (i = 0; i < track->n_events; ++i) ass_free_event(track, i); - free(track->events); } + free(track->events); free(track->name); free(track); } @@ -133,23 +130,19 @@ int ass_alloc_event(ASS_Track *track) void ass_free_event(ASS_Track *track, int eid) { ASS_Event *event = track->events + eid; - if (event->Name) - free(event->Name); - if (event->Effect) - free(event->Effect); - if (event->Text) - free(event->Text); - if (event->render_priv) - free(event->render_priv); + + free(event->Name); + free(event->Effect); + free(event->Text); + free(event->render_priv); } void ass_free_style(ASS_Track *track, int sid) { ASS_Style *style = track->styles + sid; - if (style->Name) - free(style->Name); - if (style->FontName) - free(style->FontName); + + free(style->Name); + free(style->FontName); } // ============================================================================================== @@ -250,7 +243,7 @@ static int numpad2align(int val) ass_msg(track->library, MSGL_DBG2, "%s = %s", #name, token); #define INTVAL(name) ANYVAL(name,atoi) -#define FPVAL(name) ANYVAL(name,atof) +#define FPVAL(name) ANYVAL(name,ass_atof) #define TIMEVAL(name) \ } else if (strcasecmp(tname, #name) == 0) { \ target->name = string2timecode(track->library, token); \ @@ -384,7 +377,7 @@ void ass_process_force_style(ASS_Track *track) else if (!strcasecmp(*fs, "PlayResY")) track->PlayResY = atoi(token); else if (!strcasecmp(*fs, "Timer")) - track->Timer = atof(token); + track->Timer = ass_atof(token); else if (!strcasecmp(*fs, "WrapStyle")) track->WrapStyle = atoi(token); else if (!strcasecmp(*fs, "ScaledBorderAndShadow")) @@ -534,12 +527,6 @@ static int process_style(ASS_Track *track, char *str) style->Name = strdup("Default"); if (!style->FontName) style->FontName = strdup("Arial"); - // skip '@' at the start of the font name - if (*style->FontName == '@') { - p = style->FontName; - style->FontName = strdup(p + 1); - free(p); - } free(format); return 0; @@ -568,7 +555,7 @@ static int process_info_line(ASS_Track *track, char *str) } else if (!strncmp(str, "PlayResY:", 9)) { track->PlayResY = atoi(str + 9); } else if (!strncmp(str, "Timer:", 6)) { - track->Timer = atof(str + 6); + track->Timer = ass_atof(str + 6); } else if (!strncmp(str, "WrapStyle:", 10)) { track->WrapStyle = atoi(str + 10); } else if (!strncmp(str, "ScaledBorderAndShadow:", 22)) { @@ -597,6 +584,7 @@ static int process_events_line(ASS_Track *track, char *str) if (!strncmp(str, "Format:", 7)) { char *p = str + 7; skip_spaces(&p); + free(track->event_format); track->event_format = strdup(p); ass_msg(track->library, MSGL_DBG2, "Event format: %s", track->event_format); } else if (!strncmp(str, "Dialogue:", 9)) { @@ -618,7 +606,7 @@ static int process_events_line(ASS_Track *track, char *str) process_event_tail(track, event, str, 0); } else { - ass_msg(track->library, MSGL_V, "Not understood: '%s'", str); + ass_msg(track->library, MSGL_V, "Not understood: '%.30s'", str); } return 0; } @@ -677,12 +665,10 @@ static int decode_font(ASS_Track *track) if (track->library->extract_fonts) { ass_add_font(track->library, track->parser_priv->fontname, (char *) buf, dsize); - buf = 0; } - error_decode_font: - if (buf) - free(buf); +error_decode_font: + free(buf); free(track->parser_priv->fontname); free(track->parser_priv->fontdata); track->parser_priv->fontname = 0; @@ -909,6 +895,20 @@ void ass_process_chunk(ASS_Track *track, char *data, int size, free(str); } +/** + * \brief Flush buffered events. + * \param track track +*/ +void ass_flush_events(ASS_Track *track) +{ + if (track->events) { + int eid; + for (eid = 0; eid < track->n_events; eid++) + ass_free_event(track, eid); + track->n_events = 0; + } +} + #ifdef CONFIG_ICONV /** \brief recode buffer to utf-8 * constraint: codepage != 0 @@ -1019,14 +1019,6 @@ static char *read_file(ASS_Library *library, char *fname, size_t *bufsize) sz = ftell(fp); rewind(fp); - if (sz > 10 * 1024 * 1024) { - ass_msg(library, MSGL_INFO, - "ass_read_file(%s): Refusing to load subtitles " - "larger than 10MiB", fname); - fclose(fp); - return 0; - } - ass_msg(library, MSGL_V, "File size: %ld", sz); buf = malloc(sz + 1); diff --git a/aegisub/libass/ass.h b/aegisub/libass/ass.h index e7674a736..3762bffe4 100644 --- a/aegisub/libass/ass.h +++ b/aegisub/libass/ass.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_ASS_H @@ -25,7 +23,7 @@ #include #include "ass_types.h" -#define LIBASS_VERSION 0x00908000 +#define LIBASS_VERSION 0x00911000 /* * A linked list of images produced by an ass renderer. @@ -75,11 +73,13 @@ ASS_Library *ass_library_init(void); void ass_library_done(ASS_Library *priv); /** - * \brief Set private font directory. - * It is used for saving embedded fonts and also in font lookup. + * \brief Set additional fonts directory. + * Optional directory that will be scanned for fonts recursively. The fonts + * found are used for font lookup. + * NOTE: A valid font directory is not needed to support embedded fonts. * * \param priv library handle - * \param fonts_dir private directory for font extraction + * \param fonts_dir directory with additional fonts */ void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir); @@ -203,6 +203,8 @@ void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing); * if fontconfig is used. * \param update whether fontconfig cache should be built/updated now. Only * relevant if fontconfig is used. + * + * NOTE: font lookup must be configured before an ASS_Renderer can be used. */ void ass_set_fonts(ASS_Renderer *priv, const char *default_font, const char *default_family, int fc, const char *config, @@ -297,7 +299,8 @@ void ass_free_event(ASS_Track *track, int eid); void ass_process_data(ASS_Track *track, char *data, int size); /** - * \brief Parse Codec Private section of subtitle stream. + * \brief Parse Codec Private section of the subtitle stream, in Matroska + * format. See the Matroska specification for details. * \param track target track * \param data string to parse * \param size length of data @@ -305,8 +308,8 @@ void ass_process_data(ASS_Track *track, char *data, int size); void ass_process_codec_private(ASS_Track *track, char *data, int size); /** - * \brief Parse a chunk of subtitle stream data. In Matroska, - * this contains exactly 1 event (or a commentary). + * \brief Parse a chunk of subtitle stream data. A chunk contains exactly one + * event in Matroska format. See the Matroska specification for details. * \param track track * \param data string to parse * \param size length of data @@ -316,6 +319,12 @@ void ass_process_codec_private(ASS_Track *track, char *data, int size); void ass_process_chunk(ASS_Track *track, char *data, int size, long long timecode, long long duration); +/** + * \brief Flush buffered events. + * \param track track +*/ +void ass_flush_events(ASS_Track *track); + /** * \brief Read subtitles from file. * \param library library handle diff --git a/aegisub/libass/ass_bitmap.c b/aegisub/libass/ass_bitmap.c index c7c039ddd..6ecdbc667 100644 --- a/aegisub/libass/ass_bitmap.c +++ b/aegisub/libass/ass_bitmap.c @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include @@ -113,8 +111,7 @@ static void resize_tmp(ASS_SynthPriv *priv, int w, int h) priv->tmp_w *= 2; while (priv->tmp_h < h) priv->tmp_h *= 2; - if (priv->tmp) - free(priv->tmp); + free(priv->tmp); priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short)); } @@ -127,20 +124,17 @@ ASS_SynthPriv *ass_synth_init(double radius) void ass_synth_done(ASS_SynthPriv *priv) { - if (priv->tmp) - free(priv->tmp); - if (priv->g) - free(priv->g); - if (priv->gt2) - free(priv->gt2); + free(priv->tmp); + free(priv->g); + free(priv->gt2); free(priv); } static Bitmap *alloc_bitmap(int w, int h) { Bitmap *bm; - bm = calloc(1, sizeof(Bitmap)); - bm->buffer = malloc(w * h); + bm = malloc(sizeof(Bitmap)); + bm->buffer = calloc(w, h); bm->w = w; bm->h = h; bm->left = bm->top = 0; @@ -149,11 +143,9 @@ static Bitmap *alloc_bitmap(int w, int h) void ass_free_bitmap(Bitmap *bm) { - if (bm) { - if (bm->buffer) - free(bm->buffer); - free(bm); - } + if (bm) + free(bm->buffer); + free(bm); } static Bitmap *copy_bitmap(const Bitmap *src) @@ -165,7 +157,7 @@ static Bitmap *copy_bitmap(const Bitmap *src) return dst; } -static int check_glyph_area(ASS_Library *library, FT_Glyph glyph) +int check_glyph_area(ASS_Library *library, FT_Glyph glyph) { FT_BBox bbox; long long dx, dy; @@ -213,7 +205,6 @@ static Bitmap *glyph_to_bitmap_internal(ASS_Library *library, w = bit->width; h = bit->rows; bm = alloc_bitmap(w + 2 * bord, h + 2 * bord); - memset(bm->buffer, 0, bm->w * bm->h); bm->left = bg->left - bord; bm->top = -bg->top - bord; diff --git a/aegisub/libass/ass_bitmap.h b/aegisub/libass/ass_bitmap.h index 338db0119..287b63828 100644 --- a/aegisub/libass/ass_bitmap.h +++ b/aegisub/libass/ass_bitmap.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_BITMAP_H @@ -53,5 +51,6 @@ int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur, int border_style); void ass_free_bitmap(Bitmap *bm); +int check_glyph_area(ASS_Library *library, FT_Glyph glyph); #endif /* LIBASS_BITMAP_H */ diff --git a/aegisub/libass/ass_cache.c b/aegisub/libass/ass_cache.c index 643d9912e..46c2478f8 100644 --- a/aegisub/libass/ass_cache.c +++ b/aegisub/libass/ass_cache.c @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" @@ -156,6 +154,8 @@ static int font_compare(void *key1, void *key2, size_t key_size) return 0; if (a->treat_family_as_pattern != b->treat_family_as_pattern) return 0; + if (a->vertical != b->vertical) + return 0; return 1; } @@ -286,6 +286,11 @@ static void glyph_hash_dtor(void *key, size_t key_size, void *value, void *cache_add_glyph(Hashmap *glyph_cache, GlyphHashKey *key, GlyphHashValue *val) { + if (val->glyph && val->glyph->format == FT_GLYPH_FORMAT_BITMAP) { + FT_Bitmap *bitmap = &((FT_BitmapGlyph) val->glyph)->bitmap; + glyph_cache->cache_size += bitmap->rows * bitmap->pitch; + } + return hashmap_insert(glyph_cache, key, val); } diff --git a/aegisub/libass/ass_cache.h b/aegisub/libass/ass_cache.h index 5c9749f87..472bf359b 100644 --- a/aegisub/libass/ass_cache.h +++ b/aegisub/libass/ass_cache.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_CACHE_H diff --git a/aegisub/libass/ass_drawing.c b/aegisub/libass/ass_drawing.c index a3207c7c3..93cc458d1 100644 --- a/aegisub/libass/ass_drawing.c +++ b/aegisub/libass/ass_drawing.c @@ -34,13 +34,13 @@ * \brief Get and prepare a FreeType glyph */ static void drawing_make_glyph(ASS_Drawing *drawing, void *fontconfig_priv, - ASS_Font *font, ASS_Hinting hint) + ASS_Font *font) { FT_OutlineGlyph glyph; // This is hacky... glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font, - (uint32_t) ' ', hint, 0); + (uint32_t) ' ', 0, 0); if (glyph) { FT_Outline_Done(drawing->ftlibrary, &glyph->outline); FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS, @@ -112,24 +112,12 @@ static void drawing_prepare(ASS_Drawing *drawing) static void drawing_finish(ASS_Drawing *drawing, int raw_mode) { int i, offset; - FT_BBox bbox; + FT_BBox bbox = drawing->cbox; FT_Outline *ol = &drawing->glyph->outline; // Close the last contour drawing_close_shape(drawing); -#if 0 - // Dump points - for (i = 0; i < ol->n_points; i++) { - printf("point (%d, %d)\n", (int) ol->points[i].x, - (int) ol->points[i].y); - } - - // Dump contours - for (i = 0; i < ol->n_contours; i++) - printf("contour %d\n", ol->contours[i]); -#endif - ass_msg(drawing->library, MSGL_V, "Parsed drawing with %d points and %d contours", ol->n_points, ol->n_contours); @@ -137,7 +125,6 @@ static void drawing_finish(ASS_Drawing *drawing, int raw_mode) if (raw_mode) return; - FT_Outline_Get_CBox(&drawing->glyph->outline, &bbox); drawing->glyph->root.advance.x = d6_to_d16(bbox.xMax - bbox.xMin); drawing->desc = double_to_d6(-drawing->pbo * drawing->scale_y); @@ -231,15 +218,6 @@ static ASS_DrawingToken *drawing_tokenize(char *str) p++; } -#if 0 - // Check tokens - ASS_DrawingToken *t = root; - while(t) { - printf("token %d point (%d, %d)\n", t->type, t->point.x, t->point.y); - t = t->next; - } -#endif - return root; } @@ -255,6 +233,19 @@ static void drawing_free_tokens(ASS_DrawingToken *token) } } +/* + * \brief Update drawing cbox + */ +static inline void update_cbox(ASS_Drawing *drawing, FT_Vector *point) +{ + FT_BBox *box = &drawing->cbox; + + box->xMin = FFMIN(box->xMin, point->x); + box->xMax = FFMAX(box->xMax, point->x); + box->yMin = FFMIN(box->yMin, point->y); + box->yMax = FFMAX(box->yMax, point->y); +} + /* * \brief Translate and scale a point coordinate according to baseline * offset and scale. @@ -263,6 +254,8 @@ static inline void translate_point(ASS_Drawing *drawing, FT_Vector *point) { point->x = drawing->point_scale_x * point->x; point->y = drawing->point_scale_y * -point->y; + + update_cbox(drawing, point); } /* @@ -362,19 +355,19 @@ static void drawing_evaluate_curve(ASS_Drawing *drawing, * \brief Create and initialize a new drawing and return it */ ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font, - ASS_Hinting hint, FT_Library lib) + FT_Library lib) { ASS_Drawing *drawing; drawing = calloc(1, sizeof(*drawing)); drawing->text = calloc(1, DRAWING_INITIAL_SIZE); drawing->size = DRAWING_INITIAL_SIZE; - + drawing->cbox.xMin = drawing->cbox.yMin = INT_MAX; + drawing->cbox.xMax = drawing->cbox.yMax = INT_MIN; + drawing->fontconfig_priv = fontconfig_priv; + drawing->font = font; drawing->ftlibrary = lib; - if (font) { - drawing->library = font->library; - drawing_make_glyph(drawing, fontconfig_priv, font, hint); - } + drawing->library = font->library; drawing->scale_x = 1.; drawing->scale_y = 1.; @@ -390,8 +383,6 @@ ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font, void ass_drawing_free(ASS_Drawing* drawing) { if (drawing) { - if (drawing->glyph) - FT_Done_Glyph((FT_Glyph) drawing->glyph); free(drawing->text); } free(drawing); @@ -429,6 +420,8 @@ FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode) ASS_DrawingToken *token; FT_Vector pen = {0, 0}; + if (drawing->font) + drawing_make_glyph(drawing, drawing->fontconfig_priv, drawing->font); if (!drawing->glyph) return NULL; diff --git a/aegisub/libass/ass_drawing.h b/aegisub/libass/ass_drawing.h index 913588e74..f677fcddd 100644 --- a/aegisub/libass/ass_drawing.h +++ b/aegisub/libass/ass_drawing.h @@ -57,7 +57,9 @@ typedef struct { int hash; // hash value (for caching) // private - FT_Library ftlibrary; // FT library instance, needed for font ops + FT_Library ftlibrary; // needed for font ops + ASS_Font *font; // dito + void *fontconfig_priv; // dito ASS_Library *library; int size; // current buffer size ASS_DrawingToken *tokens; // tokenized drawing @@ -65,10 +67,11 @@ typedef struct { int max_contours; double point_scale_x; double point_scale_y; + FT_BBox cbox; // bounding box, or let's say... VSFilter's idea of it } ASS_Drawing; ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font, - ASS_Hinting hint, FT_Library lib); + FT_Library lib); void ass_drawing_free(ASS_Drawing* drawing); void ass_drawing_add_char(ASS_Drawing* drawing, char symbol); void ass_drawing_hash(ASS_Drawing* drawing); diff --git a/aegisub/libass/ass_font.c b/aegisub/libass/ass_font.c index 7db1f076f..74467df6b 100644 --- a/aegisub/libass/ass_font.c +++ b/aegisub/libass/ass_font.c @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" @@ -27,6 +25,7 @@ #include FT_GLYPH_H #include FT_TRUETYPE_TABLES_H #include FT_OUTLINE_H +#include #include "ass.h" #include "ass_library.h" @@ -36,13 +35,18 @@ #include "ass_fontconfig.h" #include "ass_utils.h" +#define VERTICAL_LOWER_BOUND 0x02f1 + /** - * Select Microfost Unicode CharMap, if the font has one. + * Select a good charmap, prefer Microsoft Unicode charmaps. * Otherwise, let FreeType decide. */ static void charmap_magic(ASS_Library *library, FT_Face face) { int i; + int ms_cmap = -1; + + // Search for a Microsoft Unicode cmap for (i = 0; i < face->num_charmaps; ++i) { FT_CharMap cmap = face->charmaps[i]; unsigned pid = cmap->platform_id; @@ -52,7 +56,15 @@ static void charmap_magic(ASS_Library *library, FT_Face face) || eid == 10 /*full unicode */ )) { FT_Set_Charmap(face, cmap); return; - } + } else if (pid == 3 && ms_cmap < 0) + ms_cmap = i; + } + + // Try the first Microsoft cmap if no Microsoft Unicode cmap was found + if (ms_cmap >= 0) { + FT_CharMap cmap = face->charmaps[ms_cmap]; + FT_Set_Charmap(face, cmap); + return; } if (!face->charmap) { @@ -67,17 +79,6 @@ static void charmap_magic(ASS_Library *library, FT_Face face) } } -static void update_transform(ASS_Font *font) -{ - int i; - FT_Matrix m; - m.xx = double_to_d16(font->scale_x); - m.yy = double_to_d16(font->scale_y); - m.xy = m.yx = 0; - for (i = 0; i < font->n_faces; ++i) - FT_Set_Transform(font->faces[i], &m, &font->v); -} - /** * \brief find a memory font by name */ @@ -139,7 +140,7 @@ static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch) FT_New_Memory_Face(font->ftlibrary, (unsigned char *) font->library-> fontdata[mem_idx].data, - font->library->fontdata[mem_idx].size, 0, + font->library->fontdata[mem_idx].size, index, &face); if (error) { ass_msg(font->library, MSGL_WARN, @@ -160,7 +161,6 @@ static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch) buggy_font_workaround(face); font->faces[font->n_faces++] = face; - update_transform(font); face_set_size(face, font->size); free(path); return font->n_faces - 1; @@ -188,6 +188,7 @@ ASS_Font *ass_font_new(void *font_cache, ASS_Library *library, font.desc.treat_family_as_pattern = desc->treat_family_as_pattern; font.desc.bold = desc->bold; font.desc.italic = desc->italic; + font.desc.vertical = desc->vertical; font.scale_x = font.scale_y = 1.; font.v.x = font.v.y = 0; @@ -213,7 +214,6 @@ void ass_font_set_transform(ASS_Font *font, double scale_x, font->v.x = v->x; font->v.y = v->y; } - update_transform(font); } static void face_set_size(FT_Face face, double size) @@ -276,6 +276,9 @@ void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc, *asc = FT_MulFix(face->ascender, y_scale); *desc = FT_MulFix(-face->descender, y_scale); } + if (font->desc.vertical && ch >= VERTICAL_LOWER_BOUND) { + *asc = FT_MulFix(face->max_advance_width, y_scale); + } return; } } @@ -414,6 +417,7 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, FT_Glyph glyph; FT_Face face = 0; int flags = 0; + int vertical = font->desc.vertical; if (ch < 0x20) return 0; @@ -441,6 +445,14 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, if (face_idx >= 0) { face = font->faces[face_idx]; index = FT_Get_Char_Index(face, ch); + if (index == 0 && face->num_charmaps > 0) { + ass_msg(font->library, MSGL_WARN, + "Glyph 0x%X not found, falling back to first charmap", ch); + FT_CharMap cur = face->charmap; + FT_Set_Charmap(face, face->charmaps[0]); + index = FT_Get_Char_Index(face, ch); + FT_Set_Charmap(face, cur); + } if (index == 0) { ass_msg(font->library, MSGL_ERR, "Glyph 0x%X not found in font for (%s, %d, %d)", @@ -451,22 +463,23 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, } #endif + flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH + | FT_LOAD_IGNORE_TRANSFORM; switch (hinting) { case ASS_HINTING_NONE: - flags = FT_LOAD_NO_HINTING; + flags |= FT_LOAD_NO_HINTING; break; case ASS_HINTING_LIGHT: - flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; + flags |= FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; break; case ASS_HINTING_NORMAL: - flags = FT_LOAD_FORCE_AUTOHINT; + flags |= FT_LOAD_FORCE_AUTOHINT; break; case ASS_HINTING_NATIVE: - flags = 0; break; } - error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags); + error = FT_Load_Glyph(face, index, flags); if (error) { ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d", index); @@ -488,6 +501,24 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, return 0; } + // Rotate glyph, if needed + if (vertical && ch >= VERTICAL_LOWER_BOUND) { + FT_Matrix m = { 0, double_to_d16(-1.0), double_to_d16(1.0), 0 }; + FT_Outline_Transform(&((FT_OutlineGlyph) glyph)->outline, &m); + FT_Outline_Translate(&((FT_OutlineGlyph) glyph)->outline, + face->glyph->metrics.vertAdvance, + 0); + glyph->advance.x = face->glyph->linearVertAdvance; + } + + // Apply scaling and shift + FT_Matrix scale = { double_to_d16(font->scale_x), 0, 0, + double_to_d16(font->scale_y) }; + FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline; + FT_Outline_Transform(outl, &scale); + FT_Outline_Translate(outl, font->v.x, font->v.y); + glyph->advance.x *= font->scale_x; + ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE, deco & DECO_STRIKETHROUGH); @@ -502,6 +533,9 @@ FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2) FT_Vector v = { 0, 0 }; int i; + if (font->desc.vertical) + return v; + for (i = 0; i < font->n_faces; ++i) { FT_Face face = font->faces[i]; int i1 = FT_Get_Char_Index(face, c1); @@ -526,7 +560,133 @@ void ass_font_free(ASS_Font *font) for (i = 0; i < font->n_faces; ++i) if (font->faces[i]) FT_Done_Face(font->faces[i]); - if (font->desc.family) - free(font->desc.family); + free(font->desc.family); free(font); } + +/** + * \brief Calculate the cbox of a series of points + */ +static void +get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end) +{ + box->xMin = box->yMin = INT_MAX; + box->xMax = box->yMax = INT_MIN; + int i; + + for (i = start; i <= end; i++) { + box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin; + box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax; + box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin; + box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax; + } +} + +/** + * \brief Determine winding direction of a contour + * \return direction; 0 = clockwise + */ +static int get_contour_direction(FT_Vector *points, int start, int end) +{ + int i; + long long sum = 0; + int x = points[start].x; + int y = points[start].y; + for (i = start + 1; i <= end; i++) { + sum += x * (points[i].y - y) - y * (points[i].x - x); + x = points[i].x; + y = points[i].y; + } + sum += x * (points[start].y - y) - y * (points[start].x - x); + return sum > 0; +} + +/** + * \brief Fix-up stroker result for huge borders by removing inside contours + * that would reverse in size + */ +void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y) +{ + int nc = glyph->outline.n_contours; + int begin, stop; + char modified = 0; + char *valid_cont = malloc(nc); + int start = 0; + int end = -1; + FT_BBox *boxes = malloc(nc * sizeof(FT_BBox)); + int i, j; + int inside_direction; + + inside_direction = FT_Outline_Get_Orientation(&glyph->outline) == + FT_ORIENTATION_TRUETYPE; + + // create a list of cboxes of the contours + for (i = 0; i < nc; i++) { + start = end + 1; + end = glyph->outline.contours[i]; + get_contour_cbox(&boxes[i], glyph->outline.points, start, end); + } + + // for each contour, check direction and whether it's "outside" + // or contained in another contour + end = -1; + for (i = 0; i < nc; i++) { + start = end + 1; + end = glyph->outline.contours[i]; + int dir = get_contour_direction(glyph->outline.points, start, end); + valid_cont[i] = 1; + if (dir == inside_direction) { + for (j = 0; j < nc; j++) { + if (i == j) + continue; + if (boxes[i].xMin >= boxes[j].xMin && + boxes[i].xMax <= boxes[j].xMax && + boxes[i].yMin >= boxes[j].yMin && + boxes[i].yMax <= boxes[j].yMax) + goto check_inside; + } + /* "inside" contour but we can't find anything it could be + * inside of - assume the font is buggy and it should be + * an "outside" contour, and reverse it */ + for (j = 0; j < (end + 1 - start) / 2; j++) { + FT_Vector temp = glyph->outline.points[start + j]; + char temp2 = glyph->outline.tags[start + j]; + glyph->outline.points[start + j] = glyph->outline.points[end - j]; + glyph->outline.points[end - j] = temp; + glyph->outline.tags[start + j] = glyph->outline.tags[end - j]; + glyph->outline.tags[end - j] = temp2; + } + dir ^= 1; + } + check_inside: + if (dir == inside_direction) { + FT_BBox box; + get_contour_cbox(&box, glyph->outline.points, start, end); + int width = box.xMax - box.xMin; + int height = box.yMax - box.yMin; + if (width < border_x * 2 || height < border_y * 2) { + valid_cont[i] = 0; + modified = 1; + } + } + } + + // zero-out contours that can be removed; much simpler than copying + if (modified) { + for (i = 0; i < nc; i++) { + if (valid_cont[i]) + continue; + begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1; + stop = glyph->outline.contours[i]; + for (j = begin; j <= stop; j++) { + glyph->outline.points[j].x = 0; + glyph->outline.points[j].y = 0; + glyph->outline.tags[j] = 0; + } + } + } + + free(boxes); + free(valid_cont); +} + diff --git a/aegisub/libass/ass_font.h b/aegisub/libass/ass_font.h index ca0c213a0..ab4054813 100644 --- a/aegisub/libass/ass_font.h +++ b/aegisub/libass/ass_font.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_FONT_H @@ -36,6 +34,7 @@ typedef struct { unsigned bold; unsigned italic; int treat_family_as_pattern; + int vertical; // @font vertical layout } ASS_FontDesc; typedef struct { @@ -62,5 +61,6 @@ FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font, uint32_t ch, ASS_Hinting hinting, int flags); FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2); void ass_font_free(ASS_Font *font); +void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, int border_y); #endif /* LIBASS_FONT_H */ diff --git a/aegisub/libass/ass_fontconfig.c b/aegisub/libass/ass_fontconfig.c index 2a43694f3..2571739ff 100644 --- a/aegisub/libass/ass_fontconfig.c +++ b/aegisub/libass/ass_fontconfig.c @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" @@ -24,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +50,61 @@ struct fc_instance { #ifdef CONFIG_FONTCONFIG +/** + * \brief Case-insensitive match ASS/SSA font family against full name. (also + * known as "name for humans") + * + * \param lib library instance + * \param priv fontconfig instance + * \param family font fullname + * \param bold weight attribute + * \param italic italic attribute + * \return font set + */ +static FcFontSet * +match_fullname(ASS_Library *lib, FCInstance *priv, const char *family, + unsigned bold, unsigned italic) +{ + FcFontSet *sets[2]; + FcFontSet *result = FcFontSetCreate(); + int nsets = 0; + int i, fi; + + if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetSystem))) + nsets++; + if ((sets[nsets] = FcConfigGetFonts(priv->config, FcSetApplication))) + nsets++; + + // Run over font sets and patterns and try to match against full name + for (i = 0; i < nsets; i++) { + FcFontSet *set = sets[i]; + for (fi = 0; fi < set->nfont; fi++) { + FcPattern *pat = set->fonts[fi]; + char *fullname; + int pi = 0, at; + FcBool ol; + while (FcPatternGetString(pat, FC_FULLNAME, pi++, + (FcChar8 **) &fullname) == FcResultMatch) { + if (FcPatternGetBool(pat, FC_OUTLINE, 0, &ol) != FcResultMatch + || ol != FcTrue) + continue; + if (FcPatternGetInteger(pat, FC_SLANT, 0, &at) != FcResultMatch + || at < italic) + continue; + if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &at) != FcResultMatch + || at < bold) + continue; + if (strcasecmp(fullname, family) == 0) { + FcFontSetAdd(result, FcPatternDuplicate(pat)); + break; + } + } + } + } + + return result; +} + /** * \brief Low-level font selection. * \param priv private data @@ -62,7 +116,7 @@ struct fc_instance { * \param code: the character that should be present in the font, can be 0 * \return font file path */ -static char *_select_font(ASS_Library *library, FCInstance *priv, +static char *select_font(ASS_Library *library, FCInstance *priv, const char *family, int treat_family_as_pattern, unsigned bold, unsigned italic, int *index, uint32_t code) @@ -74,7 +128,7 @@ static char *_select_font(ASS_Library *library, FCInstance *priv, FcChar8 *r_family, *r_style, *r_file, *r_fullname; FcBool r_outline, r_embolden; FcCharSet *r_charset; - FcFontSet *fset = NULL; + FcFontSet *ffullname = NULL, *fsorted = NULL, *fset = NULL; int curf; char *retval = NULL; int family_cnt = 0; @@ -126,10 +180,23 @@ static char *_select_font(ASS_Library *library, FCInstance *priv, if (!rc) goto error; - fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result); - if (!fset) + fsorted = FcFontSort(priv->config, pat, FcTrue, NULL, &result); + ffullname = match_fullname(library, priv, family, bold, italic); + if (!fsorted || !ffullname) goto error; + fset = FcFontSetCreate(); + for (curf = 0; curf < ffullname->nfont; ++curf) { + FcPattern *curp = ffullname->fonts[curf]; + FcPatternReference(curp); + FcFontSetAdd(fset, curp); + } + for (curf = 0; curf < fsorted->nfont; ++curf) { + FcPattern *curp = fsorted->fonts[curf]; + FcPatternReference(curp); + FcFontSetAdd(fset, curp); + } + for (curf = 0; curf < fset->nfont; ++curf) { FcPattern *curp = fset->fonts[curf]; @@ -215,6 +282,10 @@ static char *_select_font(ASS_Library *library, FCInstance *priv, FcPatternDestroy(pat); if (rpat) FcPatternDestroy(rpat); + if (fsorted) + FcFontSetDestroy(fsorted); + if (ffullname) + FcFontSetDestroy(ffullname); if (fset) FcFontSetDestroy(fset); return retval; @@ -244,11 +315,11 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, } if (family && *family) res = - _select_font(library, priv, family, treat_family_as_pattern, + select_font(library, priv, family, treat_family_as_pattern, bold, italic, index, code); if (!res && priv->family_default) { res = - _select_font(library, priv, priv->family_default, 0, bold, + select_font(library, priv, priv->family_default, 0, bold, italic, index, code); if (res) ass_msg(library, MSGL_WARN, "fontconfig_select: Using default " @@ -263,7 +334,7 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, res, *index); } if (!res) { - res = _select_font(library, priv, "Arial", 0, bold, italic, + res = select_font(library, priv, "Arial", 0, bold, italic, index, code); if (res) ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' " @@ -283,8 +354,8 @@ char *fontconfig_select(ASS_Library *library, FCInstance *priv, * \param library library object * \param ftlibrary freetype library object * \param idx index of the processed font in library->fontdata - * With FontConfig >= 2.4.2, builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace. - * With older FontConfig versions, save the font to ~/.mplayer/fonts. + * + * Builds a font pattern in memory via FT_New_Memory_Face/FcFreeTypeQueryFace. */ static void process_fontdata(FCInstance *priv, ASS_Library *library, FT_Library ftlibrary, int idx) @@ -311,7 +382,7 @@ static void process_fontdata(FCInstance *priv, ASS_Library *library, num_faces = face->num_faces; pattern = - FcFreeTypeQueryFace(face, (unsigned char *) name, 0, + FcFreeTypeQueryFace(face, (unsigned char *) name, face_index, FcConfigGetBlanks(priv->config)); if (!pattern) { ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace"); @@ -388,7 +459,7 @@ FCInstance *fontconfig_init(ASS_Library *library, process_fontdata(priv, library, ftlibrary, i); if (dir) { - ass_msg(library, MSGL_INFO, "Updating font cache"); + ass_msg(library, MSGL_V, "Updating font cache"); rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir); if (!rc) { @@ -448,14 +519,13 @@ int fontconfig_update(FCInstance *priv) void fontconfig_done(FCInstance *priv) { + + if (priv) { #ifdef CONFIG_FONTCONFIG - if (priv && priv->config) FcConfigDestroy(priv->config); #endif - if (priv && priv->path_default) free(priv->path_default); - if (priv && priv->family_default) free(priv->family_default); - if (priv) - free(priv); + } + free(priv); } diff --git a/aegisub/libass/ass_fontconfig.h b/aegisub/libass/ass_fontconfig.h index ad5b9f0e4..396fb72d0 100644 --- a/aegisub/libass/ass_fontconfig.h +++ b/aegisub/libass/ass_fontconfig.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_FONTCONFIG_H diff --git a/aegisub/libass/ass_library.c b/aegisub/libass/ass_library.c index 53b91af16..5bca64485 100644 --- a/aegisub/libass/ass_library.c +++ b/aegisub/libass/ass_library.c @@ -3,21 +3,21 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "config.h" + #include #include #include @@ -57,8 +57,7 @@ void ass_library_done(ASS_Library *priv) void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir) { - if (priv->fonts_dir) - free(priv->fonts_dir); + free(priv->fonts_dir); priv->fonts_dir = fonts_dir ? strdup(fonts_dir) : 0; } @@ -77,8 +76,8 @@ void ass_set_style_overrides(ASS_Library *priv, char **list) if (priv->style_overrides) { for (p = priv->style_overrides; *p; ++p) free(*p); - free(priv->style_overrides); } + free(priv->style_overrides); if (!list) return; diff --git a/aegisub/libass/ass_library.h b/aegisub/libass/ass_library.h index e0db5c951..8faf15e93 100644 --- a/aegisub/libass/ass_library.h +++ b/aegisub/libass/ass_library.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_LIBRARY_H diff --git a/aegisub/libass/ass_parse.c b/aegisub/libass/ass_parse.c index 0ccb5a2b1..40aaf0430 100644 --- a/aegisub/libass/ass_parse.c +++ b/aegisub/libass/ass_parse.c @@ -68,9 +68,15 @@ void update_font(ASS_Renderer *render_priv) { unsigned val; ASS_FontDesc desc; - desc.family = strdup(render_priv->state.family); - desc.treat_family_as_pattern = - render_priv->state.treat_family_as_pattern; + desc.treat_family_as_pattern = render_priv->state.treat_family_as_pattern; + + if (render_priv->state.family[0] == '@') { + desc.vertical = 1; + desc.family = strdup(render_priv->state.family + 1); + } else { + desc.vertical = 0; + desc.family = strdup(render_priv->state.family); + } val = render_priv->state.bold; // 0 = normal, 1 = bold, >1 = exact weight @@ -208,12 +214,14 @@ static char *parse_vector_clip(ASS_Renderer *render_priv, char *p) { int scale = 1; int res = 0; - ASS_Drawing *drawing; + ASS_Drawing *drawing = render_priv->state.clip_drawing; + if (drawing && drawing->glyph) + FT_Done_Glyph((FT_Glyph) drawing->glyph); + ass_drawing_free(drawing); render_priv->state.clip_drawing = ass_drawing_new( render_priv->fontconfig_priv, render_priv->state.font, - render_priv->settings.hinting, render_priv->ftlibrary); drawing = render_priv->state.clip_drawing; skipopt('('); @@ -227,20 +235,6 @@ static char *parse_vector_clip(ASS_Renderer *render_priv, char *p) while (*p != ')' && *p != '}' && p != 0) ass_drawing_add_char(drawing, *p++); skipopt(')'); - if (ass_drawing_parse(drawing, 1)) { - // We need to translate the clip according to screen borders - if (render_priv->settings.left_margin != 0 || - render_priv->settings.top_margin != 0) { - FT_Vector trans = { - .x = int_to_d6(render_priv->settings.left_margin), - .y = -int_to_d6(render_priv->settings.top_margin), - }; - FT_Outline_Translate(&drawing->glyph->outline, trans.x, trans.y); - } - ass_msg(render_priv->library, MSGL_DBG2, - "Parsed vector clip: scale %d, scales (%f, %f) string [%s]\n", - scale, drawing->scale_x, drawing->scale_y, drawing->text); - } return p; } @@ -365,6 +359,22 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) render_priv->state.hspacing * (1 - pwr) + val * pwr; else render_priv->state.hspacing = render_priv->state.style->Spacing; + } else if (mystrcmp(&p, "fs+")) { + double val; + if (mystrtod(&p, &val)) { + val = render_priv->state.font_size + pwr * val; + } else + val = render_priv->state.style->FontSize; + if (render_priv->state.font) + change_font_size(render_priv, val); + } else if (mystrcmp(&p, "fs-")) { + double val; + if (mystrtod(&p, &val)) + val = render_priv->state.font_size - pwr * val; + else + val = render_priv->state.style->FontSize; + if (render_priv->state.font) + change_font_size(render_priv, val); } else if (mystrcmp(&p, "fs")) { double val; if (mystrtod(&p, &val)) @@ -461,8 +471,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) family[p - start] = '\0'; } else family = strdup(render_priv->state.style->FontName); - if (render_priv->state.family) - free(render_priv->state.family); + free(render_priv->state.family); render_priv->state.family = family; update_font(render_priv); } else if (mystrcmp(&p, "alpha")) { @@ -586,7 +595,7 @@ static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr) for (cnt = 0; cnt < 3; ++cnt) { if (*p == '\\') break; - v[cnt] = strtod(p, &p); + mystrtod(&p, &v[cnt]); skip(','); } if (cnt == 3) { @@ -836,7 +845,7 @@ void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event) } else if (strncmp(event->Effect, "Scroll down;", 12) == 0) { render_priv->state.scroll_direction = SCROLL_TB; } else { - ass_msg(render_priv->library, MSGL_V, + ass_msg(render_priv->library, MSGL_DBG2, "Unknown transition effect: '%s'", event->Effect); return; } @@ -894,7 +903,7 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str) break; } else if (*p != '\\') ass_msg(render_priv->library, MSGL_V, - "Unable to parse: '%s'", p); + "Unable to parse: '%.30s'", p); if (*p == 0) break; } @@ -918,6 +927,14 @@ unsigned get_next_char(ASS_Renderer *render_priv, char **str) p += 2; *str = p; return NBSP; + } else if (p[1] == '{') { + p += 2; + *str = p; + return '{'; + } else if (p[1] == '}') { + p += 2; + *str = p; + return '}'; } } chr = ass_utf8_get_char((char **) &p); diff --git a/aegisub/libass/ass_render.c b/aegisub/libass/ass_render.c index 6bc0c61ba..480fc4aee 100644 --- a/aegisub/libass/ass_render.c +++ b/aegisub/libass/ass_render.c @@ -3,49 +3,31 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" #include #include -#include -#include -#include FT_FREETYPE_H -#include FT_STROKER_H -#include FT_GLYPH_H -#include FT_SYNTHESIS_H -#include "ass.h" -#include "ass_font.h" -#include "ass_bitmap.h" -#include "ass_cache.h" -#include "ass_utils.h" -#include "ass_fontconfig.h" -#include "ass_library.h" -#include "ass_drawing.h" #include "ass_render.h" #include "ass_parse.h" #define MAX_GLYPHS_INITIAL 1024 #define MAX_LINES_INITIAL 64 #define SUBPIXEL_MASK 63 -#define SUBPIXEL_ACCURACY 7 // d6 mask for subpixel accuracy adjustment -#define GLYPH_CACHE_MAX 1000 -#define BITMAP_CACHE_MAX_SIZE 50 * 1048576 +#define SUBPIXEL_ACCURACY 7 static void ass_lazy_track_init(ASS_Renderer *render_priv) { @@ -119,27 +101,20 @@ ASS_Renderer *ass_renderer_init(ASS_Library *library) priv->text_info.max_glyphs = MAX_GLYPHS_INITIAL; priv->text_info.max_lines = MAX_LINES_INITIAL; - priv->text_info.glyphs = - calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo)); + priv->text_info.glyphs = calloc(MAX_GLYPHS_INITIAL, sizeof(GlyphInfo)); priv->text_info.lines = calloc(MAX_LINES_INITIAL, sizeof(LineInfo)); + priv->settings.font_size_coeff = 1.; + ass_init_exit: if (priv) - ass_msg(library, MSGL_INFO, "Init"); + ass_msg(library, MSGL_V, "Init"); else ass_msg(library, MSGL_ERR, "Init failed"); return priv; } -void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max, - int bitmap_max) -{ - render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX; - render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max : - BITMAP_CACHE_MAX_SIZE; -} - static void free_list_clear(ASS_Renderer *render_priv) { if (render_priv->free_head) { @@ -154,8 +129,6 @@ static void free_list_clear(ASS_Renderer *render_priv) } } -static void ass_free_images(ASS_Image *img); - void ass_renderer_done(ASS_Renderer *render_priv) { ass_font_cache_done(render_priv->cache.font_cache); @@ -170,14 +143,13 @@ void ass_renderer_done(ASS_Renderer *render_priv) FT_Stroker_Done(render_priv->state.stroker); render_priv->state.stroker = 0; } - if (render_priv && render_priv->ftlibrary) + if (render_priv->ftlibrary) FT_Done_FreeType(render_priv->ftlibrary); - if (render_priv && render_priv->fontconfig_priv) + if (render_priv->fontconfig_priv) fontconfig_done(render_priv->fontconfig_priv); - if (render_priv && render_priv->synth_priv) + if (render_priv->synth_priv) ass_synth_done(render_priv->synth_priv); - if (render_priv && render_priv->eimg) - free(render_priv->eimg); + free(render_priv->eimg); free(render_priv->text_info.glyphs); free(render_priv->text_info.lines); @@ -196,21 +168,85 @@ static ASS_Image *my_draw_bitmap(unsigned char *bitmap, int bitmap_w, int bitmap_h, int stride, int dst_x, int dst_y, uint32_t color) { - ASS_Image *img = calloc(1, sizeof(ASS_Image)); + ASS_Image *img = malloc(sizeof(ASS_Image)); - img->w = bitmap_w; - img->h = bitmap_h; - img->stride = stride; - img->bitmap = bitmap; - img->color = color; - img->dst_x = dst_x; - img->dst_y = dst_y; + if (img) { + img->w = bitmap_w; + img->h = bitmap_h; + img->stride = stride; + img->bitmap = bitmap; + img->color = color; + img->dst_x = dst_x; + img->dst_y = dst_y; + } return img; } -static double x2scr_pos(ASS_Renderer *render_priv, double x); -static double y2scr_pos(ASS_Renderer *render_priv, double y); +/** + * \brief Mapping between script and screen coordinates + */ +static double x2scr(ASS_Renderer *render_priv, double x) +{ + return x * render_priv->orig_width_nocrop / render_priv->font_scale_x / + render_priv->track->PlayResX + + FFMAX(render_priv->settings.left_margin, 0); +} +static double x2scr_pos(ASS_Renderer *render_priv, double x) +{ + return x * render_priv->orig_width / render_priv->font_scale_x / render_priv->track->PlayResX + + render_priv->settings.left_margin; +} +static double x2scr_scaled(ASS_Renderer *render_priv, double x) +{ + return x * render_priv->orig_width_nocrop / + render_priv->track->PlayResX + + FFMAX(render_priv->settings.left_margin, 0); +} +static double x2scr_pos_scaled(ASS_Renderer *render_priv, double x) +{ + return x * render_priv->orig_width / render_priv->track->PlayResX + + render_priv->settings.left_margin; +} +/** + * \brief Mapping between script and screen coordinates + */ +static double y2scr(ASS_Renderer *render_priv, double y) +{ + return y * render_priv->orig_height_nocrop / + render_priv->track->PlayResY + + FFMAX(render_priv->settings.top_margin, 0); +} +static double y2scr_pos(ASS_Renderer *render_priv, double y) +{ + return y * render_priv->orig_height / render_priv->track->PlayResY + + render_priv->settings.top_margin; +} + +// the same for toptitles +static double y2scr_top(ASS_Renderer *render_priv, double y) +{ + if (render_priv->settings.use_margins) + return y * render_priv->orig_height_nocrop / + render_priv->track->PlayResY; + else + return y * render_priv->orig_height_nocrop / + render_priv->track->PlayResY + + FFMAX(render_priv->settings.top_margin, 0); +} +// the same for subtitles +static double y2scr_sub(ASS_Renderer *render_priv, double y) +{ + if (render_priv->settings.use_margins) + return y * render_priv->orig_height_nocrop / + render_priv->track->PlayResY + + FFMAX(render_priv->settings.top_margin, 0) + + FFMAX(render_priv->settings.bottom_margin, 0); + else + return y * render_priv->orig_height_nocrop / + render_priv->track->PlayResY + + FFMAX(render_priv->settings.top_margin, 0); +} /* * \brief Convert bitmap glyphs into ASS_Image list with inverse clipping @@ -238,9 +274,9 @@ static ASS_Image **render_glyph_i(ASS_Renderer *render_priv, dst_y += bm->top; // we still need to clip against screen boundaries - zx = x2scr_pos(render_priv, 0); + zx = x2scr_pos_scaled(render_priv, 0); zy = y2scr_pos(render_priv, 0); - sx = x2scr_pos(render_priv, render_priv->track->PlayResX); + sx = x2scr_pos_scaled(render_priv, render_priv->track->PlayResX); sy = y2scr_pos(render_priv, render_priv->track->PlayResY); x0 = 0; @@ -295,6 +331,7 @@ static ASS_Image **render_glyph_i(ASS_Renderer *render_priv, img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->w + r[j].x0, lbrk - r[j].x0, r[j].y1 - r[j].y0, bm->w, dst_x + r[j].x0, dst_y + r[j].y0, color); + if (!img) break; *tail = img; tail = &img->next; } @@ -303,6 +340,7 @@ static ASS_Image **render_glyph_i(ASS_Renderer *render_priv, img = my_draw_bitmap(bm->buffer + r[j].y0 * bm->w + lbrk, r[j].x1 - lbrk, r[j].y1 - r[j].y0, bm->w, dst_x + lbrk, dst_y + r[j].y0, color2); + if (!img) break; *tail = img; tail = &img->next; } @@ -384,6 +422,7 @@ render_glyph(ASS_Renderer *render_priv, Bitmap *bm, int dst_x, int dst_y, img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + b_x0, brk - b_x0, b_y1 - b_y0, bm->w, dst_x + b_x0, dst_y + b_y0, color); + if (!img) return tail; *tail = img; tail = &img->next; } @@ -393,6 +432,7 @@ render_glyph(ASS_Renderer *render_priv, Bitmap *bm, int dst_x, int dst_y, img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + brk, b_x1 - brk, b_y1 - b_y0, bm->w, dst_x + brk, dst_y + b_y0, color2); + if (!img) return tail; *tail = img; tail = &img->next; } @@ -464,7 +504,6 @@ render_overlap(ASS_Renderer *render_priv, ASS_Image **last_tail, cur_top = top - by; // Query cache - memset(&hk, 0, sizeof(hk)); hk.a = (*last_tail)->bitmap; hk.b = (*tail)->bitmap; hk.aw = aw; @@ -529,23 +568,73 @@ static void blend_vector_clip(ASS_Renderer *render_priv, FT_BitmapGlyph clip_bm; ASS_Image *cur; ASS_Drawing *drawing = render_priv->state.clip_drawing; + GlyphHashKey key; + GlyphHashValue *val; int error; if (!drawing) return; - // Rasterize it - FT_Glyph_Copy((FT_Glyph) drawing->glyph, &glyph); - error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); - if (error) { - ass_msg(render_priv->library, MSGL_V, - "Clip vector rasterization failed: %d. Skipping.", error); - goto blend_vector_exit; - } - clip_bm = (FT_BitmapGlyph) glyph; - clip_bm->top = -clip_bm->top; + // Try to get mask from cache + ass_drawing_hash(drawing); + memset(&key, 0, sizeof(key)); + key.ch = -2; + key.drawing_hash = drawing->hash; + val = cache_find_glyph(render_priv->cache.glyph_cache, &key); - assert(clip_bm->bitmap.pitch >= 0); + if (val) { + clip_bm = (FT_BitmapGlyph) val->glyph; + } else { + GlyphHashValue v; + + // Not found in cache, parse and rasterize it + glyph = (FT_Glyph) *ass_drawing_parse(drawing, 1); + if (!glyph) { + ass_msg(render_priv->library, MSGL_WARN, + "Clip vector parsing failed. Skipping."); + goto blend_vector_error; + } + + // We need to translate the clip according to screen borders + if (render_priv->settings.left_margin != 0 || + render_priv->settings.top_margin != 0) { + FT_Vector trans = { + .x = int_to_d6(render_priv->settings.left_margin), + .y = -int_to_d6(render_priv->settings.top_margin), + }; + FT_Outline_Translate(&drawing->glyph->outline, + trans.x, trans.y); + } + + // Check glyph bounding box size + if (check_glyph_area(render_priv->library, glyph)) { + FT_Done_Glyph(glyph); + glyph = 0; + goto blend_vector_error; + } + + ass_msg(render_priv->library, MSGL_DBG2, + "Parsed vector clip: scales (%f, %f) string [%s]\n", + drawing->scale_x, drawing->scale_y, drawing->text); + + error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); + if (error) { + ass_msg(render_priv->library, MSGL_WARN, + "Clip vector rasterization failed: %d. Skipping.", error); + FT_Done_Glyph(glyph); + glyph = 0; + } + +blend_vector_error: + clip_bm = (FT_BitmapGlyph) glyph; + + // Add to cache + memset(&v, 0, sizeof(v)); + v.glyph = glyph; + cache_add_glyph(render_priv->cache.glyph_cache, &key, &v); + } + + if (!clip_bm) goto blend_vector_exit; // Iterate through bitmaps and blend/clip them for (cur = head; cur; cur = cur->next) { @@ -563,7 +652,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv, ah = cur->h; as = cur->stride; bx = clip_bm->left; - by = clip_bm->top; + by = -clip_bm->top; bw = clip_bm->bitmap.width; bh = clip_bm->bitmap.rows; bs = clip_bm->bitmap.pitch; @@ -589,6 +678,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv, // Allocate new buffer and add to free list nbuffer = malloc(as * ah); + if (!nbuffer) goto blend_vector_exit; free_list_add(render_priv, nbuffer); // Blend together @@ -609,6 +699,7 @@ static void blend_vector_clip(ASS_Renderer *render_priv, // Allocate new buffer and add to free list nbuffer = calloc(as, ah); + if (!nbuffer) goto blend_vector_exit; free_list_add(render_priv, nbuffer); // Blend together @@ -622,8 +713,6 @@ static void blend_vector_clip(ASS_Renderer *render_priv, cur->bitmap = nbuffer; } - // Free clip vector and its bitmap, we don't need it anymore - FT_Done_Glyph(glyph); blend_vector_exit: ass_drawing_free(render_priv->state.clip_drawing); render_priv->state.clip_drawing = 0; @@ -633,8 +722,7 @@ blend_vector_exit: * \brief Convert TextInfo struct to ASS_Image list * Splits glyphs in halves when needed (for \kf karaoke). */ -static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, - int dst_y) +static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, int dst_y) { int pen_x, pen_y; int i; @@ -731,62 +819,6 @@ static ASS_Image *render_text(ASS_Renderer *render_priv, int dst_x, return head; } -/** - * \brief Mapping between script and screen coordinates - */ -static double x2scr(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width_nocrop / - render_priv->track->PlayResX + - FFMAX(render_priv->settings.left_margin, 0); -} -static double x2scr_pos(ASS_Renderer *render_priv, double x) -{ - return x * render_priv->orig_width / render_priv->track->PlayResX + - render_priv->settings.left_margin; -} - -/** - * \brief Mapping between script and screen coordinates - */ -static double y2scr(ASS_Renderer *render_priv, double y) -{ - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0); -} -static double y2scr_pos(ASS_Renderer *render_priv, double y) -{ - return y * render_priv->orig_height / render_priv->track->PlayResY + - render_priv->settings.top_margin; -} - -// the same for toptitles -static double y2scr_top(ASS_Renderer *render_priv, double y) -{ - if (render_priv->settings.use_margins) - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY; - else - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0); -} - -// the same for subtitles -static double y2scr_sub(ASS_Renderer *render_priv, double y) -{ - if (render_priv->settings.use_margins) - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, - 0) + FFMAX(render_priv->settings.bottom_margin, 0); - else - return y * render_priv->orig_height_nocrop / - render_priv->track->PlayResY + - FFMAX(render_priv->settings.top_margin, 0); -} - static void compute_string_bbox(TextInfo *info, DBBox *bbox) { int i; @@ -845,8 +877,6 @@ void reset_render_context(ASS_Renderer *render_priv) render_priv->state.frz = M_PI * render_priv->state.style->Angle / 180.; render_priv->state.fax = render_priv->state.fay = 0.; render_priv->state.wrap_style = render_priv->track->WrapStyle; - - // FIXME: does not reset unsupported attributes. } /** @@ -878,11 +908,10 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event) render_priv->state.effect_type = EF_NONE; render_priv->state.effect_timing = 0; render_priv->state.effect_skip_timing = 0; - render_priv->state.drawing = - ass_drawing_new(render_priv->fontconfig_priv, - render_priv->state.font, - render_priv->settings.hinting, - render_priv->ftlibrary); + ass_drawing_free(render_priv->state.drawing); + render_priv->state.drawing = ass_drawing_new(render_priv->fontconfig_priv, + render_priv->state.font, + render_priv->ftlibrary); apply_transition_effects(render_priv, event); } @@ -896,88 +925,6 @@ static void free_render_context(ASS_Renderer *render_priv) render_priv->state.drawing = NULL; } -// Calculate the cbox of a series of points -static void -get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end) -{ - box->xMin = box->yMin = INT_MAX; - box->xMax = box->yMax = INT_MIN; - int i; - - for (i = start; i < end; i++) { - box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin; - box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax; - box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin; - box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax; - } -} - -/** - * \brief Fix-up stroker result for huge borders by removing the contours from - * the outline that are harmful. -*/ -static void fix_freetype_stroker(FT_OutlineGlyph glyph, int border_x, - int border_y) -{ - int nc = glyph->outline.n_contours; - int begin, stop; - char modified = 0; - char *valid_cont; - int start = 0; - int end = -1; - FT_BBox *boxes = calloc(nc, sizeof(FT_BBox)); - int i, j; - - // Create a list of cboxes of the contours - for (i = 0; i < nc; i++) { - start = end + 1; - end = glyph->outline.contours[i]; - get_contour_cbox(&boxes[i], glyph->outline.points, start, end); - } - - // if a) contour's cbox is contained in another contours cbox - // b) contour's height or width is smaller than the border*2 - // the contour can be safely removed. - valid_cont = calloc(1, nc); - for (i = 0; i < nc; i++) { - valid_cont[i] = 1; - for (j = 0; j < nc; j++) { - if (i == j) - continue; - if (boxes[i].xMin >= boxes[j].xMin && - boxes[i].xMax <= boxes[j].xMax && - boxes[i].yMin >= boxes[j].yMin && - boxes[i].yMax <= boxes[j].yMax) { - int width = boxes[i].xMax - boxes[i].xMin; - int height = boxes[i].yMax - boxes[i].yMin; - if (width < border_x * 2 || height < border_y * 2) { - valid_cont[i] = 0; - modified = 1; - break; - } - } - } - } - - // Zero-out contours that can be removed; much simpler than copying - if (modified) { - for (i = 0; i < nc; i++) { - if (valid_cont[i]) - continue; - begin = (i == 0) ? 0 : glyph->outline.contours[i - 1] + 1; - stop = glyph->outline.contours[i]; - for (j = begin; j <= stop; j++) { - glyph->outline.points[j].x = 0; - glyph->outline.points[j].y = 0; - glyph->outline.tags[j] = 0; - } - } - } - - free(boxes); - free(valid_cont); -} - /* * Replace the outline of a glyph by a contour which makes up a simple * opaque rectangle. @@ -989,8 +936,7 @@ static void draw_opaque_box(ASS_Renderer *render_priv, uint32_t ch, int i; int adv = d16_to_d6(glyph->advance.x); double scale_y = render_priv->state.scale_y; - double scale_x = render_priv->state.scale_x - * render_priv->font_scale_x; + double scale_x = render_priv->state.scale_x; FT_OutlineGlyph og = (FT_OutlineGlyph) glyph; FT_Outline *ol; @@ -1079,6 +1025,38 @@ static void stroke_outline_glyph(ASS_Renderer *render_priv, } } +/** + * \brief Prepare glyph hash + */ +static void +fill_glyph_hash(ASS_Renderer *priv, GlyphHashKey *key, + ASS_Drawing *drawing, uint32_t ch) +{ + if (drawing->hash) { + key->scale_x = double_to_d16(priv->state.scale_x); + key->scale_y = double_to_d16(priv->state.scale_y); + key->outline.x = priv->state.border_x * 0xFFFF; + key->outline.y = priv->state.border_y * 0xFFFF; + key->border_style = priv->state.style->BorderStyle; + key->drawing_hash = drawing->hash; + // not very clean, but works + key->size = drawing->scale; + key->ch = -1; + } else { + key->font = priv->state.font; + key->size = priv->state.font_size; + key->ch = ch; + key->bold = priv->state.bold; + key->italic = priv->state.italic; + key->scale_x = double_to_d16(priv->state.scale_x); + key->scale_y = double_to_d16(priv->state.scale_y); + key->outline.x = priv->state.border_x * 0xFFFF; + key->outline.y = priv->state.border_y * 0xFFFF; + key->flags = priv->state.flags; + key->border_style = priv->state.style->BorderStyle; + } +} + /** * \brief Get normal and outline (border) glyphs * \param symbol ucs4 char @@ -1094,35 +1072,15 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, { GlyphHashValue *val; GlyphHashKey key; - memset(&key, 0, sizeof(key)); - if (drawing->hash) { - key.scale_x = double_to_d16(render_priv->state.scale_x); - key.scale_y = double_to_d16(render_priv->state.scale_y); - key.outline.x = render_priv->state.border_x * 0xFFFF; - key.outline.y = render_priv->state.border_y * 0xFFFF; - key.border_style = render_priv->state.style->BorderStyle; - key.drawing_hash = drawing->hash; - } else { - key.font = render_priv->state.font; - key.size = render_priv->state.font_size; - key.ch = symbol; - key.bold = render_priv->state.bold; - key.italic = render_priv->state.italic; - key.scale_x = double_to_d16(render_priv->state.scale_x); - key.scale_y = double_to_d16(render_priv->state.scale_y); - key.outline.x = render_priv->state.border_x * 0xFFFF; - key.outline.y = render_priv->state.border_y * 0xFFFF; - key.flags = render_priv->state.flags; - key.border_style = render_priv->state.style->BorderStyle; - } + memset(&key, 0, sizeof(key)); memset(info, 0, sizeof(GlyphInfo)); + fill_glyph_hash(render_priv, &key, drawing, symbol); val = cache_find_glyph(render_priv->cache.glyph_cache, &key); if (val) { - FT_Glyph_Copy(val->glyph, &info->glyph); - if (val->outline_glyph) - FT_Glyph_Copy(val->outline_glyph, &info->outline_glyph); + info->glyph = val->glyph; + info->outline_glyph = val->outline_glyph; info->bbox = val->bbox_scaled; info->advance.x = val->advance.x; info->advance.y = val->advance.y; @@ -1135,7 +1093,7 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, if (drawing->hash) { if(!ass_drawing_parse(drawing, 0)) return; - FT_Glyph_Copy((FT_Glyph) drawing->glyph, &info->glyph); + info->glyph = (FT_Glyph) drawing->glyph; } else { info->glyph = ass_font_get_glyph(render_priv->fontconfig_priv, @@ -1145,6 +1103,7 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, } if (!info->glyph) return; + info->advance.x = d16_to_d6(info->glyph->advance.x); info->advance.y = d16_to_d6(info->glyph->advance.y); FT_Glyph_Get_CBox(info->glyph, FT_GLYPH_BBOX_SUBPIXELS, &info->bbox); @@ -1158,8 +1117,9 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, render_priv->border_scale), double_to_d6(render_priv->state.border_y * render_priv->border_scale)); - } else if (render_priv->state.border_x > 0 || - render_priv->state.border_y > 0) { + } else if ((render_priv->state.border_x > 0 + || render_priv->state.border_y > 0) + && key.scale_x && key.scale_y) { FT_Glyph_Copy(info->glyph, &info->outline_glyph); stroke_outline_glyph(render_priv, @@ -1171,9 +1131,8 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, } memset(&v, 0, sizeof(v)); - FT_Glyph_Copy(info->glyph, &v.glyph); - if (info->outline_glyph) - FT_Glyph_Copy(info->outline_glyph, &v.outline_glyph); + v.glyph = info->glyph; + v.outline_glyph = info->outline_glyph; v.advance = info->advance; v.bbox_scaled = info->bbox; if (drawing->hash) { @@ -1184,10 +1143,81 @@ get_outline_glyph(ASS_Renderer *render_priv, int symbol, GlyphInfo *info, } } -static void transform_3d(FT_Vector shift, FT_Glyph *glyph, - FT_Glyph *glyph2, double frx, double fry, - double frz, double fax, double fay, double scale, - int yshift); +/** + * \brief Apply transformation to outline points of a glyph + * Applies rotations given by frx, fry and frz and projects the points back + * onto the screen plane. + */ +static void +transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry, + double frz, double fax, double fay, double scale, + int yshift) +{ + double sx = sin(frx); + double sy = sin(fry); + double sz = sin(frz); + double cx = cos(frx); + double cy = cos(fry); + double cz = cos(frz); + FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline; + FT_Vector *p = outline->points; + double x, y, z, xx, yy, zz; + int i, dist; + + dist = 20000 * scale; + for (i = 0; i < outline->n_points; i++) { + x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y)); + y = (double) p[i].y + shift.y + (-fay * p[i].x); + z = 0.; + + xx = x * cz + y * sz; + yy = -(x * sz - y * cz); + zz = z; + + x = xx; + y = yy * cx + zz * sx; + z = yy * sx - zz * cx; + + xx = x * cy + z * sy; + yy = y; + zz = x * sy - z * cy; + + zz = FFMAX(zz, 1000 - dist); + + x = (xx * dist) / (zz + dist); + y = (yy * dist) / (zz + dist); + p[i].x = x - shift.x + 0.5; + p[i].y = y - shift.y + 0.5; + } +} + +/** + * \brief Apply 3d transformation to several objects + * \param shift FreeType vector + * \param glyph FreeType glyph + * \param glyph2 FreeType glyph + * \param frx x-axis rotation angle + * \param fry y-axis rotation angle + * \param frz z-axis rotation angle + * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it. + */ +static void +transform_3d(FT_Vector shift, FT_Glyph *glyph, FT_Glyph *glyph2, + double frx, double fry, double frz, double fax, double fay, + double scale, int yshift) +{ + frx = -frx; + frz = -frz; + if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) { + if (glyph && *glyph) + transform_3d_points(shift, *glyph, frx, fry, frz, + fax, fay, scale, yshift); + + if (glyph2 && *glyph2) + transform_3d_points(shift, *glyph2, frx, fry, frz, + fax, fay, scale, yshift); + } +} /** * \brief Get bitmaps for a glyph @@ -1217,38 +1247,48 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) info->bm = info->bm_o = info->bm_s = 0; if (info->glyph && info->symbol != '\n' && info->symbol != 0 && !info->skip) { + FT_Glyph glyph; + FT_Glyph outline; + double scale_x = render_priv->font_scale_x; + + FT_Glyph_Copy(info->glyph, &glyph); + FT_Glyph_Copy(info->outline_glyph, &outline); // calculating rotation shift vector (from rotation origin to the glyph basepoint) - shift.x = info->hash_key.shift_x; - shift.y = info->hash_key.shift_y; - fax_scaled = info->fax * render_priv->font_scale_x * + shift.x = key->shift_x; + shift.y = key->shift_y; + fax_scaled = info->fax * render_priv->state.scale_x; fay_scaled = info->fay * render_priv->state.scale_y; // apply rotation - transform_3d(shift, &info->glyph, &info->outline_glyph, + transform_3d(shift, &glyph, &outline, info->frx, info->fry, info->frz, fax_scaled, fay_scaled, render_priv->font_scale, info->asc); - // subpixel shift - if (info->glyph) - FT_Outline_Translate( - &((FT_OutlineGlyph) info->glyph)->outline, - info->hash_key.advance.x, - -info->hash_key.advance.y); - if (info->outline_glyph) - FT_Outline_Translate( - &((FT_OutlineGlyph) info->outline_glyph)->outline, - info->hash_key.advance.x, - -info->hash_key.advance.y); + // PAR correction scaling + FT_Matrix m = { double_to_d16(scale_x), 0, + 0, double_to_d16(1.0) }; + // subpixel shift + if (glyph) { + FT_Outline *outl = &((FT_OutlineGlyph) glyph)->outline; + if (scale_x != 1.0) + FT_Outline_Transform(outl, &m); + FT_Outline_Translate(outl, key->advance.x, -key->advance.y); + } + if (outline) { + FT_Outline *outl = &((FT_OutlineGlyph) outline)->outline; + if (scale_x != 1.0) + FT_Outline_Transform(outl, &m); + FT_Outline_Translate(outl, key->advance.x, -key->advance.y); + } // render glyph error = glyph_to_bitmap(render_priv->library, render_priv->synth_priv, - info->glyph, info->outline_glyph, + glyph, outline, &info->bm, &info->bm_o, &info->bm_s, info->be, info->blur * render_priv->border_scale, - info->hash_key.shadow_offset, - info->hash_key.border_style); + key->shadow_offset, key->border_style); if (error) info->symbol = 0; @@ -1256,15 +1296,12 @@ get_bitmap_glyph(ASS_Renderer *render_priv, GlyphInfo *info) hash_val.bm_o = info->bm_o; hash_val.bm = info->bm; hash_val.bm_s = info->bm_s; - cache_add_bitmap(render_priv->cache.bitmap_cache, - &(info->hash_key), &hash_val); + cache_add_bitmap(render_priv->cache.bitmap_cache, key, &hash_val); + + FT_Done_Glyph(glyph); + FT_Done_Glyph(outline); } } - // deallocate glyphs - if (info->glyph) - FT_Done_Glyph(info->glyph); - if (info->outline_glyph) - FT_Done_Glyph(info->outline_glyph); } /** @@ -1377,7 +1414,7 @@ static void trim_whitespace(ASS_Renderer *render_priv) * the difference in lengths between this two lines. * The result may not be optimal, but usually is good enough. * - * FIXME: implement style 0 and 3 correctly, add support for style 1 + * FIXME: implement style 0 and 3 correctly */ static void wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width) @@ -1415,13 +1452,9 @@ wrap_lines_smart(ASS_Renderer *render_priv, double max_text_width) && (render_priv->state.wrap_style != 2)) { break_type = 1; break_at = last_space; - if (break_at == -1) - break_at = i - 1; - if (break_at == -1) - break_at = 0; - ass_msg(render_priv->library, MSGL_DBG2, "overfill at %d", i); - ass_msg(render_priv->library, MSGL_DBG2, "line break at %d", - break_at); + if (break_at >= 0) + ass_msg(render_priv->library, MSGL_DBG2, "line break at %d", + break_at); } if (break_at != -1) { @@ -1646,82 +1679,43 @@ static void get_base_point(DBBox *bbox, int alignment, double *bx, double *by) } /** - * \brief Apply transformation to outline points of a glyph - * Applies rotations given by frx, fry and frz and projects the points back - * onto the screen plane. + * Prepare bitmap hash key of a glyph */ static void -transform_3d_points(FT_Vector shift, FT_Glyph glyph, double frx, double fry, - double frz, double fax, double fay, double scale, - int yshift) +fill_bitmap_hash(ASS_Renderer *priv, BitmapHashKey *hash_key, + ASS_Drawing *drawing, FT_Vector pen, uint32_t code) { - double sx = sin(frx); - double sy = sin(fry); - double sz = sin(frz); - double cx = cos(frx); - double cy = cos(fry); - double cz = cos(frz); - FT_Outline *outline = &((FT_OutlineGlyph) glyph)->outline; - FT_Vector *p = outline->points; - double x, y, z, xx, yy, zz; - int i, dist; - - dist = 20000 * scale; - for (i = 0; i < outline->n_points; i++) { - x = (double) p[i].x + shift.x + (fax * (yshift - p[i].y)); - y = (double) p[i].y + shift.y + (-fay * p[i].x); - z = 0.; - - xx = x * cz + y * sz; - yy = -(x * sz - y * cz); - zz = z; - - x = xx; - y = yy * cx + zz * sx; - z = yy * sx - zz * cx; - - xx = x * cy + z * sy; - yy = y; - zz = x * sy - z * cy; - - zz = FFMAX(zz, 1000 - dist); - - x = (xx * dist) / (zz + dist); - y = (yy * dist) / (zz + dist); - p[i].x = x - shift.x + 0.5; - p[i].y = y - shift.y + 0.5; + if (!drawing->hash) { + hash_key->font = priv->state.font; + hash_key->size = priv->state.font_size; + hash_key->bold = priv->state.bold; + hash_key->italic = priv->state.italic; + } else { + hash_key->drawing_hash = drawing->hash; + hash_key->size = drawing->scale; } + hash_key->ch = code; + hash_key->outline.x = double_to_d16(priv->state.border_x); + hash_key->outline.y = double_to_d16(priv->state.border_y); + hash_key->scale_x = double_to_d16(priv->state.scale_x); + hash_key->scale_y = double_to_d16(priv->state.scale_y); + hash_key->frx = rot_key(priv->state.frx); + hash_key->fry = rot_key(priv->state.fry); + hash_key->frz = rot_key(priv->state.frz); + hash_key->fax = double_to_d16(priv->state.fax); + hash_key->fay = double_to_d16(priv->state.fay); + hash_key->be = priv->state.be; + hash_key->blur = priv->state.blur; + hash_key->border_style = priv->state.style->BorderStyle; + hash_key->shadow_offset.x = double_to_d6( + priv->state.shadow_x * priv->border_scale - + (int) (priv->state.shadow_x * priv->border_scale)); + hash_key->shadow_offset.y = double_to_d6( + priv->state.shadow_y * priv->border_scale - + (int) (priv->state.shadow_y * priv->border_scale)); + hash_key->flags = priv->state.flags; } -/** - * \brief Apply 3d transformation to several objects - * \param shift FreeType vector - * \param glyph FreeType glyph - * \param glyph2 FreeType glyph - * \param frx x-axis rotation angle - * \param fry y-axis rotation angle - * \param frz z-axis rotation angle - * Rotates both glyphs by frx, fry and frz. Shift vector is added before rotation and subtracted after it. - */ -static void -transform_3d(FT_Vector shift, FT_Glyph *glyph, FT_Glyph *glyph2, - double frx, double fry, double frz, double fax, double fay, - double scale, int yshift) -{ - frx = -frx; - frz = -frz; - if (frx != 0. || fry != 0. || frz != 0. || fax != 0. || fay != 0.) { - if (glyph && *glyph) - transform_3d_points(shift, *glyph, frx, fry, frz, - fax, fay, scale, yshift); - - if (glyph2 && *glyph2) - transform_3d_points(shift, *glyph2, frx, fry, frz, - fax, fay, scale, yshift); - } -} - - /** * \brief Main ass rendering function, glues everything together * \param event event to render @@ -1746,6 +1740,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, double device_x = 0; double device_y = 0; TextInfo *text_info = &render_priv->text_info; + GlyphInfo *glyphs = render_priv->text_info.glyphs; ASS_Drawing *drawing; if (event->Style >= render_priv->track->n_styles) { @@ -1779,7 +1774,6 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, // Parse drawing if (drawing->i) { drawing->scale_x = render_priv->state.scale_x * - render_priv->font_scale_x * render_priv->font_scale; drawing->scale_y = render_priv->state.scale_y * render_priv->font_scale; @@ -1800,7 +1794,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, if (text_info->length >= text_info->max_glyphs) { // Raise maximum number of glyphs text_info->max_glyphs *= 2; - text_info->glyphs = + text_info->glyphs = glyphs = realloc(text_info->glyphs, sizeof(GlyphInfo) * text_info->max_glyphs); } @@ -1811,139 +1805,82 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, delta = ass_font_get_kerning(render_priv->state.font, previous, code); - pen.x += delta.x * render_priv->state.scale_x - * render_priv->font_scale_x; - pen.y += delta.y * render_priv->state.scale_y - * render_priv->font_scale_x; + pen.x += delta.x * render_priv->state.scale_x; + pen.y += delta.y * render_priv->state.scale_y; } ass_font_set_transform(render_priv->state.font, - render_priv->state.scale_x * - render_priv->font_scale_x, + render_priv->state.scale_x, render_priv->state.scale_y, NULL); get_outline_glyph(render_priv, code, - text_info->glyphs + text_info->length, drawing); + glyphs + text_info->length, drawing); // Add additional space after italic to non-italic style changes if (text_info->length && - text_info->glyphs[text_info->length - 1].hash_key.italic && + glyphs[text_info->length - 1].hash_key.italic && !render_priv->state.italic) { int back = text_info->length - 1; - GlyphInfo *og = &text_info->glyphs[back]; + GlyphInfo *og = &glyphs[back]; while (back && og->bbox.xMax - og->bbox.xMin == 0 && og->hash_key.italic) - og = &text_info->glyphs[--back]; + og = &glyphs[--back]; if (og->bbox.xMax > og->advance.x) { // The FreeType oblique slants by 6/16 pen.x += og->bbox.yMax * 0.375; } } - text_info->glyphs[text_info->length].pos.x = pen.x; - text_info->glyphs[text_info->length].pos.y = pen.y; + glyphs[text_info->length].pos.x = pen.x; + glyphs[text_info->length].pos.y = pen.y; - pen.x += text_info->glyphs[text_info->length].advance.x; + pen.x += glyphs[text_info->length].advance.x; pen.x += double_to_d6(render_priv->state.hspacing * render_priv->font_scale * render_priv->state.scale_x); - pen.y += text_info->glyphs[text_info->length].advance.y; + pen.y += glyphs[text_info->length].advance.y; pen.y += (render_priv->state.fay * render_priv->state.scale_y) * - text_info->glyphs[text_info->length].advance.x; + glyphs[text_info->length].advance.x; previous = code; - text_info->glyphs[text_info->length].symbol = code; - text_info->glyphs[text_info->length].linebreak = 0; + glyphs[text_info->length].symbol = code; + glyphs[text_info->length].linebreak = 0; for (i = 0; i < 4; ++i) { uint32_t clr = render_priv->state.c[i]; change_alpha(&clr, mult_alpha(_a(clr), render_priv->state.fade), 1.); - text_info->glyphs[text_info->length].c[i] = clr; + glyphs[text_info->length].c[i] = clr; } - text_info->glyphs[text_info->length].effect_type = - render_priv->state.effect_type; - text_info->glyphs[text_info->length].effect_timing = + glyphs[text_info->length].effect_type = render_priv->state.effect_type; + glyphs[text_info->length].effect_timing = render_priv->state.effect_timing; - text_info->glyphs[text_info->length].effect_skip_timing = + glyphs[text_info->length].effect_skip_timing = render_priv->state.effect_skip_timing; - text_info->glyphs[text_info->length].be = render_priv->state.be; - text_info->glyphs[text_info->length].blur = render_priv->state.blur; - text_info->glyphs[text_info->length].shadow_x = - render_priv->state.shadow_x; - text_info->glyphs[text_info->length].shadow_y = - render_priv->state.shadow_y; - text_info->glyphs[text_info->length].frx = render_priv->state.frx; - text_info->glyphs[text_info->length].fry = render_priv->state.fry; - text_info->glyphs[text_info->length].frz = render_priv->state.frz; - text_info->glyphs[text_info->length].fax = render_priv->state.fax; - text_info->glyphs[text_info->length].fay = render_priv->state.fay; + glyphs[text_info->length].be = render_priv->state.be; + glyphs[text_info->length].blur = render_priv->state.blur; + glyphs[text_info->length].shadow_x = render_priv->state.shadow_x; + glyphs[text_info->length].shadow_y = render_priv->state.shadow_y; + glyphs[text_info->length].frx = render_priv->state.frx; + glyphs[text_info->length].fry = render_priv->state.fry; + glyphs[text_info->length].frz = render_priv->state.frz; + glyphs[text_info->length].fax = render_priv->state.fax; + glyphs[text_info->length].fay = render_priv->state.fay; if (drawing->hash) { - text_info->glyphs[text_info->length].asc = drawing->asc; - text_info->glyphs[text_info->length].desc = drawing->desc; + glyphs[text_info->length].asc = drawing->asc; + glyphs[text_info->length].desc = drawing->desc; } else { ass_font_get_asc_desc(render_priv->state.font, code, - &text_info->glyphs[text_info->length].asc, - &text_info->glyphs[text_info->length].desc); + &glyphs[text_info->length].asc, + &glyphs[text_info->length].desc); - text_info->glyphs[text_info->length].asc *= - render_priv->state.scale_y; - text_info->glyphs[text_info->length].desc *= - render_priv->state.scale_y; + glyphs[text_info->length].asc *= render_priv->state.scale_y; + glyphs[text_info->length].desc *= render_priv->state.scale_y; } - // fill bitmap_hash_key - if (!drawing->hash) { - text_info->glyphs[text_info->length].hash_key.font = - render_priv->state.font; - text_info->glyphs[text_info->length].hash_key.size = - render_priv->state.font_size; - text_info->glyphs[text_info->length].hash_key.bold = - render_priv->state.bold; - text_info->glyphs[text_info->length].hash_key.italic = - render_priv->state.italic; - } else - text_info->glyphs[text_info->length].hash_key.drawing_hash = - drawing->hash; - text_info->glyphs[text_info->length].hash_key.ch = code; - text_info->glyphs[text_info->length].hash_key.outline.x = - double_to_d16(render_priv->state.border_x); - text_info->glyphs[text_info->length].hash_key.outline.y = - double_to_d16(render_priv->state.border_y); - text_info->glyphs[text_info->length].hash_key.scale_x = - double_to_d16(render_priv->state.scale_x); - text_info->glyphs[text_info->length].hash_key.scale_y = - double_to_d16(render_priv->state.scale_y); - text_info->glyphs[text_info->length].hash_key.frx = - rot_key(render_priv->state.frx); - text_info->glyphs[text_info->length].hash_key.fry = - rot_key(render_priv->state.fry); - text_info->glyphs[text_info->length].hash_key.frz = - rot_key(render_priv->state.frz); - text_info->glyphs[text_info->length].hash_key.fax = - double_to_d16(render_priv->state.fax); - text_info->glyphs[text_info->length].hash_key.fay = - double_to_d16(render_priv->state.fay); - text_info->glyphs[text_info->length].hash_key.advance.x = pen.x; - text_info->glyphs[text_info->length].hash_key.advance.y = pen.y; - text_info->glyphs[text_info->length].hash_key.be = - render_priv->state.be; - text_info->glyphs[text_info->length].hash_key.blur = - render_priv->state.blur; - text_info->glyphs[text_info->length].hash_key.border_style = - render_priv->state.style->BorderStyle; - text_info->glyphs[text_info->length].hash_key.shadow_offset.x = - double_to_d6( - render_priv->state.shadow_x * render_priv->border_scale - - (int) (render_priv->state.shadow_x * - render_priv->border_scale)); - text_info->glyphs[text_info->length].hash_key.shadow_offset.y = - double_to_d6( - render_priv->state.shadow_y * render_priv->border_scale - - (int) (render_priv->state.shadow_y * - render_priv->border_scale)); - text_info->glyphs[text_info->length].hash_key.flags = - render_priv->state.flags; + // fill bitmap hash + fill_bitmap_hash(render_priv, &glyphs[text_info->length].hash_key, + drawing, pen, code); text_info->length++; @@ -1956,7 +1893,6 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, drawing = render_priv->state.drawing = ass_drawing_new(render_priv->fontconfig_priv, render_priv->state.font, - render_priv->settings.hinting, render_priv->ftlibrary); } } @@ -1967,6 +1903,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, free_render_context(render_priv); return 1; } + // depends on glyph x coordinates being monotonous, so it should be done before line wrap process_karaoke_effects(render_priv); @@ -1976,14 +1913,11 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, valign = alignment & 12; MarginL = - (event->MarginL) ? event->MarginL : render_priv->state.style-> - MarginL; + (event->MarginL) ? event->MarginL : render_priv->state.style->MarginL; MarginR = - (event->MarginR) ? event->MarginR : render_priv->state.style-> - MarginR; + (event->MarginR) ? event->MarginR : render_priv->state.style->MarginR; MarginV = - (event->MarginV) ? event->MarginV : render_priv->state.style-> - MarginV; + (event->MarginV) ? event->MarginV : render_priv->state.style->MarginV; if (render_priv->state.evt_type != EVENT_HSCROLL) { double max_text_width; @@ -2001,11 +1935,11 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, last_break = -1; for (i = 1; i < text_info->length + 1; ++i) { // (text_info->length + 1) is the end of the last line if ((i == text_info->length) - || text_info->glyphs[i].linebreak) { + || glyphs[i].linebreak) { double width, shift = 0; GlyphInfo *first_glyph = - text_info->glyphs + last_break + 1; - GlyphInfo *last_glyph = text_info->glyphs + i - 1; + glyphs + last_break + 1; + GlyphInfo *last_glyph = glyphs + i - 1; while (first_glyph < last_glyph && first_glyph->skip) first_glyph++; @@ -2027,7 +1961,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, shift = (max_text_width - width) / 2.0; } for (j = last_break + 1; j < i; ++j) { - text_info->glyphs[j].pos.x += double_to_d6(shift); + glyphs[j].pos.x += double_to_d6(shift); } last_break = i - 1; } @@ -2057,6 +1991,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, render_priv->state.scroll_shift) - (bbox.xMax - bbox.xMin); } + // y coordinate for everything except positioned events if (render_priv->state.evt_type == EVENT_NORMAL || render_priv->state.evt_type == EVENT_HSCROLL) { @@ -2072,7 +2007,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, double scr_y; if (valign != VALIGN_SUB) ass_msg(render_priv->library, MSGL_V, - "Invalid valign, supposing 0 (subtitle)"); + "Invalid valign, assuming 0 (subtitle)"); scr_y = y2scr_sub(render_priv, render_priv->track->PlayResY - MarginV); @@ -2093,6 +2028,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, render_priv->state.clip_y1 - render_priv->state.scroll_shift); } + // positioned events are totally different if (render_priv->state.evt_type == EVENT_POSITIONED) { double base_x = 0; @@ -2105,14 +2041,15 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, device_y = y2scr_pos(render_priv, render_priv->state.pos_y) - base_y; } + // fix clip coordinates (they depend on alignment) if (render_priv->state.evt_type == EVENT_NORMAL || render_priv->state.evt_type == EVENT_HSCROLL || render_priv->state.evt_type == EVENT_VSCROLL) { render_priv->state.clip_x0 = - x2scr(render_priv, render_priv->state.clip_x0); + x2scr_scaled(render_priv, render_priv->state.clip_x0); render_priv->state.clip_x1 = - x2scr(render_priv, render_priv->state.clip_x1); + x2scr_scaled(render_priv, render_priv->state.clip_x1); if (valign == VALIGN_TOP) { render_priv->state.clip_y0 = y2scr_top(render_priv, render_priv->state.clip_y0); @@ -2131,14 +2068,15 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, } } else if (render_priv->state.evt_type == EVENT_POSITIONED) { render_priv->state.clip_x0 = - x2scr_pos(render_priv, render_priv->state.clip_x0); + x2scr_pos_scaled(render_priv, render_priv->state.clip_x0); render_priv->state.clip_x1 = - x2scr_pos(render_priv, render_priv->state.clip_x1); + x2scr_pos_scaled(render_priv, render_priv->state.clip_x1); render_priv->state.clip_y0 = y2scr_pos(render_priv, render_priv->state.clip_y0); render_priv->state.clip_y1 = y2scr_pos(render_priv, render_priv->state.clip_y1); } + // calculate rotation parameters { DVector center; @@ -2154,7 +2092,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, } for (i = 0; i < text_info->length; ++i) { - GlyphInfo *info = text_info->glyphs + i; + GlyphInfo *info = glyphs + i; if (info->hash_key.frx || info->hash_key.fry || info->hash_key.frz || info->hash_key.fax @@ -2170,22 +2108,26 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, } // convert glyphs to bitmaps + device_x *= render_priv->font_scale_x; for (i = 0; i < text_info->length; ++i) { - GlyphInfo *g = text_info->glyphs + i; + GlyphInfo *g = glyphs + i; + g->pos.x *= render_priv->font_scale_x; g->hash_key.advance.x = double_to_d6(device_x - (int) device_x + d6_to_double(g->pos.x & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY; g->hash_key.advance.y = double_to_d6(device_y - (int) device_y + d6_to_double(g->pos.y & SUBPIXEL_MASK)) & ~SUBPIXEL_ACCURACY; - get_bitmap_glyph(render_priv, text_info->glyphs + i); + get_bitmap_glyph(render_priv, glyphs + i); } memset(event_images, 0, sizeof(*event_images)); event_images->top = device_y - text_info->lines[0].asc; event_images->height = text_info->height; - event_images->left = device_x + bbox.xMin + 0.5; - event_images->width = bbox.xMax - bbox.xMin + 0.5; + event_images->left = + (device_x + bbox.xMin * render_priv->font_scale_x) + 0.5; + event_images->width = + (bbox.xMax - bbox.xMin) * render_priv->font_scale_x + 0.5; event_images->detect_collisions = render_priv->state.detect_collisions; event_images->shift_direction = (valign == VALIGN_TOP) ? 1 : -1; event_images->event = event; @@ -2200,7 +2142,7 @@ ass_render_event(ASS_Renderer *render_priv, ASS_Event *event, * \brief deallocate image list * \param img list pointer */ -static void ass_free_images(ASS_Image *img) +void ass_free_images(ASS_Image *img) { while (img) { ASS_Image *next = img->next; @@ -2209,103 +2151,32 @@ static void ass_free_images(ASS_Image *img) } } -static void ass_reconfigure(ASS_Renderer *priv) +/** + * \brief Check cache limits and reset cache if they are exceeded + */ +static void check_cache_limits(ASS_Renderer *priv, CacheStore *cache) { - priv->render_id++; - priv->cache.glyph_cache = - ass_glyph_cache_reset(priv->cache.glyph_cache); - priv->cache.bitmap_cache = - ass_bitmap_cache_reset(priv->cache.bitmap_cache); - priv->cache.composite_cache = - ass_composite_cache_reset(priv->cache.composite_cache); - ass_free_images(priv->prev_images_root); - priv->prev_images_root = 0; -} - -void ass_set_frame_size(ASS_Renderer *priv, int w, int h) -{ - if (priv->settings.frame_width != w || priv->settings.frame_height != h) { - priv->settings.frame_width = w; - priv->settings.frame_height = h; - if (priv->settings.aspect == 0.) { - priv->settings.aspect = ((double) w) / h; - priv->settings.storage_aspect = ((double) w) / h; - } - ass_reconfigure(priv); + if (cache->bitmap_cache->cache_size > cache->bitmap_max_size) { + ass_msg(priv->library, MSGL_V, + "Hitting hard bitmap cache limit (was: %ld bytes), " + "resetting.", (long) cache->bitmap_cache->cache_size); + cache->bitmap_cache = ass_bitmap_cache_reset(cache->bitmap_cache); + cache->composite_cache = ass_composite_cache_reset( + cache->composite_cache); + ass_free_images(priv->prev_images_root); + priv->prev_images_root = 0; } -} -void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r) -{ - if (priv->settings.left_margin != l || - priv->settings.right_margin != r || - priv->settings.top_margin != t - || priv->settings.bottom_margin != b) { - priv->settings.left_margin = l; - priv->settings.right_margin = r; - priv->settings.top_margin = t; - priv->settings.bottom_margin = b; - ass_reconfigure(priv); + if (cache->glyph_cache->count > cache->glyph_max + || cache->glyph_cache->cache_size > cache->bitmap_max_size) { + ass_msg(priv->library, MSGL_V, + "Hitting hard glyph cache limit (was: %d glyphs, %ld bytes), " + "resetting.", + cache->glyph_cache->count, (long) cache->glyph_cache->cache_size); + cache->glyph_cache = ass_glyph_cache_reset(cache->glyph_cache); } } -void ass_set_use_margins(ASS_Renderer *priv, int use) -{ - priv->settings.use_margins = use; -} - -void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar) -{ - if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) { - priv->settings.aspect = dar; - priv->settings.storage_aspect = sar; - ass_reconfigure(priv); - } -} - -void ass_set_font_scale(ASS_Renderer *priv, double font_scale) -{ - if (priv->settings.font_size_coeff != font_scale) { - priv->settings.font_size_coeff = font_scale; - ass_reconfigure(priv); - } -} - -void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht) -{ - if (priv->settings.hinting != ht) { - priv->settings.hinting = ht; - ass_reconfigure(priv); - } -} - -void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing) -{ - priv->settings.line_spacing = line_spacing; -} - -void ass_set_fonts(ASS_Renderer *priv, const char *default_font, - const char *default_family, int fc, const char *config, - int update) -{ - free(priv->settings.default_font); - free(priv->settings.default_family); - priv->settings.default_font = default_font ? strdup(default_font) : 0; - priv->settings.default_family = - default_family ? strdup(default_family) : 0; - - if (priv->fontconfig_priv) - fontconfig_done(priv->fontconfig_priv); - priv->fontconfig_priv = - fontconfig_init(priv->library, priv->ftlibrary, default_family, - default_font, fc, config, update); -} - -int ass_fonts_update(ASS_Renderer *render_priv) -{ - return fontconfig_update(render_priv->fontconfig_priv); -} - /** * \brief Start a new frame */ @@ -2314,7 +2185,6 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, long long now) { ASS_Settings *settings_priv = &render_priv->settings; - CacheStore *cache = &render_priv->cache; if (!render_priv->settings.frame_width && !render_priv->settings.frame_height) @@ -2323,27 +2193,14 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, if (render_priv->library != track->library) return 1; + if (!render_priv->fontconfig_priv) + return 1; + free_list_clear(render_priv); if (track->n_events == 0) return 1; // nothing to do - render_priv->width = settings_priv->frame_width; - render_priv->height = settings_priv->frame_height; - render_priv->orig_width = - settings_priv->frame_width - settings_priv->left_margin - - settings_priv->right_margin; - render_priv->orig_height = - settings_priv->frame_height - settings_priv->top_margin - - settings_priv->bottom_margin; - render_priv->orig_width_nocrop = - settings_priv->frame_width - FFMAX(settings_priv->left_margin, - 0) - - FFMAX(settings_priv->right_margin, 0); - render_priv->orig_height_nocrop = - settings_priv->frame_height - FFMAX(settings_priv->top_margin, - 0) - - FFMAX(settings_priv->bottom_margin, 0); render_priv->track = track; render_priv->time = now; @@ -2365,23 +2222,7 @@ ass_start_frame(ASS_Renderer *render_priv, ASS_Track *track, render_priv->prev_images_root = render_priv->images_root; render_priv->images_root = 0; - if (cache->bitmap_cache->cache_size > cache->bitmap_max_size) { - ass_msg(render_priv->library, MSGL_V, - "Hitting hard bitmap cache limit (was: %ld bytes), " - "resetting.", (long) cache->bitmap_cache->cache_size); - cache->bitmap_cache = ass_bitmap_cache_reset(cache->bitmap_cache); - cache->composite_cache = ass_composite_cache_reset( - cache->composite_cache); - ass_free_images(render_priv->prev_images_root); - render_priv->prev_images_root = 0; - } - - if (cache->glyph_cache->count > cache->glyph_max) { - ass_msg(render_priv->library, MSGL_V, - "Hitting hard glyph cache limit (was: %ld glyphs), resetting.", - (long) cache->glyph_cache->count); - cache->glyph_cache = ass_glyph_cache_reset(cache->glyph_cache); - } + check_cache_limits(render_priv, &render_priv->cache); return 0; } @@ -2505,7 +2346,7 @@ fix_collisions(ASS_Renderer *render_priv, EventImages *imgs, int cnt) s.hb = priv->left + priv->width; if (priv->height != imgs[i].height) { // no, it's not ass_msg(render_priv->library, MSGL_WARN, - "Warning! Event height has changed"); + "Event height has changed"); priv->top = 0; priv->height = 0; priv->left = 0; diff --git a/aegisub/libass/ass_render.h b/aegisub/libass/ass_render.h index 6d9db23fb..89bffb012 100644 --- a/aegisub/libass/ass_render.h +++ b/aegisub/libass/ass_render.h @@ -4,19 +4,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_RENDER_H @@ -38,6 +36,9 @@ #include "ass_library.h" #include "ass_drawing.h" +#define GLYPH_CACHE_MAX 1000 +#define BITMAP_CACHE_MAX_SIZE 30 * 1048576 + typedef struct { double xMin; double xMax; @@ -258,5 +259,6 @@ typedef struct { } Segment; void reset_render_context(ASS_Renderer *render_priv); +void ass_free_images(ASS_Image *img); #endif /* LIBASS_RENDER_H */ diff --git a/aegisub/libass/ass_render_api.c b/aegisub/libass/ass_render_api.c new file mode 100644 index 000000000..65cfa58d0 --- /dev/null +++ b/aegisub/libass/ass_render_api.c @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2006 Evgeniy Stepanov + * Copyright (C) 2010 Grigori Goronzy + * + * This file is part of libass. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "config.h" +#include "ass_render.h" + +static void ass_reconfigure(ASS_Renderer *priv) +{ + ASS_Settings *settings = &priv->settings; + + priv->render_id++; + priv->cache.glyph_cache = + ass_glyph_cache_reset(priv->cache.glyph_cache); + priv->cache.bitmap_cache = + ass_bitmap_cache_reset(priv->cache.bitmap_cache); + priv->cache.composite_cache = + ass_composite_cache_reset(priv->cache.composite_cache); + ass_free_images(priv->prev_images_root); + priv->prev_images_root = 0; + + priv->width = settings->frame_width; + priv->height = settings->frame_height; + priv->orig_width = settings->frame_width - settings->left_margin - + settings->right_margin; + priv->orig_height = settings->frame_height - settings->top_margin - + settings->bottom_margin; + priv->orig_width_nocrop = + settings->frame_width - FFMAX(settings->left_margin, 0) - + FFMAX(settings->right_margin, 0); + priv->orig_height_nocrop = + settings->frame_height - FFMAX(settings->top_margin, 0) - + FFMAX(settings->bottom_margin, 0); +} + +void ass_set_frame_size(ASS_Renderer *priv, int w, int h) +{ + if (priv->settings.frame_width != w || priv->settings.frame_height != h) { + priv->settings.frame_width = w; + priv->settings.frame_height = h; + if (priv->settings.aspect == 0.) { + priv->settings.aspect = ((double) w) / h; + priv->settings.storage_aspect = ((double) w) / h; + } + ass_reconfigure(priv); + } +} + +void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r) +{ + if (priv->settings.left_margin != l || priv->settings.right_margin != r || + priv->settings.top_margin != t || priv->settings.bottom_margin != b) { + priv->settings.left_margin = l; + priv->settings.right_margin = r; + priv->settings.top_margin = t; + priv->settings.bottom_margin = b; + ass_reconfigure(priv); + } +} + +void ass_set_use_margins(ASS_Renderer *priv, int use) +{ + priv->settings.use_margins = use; +} + +void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar) +{ + if (priv->settings.aspect != dar || priv->settings.storage_aspect != sar) { + priv->settings.aspect = dar; + priv->settings.storage_aspect = sar; + ass_reconfigure(priv); + } +} + +void ass_set_font_scale(ASS_Renderer *priv, double font_scale) +{ + if (priv->settings.font_size_coeff != font_scale) { + priv->settings.font_size_coeff = font_scale; + ass_reconfigure(priv); + } +} + +void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht) +{ + if (priv->settings.hinting != ht) { + priv->settings.hinting = ht; + ass_reconfigure(priv); + } +} + +void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing) +{ + priv->settings.line_spacing = line_spacing; +} + +void ass_set_fonts(ASS_Renderer *priv, const char *default_font, + const char *default_family, int fc, const char *config, + int update) +{ + free(priv->settings.default_font); + free(priv->settings.default_family); + priv->settings.default_font = default_font ? strdup(default_font) : 0; + priv->settings.default_family = + default_family ? strdup(default_family) : 0; + + if (priv->fontconfig_priv) + fontconfig_done(priv->fontconfig_priv); + priv->fontconfig_priv = + fontconfig_init(priv->library, priv->ftlibrary, default_family, + default_font, fc, config, update); +} + +int ass_fonts_update(ASS_Renderer *render_priv) +{ + return fontconfig_update(render_priv->fontconfig_priv); +} + +void ass_set_cache_limits(ASS_Renderer *render_priv, int glyph_max, + int bitmap_max) +{ + render_priv->cache.glyph_max = glyph_max ? glyph_max : GLYPH_CACHE_MAX; + render_priv->cache.bitmap_max_size = bitmap_max ? 1048576 * bitmap_max : + BITMAP_CACHE_MAX_SIZE; +} diff --git a/aegisub/libass/ass_strtod.c b/aegisub/libass/ass_strtod.c index 7b73630bc..f55b37ae1 100644 --- a/aegisub/libass/ass_strtod.c +++ b/aegisub/libass/ass_strtod.c @@ -16,12 +16,14 @@ #include #include +const static int maxExponent = 511; /* Largest possible base 10 exponent. Any * exponent larger than this will already * produce underflow or overflow, so there's * no need to worry about additional digits. */ +const static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ 10., /* is 10^2^i. Used to convert decimal */ 100., /* exponents into floating-point numbers. */ @@ -224,7 +226,7 @@ ass_strtod(string, endPtr) errno = ERANGE; } dblExp = 1.0; - for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + for (d = (double *) powersOf10; exp != 0; exp >>= 1, d += 1) { if (exp & 01) { dblExp *= *d; } diff --git a/aegisub/libass/ass_types.h b/aegisub/libass/ass_types.h index 63bc36c40..6a6f1ae86 100644 --- a/aegisub/libass/ass_types.h +++ b/aegisub/libass/ass_types.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_TYPES_H diff --git a/aegisub/libass/ass_utils.c b/aegisub/libass/ass_utils.c index 59fdbdfb9..4c9d4bcc6 100644 --- a/aegisub/libass/ass_utils.c +++ b/aegisub/libass/ass_utils.c @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "config.h" @@ -25,6 +23,7 @@ #include #include #include FT_GLYPH_H +#include #include "ass_library.h" #include "ass.h" diff --git a/aegisub/libass/ass_utils.h b/aegisub/libass/ass_utils.h index ad8574c1d..327bb79cf 100644 --- a/aegisub/libass/ass_utils.h +++ b/aegisub/libass/ass_utils.h @@ -3,19 +3,17 @@ * * This file is part of libass. * - * libass is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * libass 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with libass; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef LIBASS_UTILS_H