Remove in-repository libass, depend on system library instead. Require minimum version 0.9.11 as that is what Ubuntu 11.04 ships.

Originally committed to SVN as r5548.
This commit is contained in:
Niels Martin Hansen 2011-08-20 18:45:39 +00:00
parent c59c4a03ba
commit 610ae5c4ad
31 changed files with 8 additions and 9786 deletions

View File

@ -5,13 +5,8 @@ if HAVE_UNIVCHARDET
univchardet = universalchardet
endif
if WITH_LIBASS
libass = libass
endif
SUBDIRS = \
$(univchardet) \
$(libass) \
src \
automation \
po \

View File

@ -34,6 +34,7 @@ m4_define([pkgconfig_required_version], [0.20])
m4_define([ruby_required_version], [1.8])
m4_define([wx_required_version], [2.8.1])
m4_define([ffms_required_version], [2.13.1])
m4_define([libass_required_version], [0.9.11])
#######
@ -650,17 +651,10 @@ AC_SUBST(FFMS_CFLAGS)
# Subtitle Provider
###################
AC_ARG_ENABLE(libass, [ --disable-libass disable libass support (default=enabled)],libass_disabled="(disabled)")
AC_ARG_ENABLE(libass, [ --without-libass disable libass support (default=enabled)],libass_disabled="(disabled)")
if test "$enable_libass" != "no"; then
if test "$agi_cv_with_iconv" = "yes"; then
LIBASS_LIBS="-L../libass -lass_aegisub"
LIBASS_CFLAGS="-I../libass"
with_libass="yes"
else
AC_MSG_WARN([libiconv is required for libass support.])
with_libass="no"
fi
PKG_CHECK_MODULES(LIBASS, libass >= libass_required_version, [with_libass="yes"], [with_libass="no"])
fi
if test "$with_libass" = "yes" || test "$enable_libass" != "no"; then
@ -1283,7 +1277,6 @@ src/libresrc/Makefile
src/libauto3/Makefile
src/libosxutil/Makefile
universalchardet/Makefile
libass/Makefile
automation/Makefile
po/Makefile.in
desktop/Makefile
@ -1364,7 +1357,6 @@ A/V Providers
Subtitle Providers:
libASS $with_libass $libass_disabled $libass_default
(requires iconv and fontconfig)
Misc Packages
Hunspell: $with_hunspell $with_hunspell_version $hunspell_disabled

View File

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
<signature of Ty Coon>, 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.

View File

@ -1,23 +0,0 @@
noinst_LIBRARIES = libass_aegisub.a
AM_CPPFLAGS = @CXXFLAGS_OSX@ @FREETYPE_CFLAGS@ -DCONFIG_ICONV -DCONFIG_FONTCONFIG @FONTCONFIG_CFLAGS@ @ICONV_CFLAGS@
if BUILD_DARWIN
AM_CPPFLAGS += -DBUILD_DARWIN
endif
libass_aegisub_a_SOURCES = \
ass.c \
ass_bitmap.c \
ass_cache.c \
ass_drawing.c \
ass_font.c \
ass_fontconfig.c \
ass_library.c \
ass_parse.c \
ass_render.c \
ass_strtod.c \
ass_utils.c
libass_aegisub_a_SOURCES += \
*.h

File diff suppressed because it is too large Load Diff

View File

@ -1,374 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_ASS_H
#define LIBASS_ASS_H
#include <stdio.h>
#include <stdarg.h>
#include "ass_types.h"
#define LIBASS_VERSION 0x00908000
/*
* A linked list of images produced by an ass renderer.
*
* These images have to be rendered in-order for the correct screen
* composition. The libass renderer clips these bitmaps to the frame size.
* w/h can be zero, in this case the bitmap should not be rendered at all.
* The last bitmap row is not guaranteed to be padded up to stride size,
* e.g. in the worst case a bitmap has the size stride * (h - 1) + w.
*/
typedef struct ass_image {
int w, h; // Bitmap width/height
int stride; // Bitmap stride
unsigned char *bitmap; // 1bpp stride*h alpha buffer
// Note: the last row may not be padded to
// bitmap stride!
uint32_t color; // Bitmap color and alpha, RGBA
int dst_x, dst_y; // Bitmap placement inside the video frame
struct ass_image *next; // Next image, or NULL
} ASS_Image;
/*
* Hinting type. (see ass_set_hinting below)
*
* FreeType's native hinter is still buggy sometimes and it is recommended
* to use the light autohinter, ASS_HINTING_LIGHT, instead. For best
* compatibility with problematic fonts, disable hinting.
*/
typedef enum {
ASS_HINTING_NONE = 0,
ASS_HINTING_LIGHT,
ASS_HINTING_NORMAL,
ASS_HINTING_NATIVE
} ASS_Hinting;
/**
* \brief Initialize the library.
* \return library handle or NULL if failed
*/
ASS_Library *ass_library_init(void);
/**
* \brief Finalize the library
* \param priv library handle
*/
void ass_library_done(ASS_Library *priv);
/**
* \brief Set private font directory.
* It is used for saving embedded fonts and also in font lookup.
*
* \param priv library handle
* \param fonts_dir private directory for font extraction
*/
void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir);
/**
* \brief Whether fonts should be extracted from track data.
* \param priv library handle
* \param extract whether to extract fonts
*/
void ass_set_extract_fonts(ASS_Library *priv, int extract);
/**
* \brief Register style overrides with a library instance.
* The overrides should have the form [Style.]Param=Value, e.g.
* SomeStyle.Font=Arial
* ScaledBorderAndShadow=yes
*
* \param priv library handle
* \param list NULL-terminated list of strings
*/
void ass_set_style_overrides(ASS_Library *priv, char **list);
/**
* \brief Explicitly process style overrides for a track.
* \param track track handle
*/
void ass_process_force_style(ASS_Track *track);
/**
* \brief Register a callback for debug/info messages.
* If a callback is registered, it is called for every message emitted by
* libass. The callback receives a format string and a list of arguments,
* to be used for the printf family of functions. Additionally, a log level
* from 0 (FATAL errors) to 7 (verbose DEBUG) is passed. Usually, level 5
* should be used by applications.
* If no callback is set, all messages level < 5 are printed to stderr,
* prefixed with [ass].
*
* \param priv library handle
* \param msg_cb pointer to callback function
* \param data additional data, will be passed to callback
*/
void ass_set_message_cb(ASS_Library *priv, void (*msg_cb)
(int level, const char *fmt, va_list args, void *data),
void *data);
/**
* \brief Initialize the renderer.
* \param priv library handle
* \return renderer handle or NULL if failed
*/
ASS_Renderer *ass_renderer_init(ASS_Library *);
/**
* \brief Finalize the renderer.
* \param priv renderer handle
*/
void ass_renderer_done(ASS_Renderer *priv);
/**
* \brief Set the frame size in pixels, including margins.
* \param priv renderer handle
* \param w width
* \param h height
*/
void ass_set_frame_size(ASS_Renderer *priv, int w, int h);
/**
* \brief Set frame margins. These values may be negative if pan-and-scan
* is used.
* \param priv renderer handle
* \param t top margin
* \param b bottom margin
* \param l left margin
* \param r right margin
*/
void ass_set_margins(ASS_Renderer *priv, int t, int b, int l, int r);
/**
* \brief Whether margins should be used for placing regular events.
* \param priv renderer handle
* \param use whether to use the margins
*/
void ass_set_use_margins(ASS_Renderer *priv, int use);
/**
* \brief Set aspect ratio parameters.
* \param priv renderer handle
* \param dar display aspect ratio (DAR), prescaled for output PAR
* \param sar storage aspect ratio (SAR)
*/
void ass_set_aspect_ratio(ASS_Renderer *priv, double dar, double sar);
/**
* \brief Set a fixed font scaling factor.
* \param priv renderer handle
* \param font_scale scaling factor, default is 1.0
*/
void ass_set_font_scale(ASS_Renderer *priv, double font_scale);
/**
* \brief Set font hinting method.
* \param priv renderer handle
* \param ht hinting method
*/
void ass_set_hinting(ASS_Renderer *priv, ASS_Hinting ht);
/**
* \brief Set line spacing. Will not be scaled with frame size.
* \param priv renderer handle
* \param line_spacing line spacing in pixels
*/
void ass_set_line_spacing(ASS_Renderer *priv, double line_spacing);
/**
* \brief Set font lookup defaults.
* \param default_font path to default font to use. Must be supplied if
* fontconfig is disabled or unavailable.
* \param default_family fallback font family for fontconfig, or NULL
* \param fc whether to use fontconfig
* \param config path to fontconfig configuration file, or NULL. Only relevant
* if fontconfig is used.
* \param update whether fontconfig cache should be built/updated now. Only
* relevant if fontconfig is used.
*/
void ass_set_fonts(ASS_Renderer *priv, const char *default_font,
const char *default_family, int fc, const char *config,
int update);
/**
* \brief Update/build font cache. This needs to be called if it was
* disabled when ass_set_fonts was set.
*
* \param priv renderer handle
* \return success
*/
int ass_fonts_update(ASS_Renderer *priv);
/**
* \brief Set hard cache limits. Do not set, or set to zero, for reasonable
* defaults.
*
* \param priv renderer handle
* \param glyph_max maximum number of cached glyphs
* \param bitmap_max_size maximum bitmap cache size (in MB)
*/
void ass_set_cache_limits(ASS_Renderer *priv, int glyph_max,
int bitmap_max_size);
/**
* \brief Render a frame, producing a list of ASS_Image.
* \param priv renderer handle
* \param track subtitle track
* \param now video timestamp in milliseconds
* \param detect_change will be set to 1 if a change occured compared
* to the last invocation
*/
ASS_Image *ass_render_frame(ASS_Renderer *priv, ASS_Track *track,
long long now, int *detect_change);
/*
* The following functions operate on track objects and do not need
* an ass_renderer
*/
/**
* \brief Allocate a new empty track object.
* \param library handle
* \return pointer to empty track
*/
ASS_Track *ass_new_track(ASS_Library *);
/**
* \brief Deallocate track and all its child objects (styles and events).
* \param track track to deallocate
*/
void ass_free_track(ASS_Track *track);
/**
* \brief Allocate new style.
* \param track track
* \return newly allocated style id
*/
int ass_alloc_style(ASS_Track *track);
/**
* \brief Allocate new event.
* \param track track
* \return newly allocated event id
*/
int ass_alloc_event(ASS_Track *track);
/**
* \brief Delete a style.
* \param track track
* \param sid style id
* Deallocates style data. Does not modify track->n_styles.
*/
void ass_free_style(ASS_Track *track, int sid);
/**
* \brief Delete an event.
* \param track track
* \param eid event id
* Deallocates event data. Does not modify track->n_events.
*/
void ass_free_event(ASS_Track *track, int eid);
/**
* \brief Parse a chunk of subtitle stream data.
* \param track track
* \param data string to parse
* \param size length of data
*/
void ass_process_data(ASS_Track *track, char *data, int size);
/**
* \brief Parse Codec Private section of subtitle stream.
* \param track target track
* \param data string to parse
* \param size length of data
*/
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).
* \param track track
* \param data string to parse
* \param size length of data
* \param timecode starting time of the event (milliseconds)
* \param duration duration of the event (milliseconds)
*/
void ass_process_chunk(ASS_Track *track, char *data, int size,
long long timecode, long long duration);
/**
* \brief Read subtitles from file.
* \param library library handle
* \param fname file name
* \param codepage encoding (iconv format)
* \return newly allocated track
*/
ASS_Track *ass_read_file(ASS_Library *library, char *fname,
char *codepage);
/**
* \brief Read subtitles from memory.
* \param library library handle
* \param buf pointer to subtitles text
* \param bufsize size of buffer
* \param codepage encoding (iconv format)
* \return newly allocated track
*/
ASS_Track *ass_read_memory(ASS_Library *library, char *buf,
size_t bufsize, char *codepage);
/**
* \brief Read styles from file into already initialized track.
* \param fname file name
* \param codepage encoding (iconv format)
* \return 0 on success
*/
int ass_read_styles(ASS_Track *track, char *fname, char *codepage);
/**
* \brief Add a memory font.
* \param library library handle
* \param name attachment name
* \param data binary font data
* \param data_size data size
*/
void ass_add_font(ASS_Library *library, char *name, char *data,
int data_size);
/**
* \brief Remove all fonts stored in an ass_library object.
* \param library library handle
*/
void ass_clear_fonts(ASS_Library *library);
/**
* \brief Calculates timeshift from now to the start of some other subtitle
* event, depending on movement parameter.
* \param track subtitle track
* \param now current time in milliseconds
* \param movement how many events to skip from the one currently displayed
* +2 means "the one after the next", -1 means "previous"
* \return timeshift in milliseconds
*/
long long ass_step_sub(ASS_Track *track, long long now, int movement);
#endif /* LIBASS_ASS_H */

View File

@ -1,537 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <ft2build.h>
#include FT_GLYPH_H
#include "ass_utils.h"
#include "ass_bitmap.h"
struct ass_synth_priv {
int tmp_w, tmp_h;
unsigned short *tmp;
int g_r;
int g_w;
unsigned *g;
unsigned *gt2;
double radius;
};
static const unsigned int maxcolor = 255;
static const unsigned base = 256;
static int generate_tables(ASS_SynthPriv *priv, double radius)
{
double A = log(1.0 / base) / (radius * radius * 2);
int mx, i;
double volume_diff, volume_factor = 0;
unsigned volume;
if (priv->radius == radius)
return 0;
else
priv->radius = radius;
priv->g_r = ceil(radius);
priv->g_w = 2 * priv->g_r + 1;
if (priv->g_r) {
priv->g = realloc(priv->g, priv->g_w * sizeof(unsigned));
priv->gt2 = realloc(priv->gt2, 256 * priv->g_w * sizeof(unsigned));
if (priv->g == NULL || priv->gt2 == NULL) {
return -1;
}
}
if (priv->g_r) {
// gaussian curve with volume = 256
for (volume_diff = 10000000; volume_diff > 0.0000001;
volume_diff *= 0.5) {
volume_factor += volume_diff;
volume = 0;
for (i = 0; i < priv->g_w; ++i) {
priv->g[i] =
(unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) *
volume_factor + .5);
volume += priv->g[i];
}
if (volume > 256)
volume_factor -= volume_diff;
}
volume = 0;
for (i = 0; i < priv->g_w; ++i) {
priv->g[i] =
(unsigned) (exp(A * (i - priv->g_r) * (i - priv->g_r)) *
volume_factor + .5);
volume += priv->g[i];
}
// gauss table:
for (mx = 0; mx < priv->g_w; mx++) {
for (i = 0; i < 256; i++) {
priv->gt2[mx + i * priv->g_w] = i * priv->g[mx];
}
}
}
return 0;
}
static void resize_tmp(ASS_SynthPriv *priv, int w, int h)
{
if (priv->tmp_w >= w && priv->tmp_h >= h)
return;
if (priv->tmp_w == 0)
priv->tmp_w = 64;
if (priv->tmp_h == 0)
priv->tmp_h = 64;
while (priv->tmp_w < w)
priv->tmp_w *= 2;
while (priv->tmp_h < h)
priv->tmp_h *= 2;
if (priv->tmp)
free(priv->tmp);
priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
}
ASS_SynthPriv *ass_synth_init(double radius)
{
ASS_SynthPriv *priv = calloc(1, sizeof(ASS_SynthPriv));
generate_tables(priv, radius);
return priv;
}
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);
}
static Bitmap *alloc_bitmap(int w, int h)
{
Bitmap *bm;
bm = calloc(1, sizeof(Bitmap));
bm->buffer = malloc(w * h);
bm->w = w;
bm->h = h;
bm->left = bm->top = 0;
return bm;
}
void ass_free_bitmap(Bitmap *bm)
{
if (bm) {
if (bm->buffer)
free(bm->buffer);
free(bm);
}
}
static Bitmap *copy_bitmap(const Bitmap *src)
{
Bitmap *dst = alloc_bitmap(src->w, src->h);
dst->left = src->left;
dst->top = src->top;
memcpy(dst->buffer, src->buffer, src->w * src->h);
return dst;
}
static int check_glyph_area(ASS_Library *library, FT_Glyph glyph)
{
FT_BBox bbox;
long long dx, dy;
FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);
dx = bbox.xMax - bbox.xMin;
dy = bbox.yMax - bbox.yMin;
if (dx * dy > 8000000) {
ass_msg(library, MSGL_WARN, "Glyph bounding box too large: %dx%dpx",
(int) dx, (int) dy);
return 1;
} else
return 0;
}
static Bitmap *glyph_to_bitmap_internal(ASS_Library *library,
FT_Glyph glyph, int bord)
{
FT_BitmapGlyph bg;
FT_Bitmap *bit;
Bitmap *bm;
int w, h;
unsigned char *src;
unsigned char *dst;
int i;
int error;
if (check_glyph_area(library, glyph))
return 0;
error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0);
if (error) {
ass_msg(library, MSGL_WARN, "FT_Glyph_To_Bitmap error %d",
error);
return 0;
}
bg = (FT_BitmapGlyph) glyph;
bit = &(bg->bitmap);
if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) {
ass_msg(library, MSGL_WARN, "Unsupported pixel mode: %d",
(int) (bit->pixel_mode));
FT_Done_Glyph(glyph);
return 0;
}
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;
src = bit->buffer;
dst = bm->buffer + bord + bm->w * bord;
for (i = 0; i < h; ++i) {
memcpy(dst, src, w);
src += bit->pitch;
dst += bm->w;
}
FT_Done_Glyph(glyph);
return bm;
}
/**
* \brief fix outline bitmap
*
* The glyph bitmap is subtracted from outline bitmap. This way looks much
* better in some cases.
*/
static void fix_outline(Bitmap *bm_g, Bitmap *bm_o)
{
int x, y;
const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left;
const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top;
const int r =
bm_o->left + bm_o->w <
bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w;
const int b =
bm_o->top + bm_o->h <
bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h;
unsigned char *g =
bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left);
unsigned char *o =
bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left);
for (y = 0; y < b - t; ++y) {
for (x = 0; x < r - l; ++x) {
unsigned char c_g, c_o;
c_g = g[x];
c_o = o[x];
o[x] = (c_o > c_g) ? c_o - (c_g / 2) : 0;
}
g += bm_g->w;
o += bm_o->w;
}
}
/**
* \brief Shift a bitmap by the fraction of a pixel in x and y direction
* expressed in 26.6 fixed point
*/
static void shift_bitmap(unsigned char *buf, int w, int h, int shift_x,
int shift_y)
{
int x, y, b;
// Shift in x direction
if (shift_x > 0) {
for (y = 0; y < h; y++) {
for (x = w - 1; x > 0; x--) {
b = (buf[x + y * w - 1] * shift_x) >> 6;
buf[x + y * w - 1] -= b;
buf[x + y * w] += b;
}
}
} else if (shift_x < 0) {
shift_x = -shift_x;
for (y = 0; y < h; y++) {
for (x = 0; x < w - 1; x++) {
b = (buf[x + y * w + 1] * shift_x) >> 6;
buf[x + y * w + 1] -= b;
buf[x + y * w] += b;
}
}
}
// Shift in y direction
if (shift_y > 0) {
for (x = 0; x < w; x++) {
for (y = h - 1; y > 0; y--) {
b = (buf[x + (y - 1) * w] * shift_y) >> 6;
buf[x + (y - 1) * w] -= b;
buf[x + y * w] += b;
}
}
} else if (shift_y < 0) {
shift_y = -shift_y;
for (x = 0; x < w; x++) {
for (y = 0; y < h - 1; y++) {
b = (buf[x + (y + 1) * w] * shift_y) >> 6;
buf[x + (y + 1) * w] -= b;
buf[x + y * w] += b;
}
}
}
}
/*
* Gaussian blur. An fast pure C implementation from MPlayer.
*/
static void ass_gauss_blur(unsigned char *buffer, unsigned short *tmp2,
int width, int height, int stride, int *m2,
int r, int mwidth)
{
int x, y;
unsigned char *s = buffer;
unsigned short *t = tmp2 + 1;
for (y = 0; y < height; y++) {
memset(t - 1, 0, (width + 1) * sizeof(short));
for (x = 0; x < r; x++) {
const int src = s[x];
if (src) {
register unsigned short *dstp = t + x - r;
int mx;
unsigned *m3 = (unsigned *) (m2 + src * mwidth);
for (mx = r - x; mx < mwidth; mx++) {
dstp[mx] += m3[mx];
}
}
}
for (; x < width - r; x++) {
const int src = s[x];
if (src) {
register unsigned short *dstp = t + x - r;
int mx;
unsigned *m3 = (unsigned *) (m2 + src * mwidth);
for (mx = 0; mx < mwidth; mx++) {
dstp[mx] += m3[mx];
}
}
}
for (; x < width; x++) {
const int src = s[x];
if (src) {
register unsigned short *dstp = t + x - r;
int mx;
const int x2 = r + width - x;
unsigned *m3 = (unsigned *) (m2 + src * mwidth);
for (mx = 0; mx < x2; mx++) {
dstp[mx] += m3[mx];
}
}
}
s += stride;
t += width + 1;
}
t = tmp2;
for (x = 0; x < width; x++) {
for (y = 0; y < r; y++) {
unsigned short *srcp = t + y * (width + 1) + 1;
int src = *srcp;
if (src) {
register unsigned short *dstp = srcp - 1 + width + 1;
const int src2 = (src + 128) >> 8;
unsigned *m3 = (unsigned *) (m2 + src2 * mwidth);
int mx;
*srcp = 128;
for (mx = r - 1; mx < mwidth; mx++) {
*dstp += m3[mx];
dstp += width + 1;
}
}
}
for (; y < height - r; y++) {
unsigned short *srcp = t + y * (width + 1) + 1;
int src = *srcp;
if (src) {
register unsigned short *dstp = srcp - 1 - r * (width + 1);
const int src2 = (src + 128) >> 8;
unsigned *m3 = (unsigned *) (m2 + src2 * mwidth);
int mx;
*srcp = 128;
for (mx = 0; mx < mwidth; mx++) {
*dstp += m3[mx];
dstp += width + 1;
}
}
}
for (; y < height; y++) {
unsigned short *srcp = t + y * (width + 1) + 1;
int src = *srcp;
if (src) {
const int y2 = r + height - y;
register unsigned short *dstp = srcp - 1 - r * (width + 1);
const int src2 = (src + 128) >> 8;
unsigned *m3 = (unsigned *) (m2 + src2 * mwidth);
int mx;
*srcp = 128;
for (mx = 0; mx < y2; mx++) {
*dstp += m3[mx];
dstp += width + 1;
}
}
}
t++;
}
t = tmp2;
s = buffer;
for (y = 0; y < height; y++) {
for (x = 0; x < width; x++) {
s[x] = t[x] >> 8;
}
s += stride;
t += width + 1;
}
}
/**
* \brief Blur with [[1,2,1]. [2,4,2], [1,2,1]] kernel
* This blur is the same as the one employed by vsfilter.
*/
static void be_blur(unsigned char *buf, int w, int h)
{
unsigned int x, y;
unsigned int old_sum, new_sum;
for (y = 0; y < h; y++) {
old_sum = 2 * buf[y * w];
for (x = 0; x < w - 1; x++) {
new_sum = buf[y * w + x] + buf[y * w + x + 1];
buf[y * w + x] = (old_sum + new_sum) >> 2;
old_sum = new_sum;
}
}
for (x = 0; x < w; x++) {
old_sum = 2 * buf[x];
for (y = 0; y < h - 1; y++) {
new_sum = buf[y * w + x] + buf[(y + 1) * w + x];
buf[y * w + x] = (old_sum + new_sum) >> 2;
old_sum = new_sum;
}
}
}
int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
FT_Glyph glyph, FT_Glyph outline_glyph,
Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
int be, double blur_radius, FT_Vector shadow_offset,
int border_style)
{
blur_radius *= 2;
int bbord = be > 0 ? sqrt(2 * be) : 0;
int gbord = blur_radius > 0.0 ? blur_radius + 1 : 0;
int bord = FFMAX(bbord, gbord);
if (bord == 0 && (shadow_offset.x || shadow_offset.y))
bord = 1;
assert(bm_g && bm_o && bm_s);
*bm_g = *bm_o = *bm_s = 0;
if (glyph)
*bm_g = glyph_to_bitmap_internal(library, glyph, bord);
if (!*bm_g)
return 1;
if (outline_glyph) {
*bm_o = glyph_to_bitmap_internal(library, outline_glyph, bord);
if (!*bm_o) {
return 1;
}
}
// Apply box blur (multiple passes, if requested)
while (be--) {
if (*bm_o)
be_blur((*bm_o)->buffer, (*bm_o)->w, (*bm_o)->h);
else
be_blur((*bm_g)->buffer, (*bm_g)->w, (*bm_g)->h);
}
// Apply gaussian blur
if (blur_radius > 0.0) {
if (*bm_o)
resize_tmp(priv_blur, (*bm_o)->w, (*bm_o)->h);
else
resize_tmp(priv_blur, (*bm_g)->w, (*bm_g)->h);
generate_tables(priv_blur, blur_radius);
if (*bm_o)
ass_gauss_blur((*bm_o)->buffer, priv_blur->tmp,
(*bm_o)->w, (*bm_o)->h, (*bm_o)->w,
(int *) priv_blur->gt2, priv_blur->g_r,
priv_blur->g_w);
else
ass_gauss_blur((*bm_g)->buffer, priv_blur->tmp,
(*bm_g)->w, (*bm_g)->h, (*bm_g)->w,
(int *) priv_blur->gt2, priv_blur->g_r,
priv_blur->g_w);
}
// Create shadow and fix outline as needed
if (*bm_o && border_style != 3) {
*bm_s = copy_bitmap(*bm_o);
fix_outline(*bm_g, *bm_o);
} else if (*bm_o) {
*bm_s = copy_bitmap(*bm_o);
} else
*bm_s = copy_bitmap(*bm_g);
assert(bm_s);
shift_bitmap((*bm_s)->buffer, (*bm_s)->w,(*bm_s)->h,
shadow_offset.x, shadow_offset.y);
return 0;
}

View File

@ -1,57 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_BITMAP_H
#define LIBASS_BITMAP_H
#include <ft2build.h>
#include FT_GLYPH_H
#include "ass.h"
typedef struct ass_synth_priv ASS_SynthPriv;
ASS_SynthPriv *ass_synth_init(double);
void ass_synth_done(ASS_SynthPriv *priv);
typedef struct {
int left, top;
int w, h; // width, height
unsigned char *buffer; // w x h buffer
} Bitmap;
/**
* \brief perform glyph rendering
* \param glyph original glyph
* \param outline_glyph "border" glyph, produced from original by FreeType's glyph stroker
* \param bm_g out: pointer to the bitmap of original glyph is returned here
* \param bm_o out: pointer to the bitmap of outline (border) glyph is returned here
* \param bm_g out: pointer to the bitmap of glyph shadow is returned here
* \param be 1 = produces blurred bitmaps, 0 = normal bitmaps
*/
int glyph_to_bitmap(ASS_Library *library, ASS_SynthPriv *priv_blur,
FT_Glyph glyph, FT_Glyph outline_glyph,
Bitmap **bm_g, Bitmap **bm_o, Bitmap **bm_s,
int be, double blur_radius, FT_Vector shadow_offset,
int border_style);
void ass_free_bitmap(Bitmap *bm);
#endif /* LIBASS_BITMAP_H */

View File

@ -1,380 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#include "config.h"
#include <inttypes.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <assert.h>
#include "ass_utils.h"
#include "ass.h"
#include "ass_fontconfig.h"
#include "ass_font.h"
#include "ass_bitmap.h"
#include "ass_cache.h"
static unsigned hashmap_hash(void *buf, size_t len)
{
return fnv_32a_buf(buf, len, FNV1_32A_INIT);
}
static int hashmap_key_compare(void *a, void *b, size_t size)
{
return memcmp(a, b, size) == 0;
}
static void hashmap_item_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
free(key);
free(value);
}
Hashmap *hashmap_init(ASS_Library *library, size_t key_size,
size_t value_size, int nbuckets,
HashmapItemDtor item_dtor,
HashmapKeyCompare key_compare,
HashmapHash hash)
{
Hashmap *map = calloc(1, sizeof(Hashmap));
map->library = library;
map->nbuckets = nbuckets;
map->key_size = key_size;
map->value_size = value_size;
map->root = calloc(nbuckets, sizeof(hashmap_item_p));
map->item_dtor = item_dtor ? item_dtor : hashmap_item_dtor;
map->key_compare = key_compare ? key_compare : hashmap_key_compare;
map->hash = hash ? hash : hashmap_hash;
return map;
}
void hashmap_done(Hashmap *map)
{
int i;
// print stats
if (map->count > 0 || map->hit_count + map->miss_count > 0)
ass_msg(map->library, MSGL_V,
"cache statistics: \n total accesses: %d\n hits: %d\n "
"misses: %d\n object count: %d",
map->hit_count + map->miss_count, map->hit_count,
map->miss_count, map->count);
for (i = 0; i < map->nbuckets; ++i) {
HashmapItem *item = map->root[i];
while (item) {
HashmapItem *next = item->next;
map->item_dtor(item->key, map->key_size, item->value,
map->value_size);
free(item);
item = next;
}
}
free(map->root);
free(map);
}
// does nothing if key already exists
void *hashmap_insert(Hashmap *map, void *key, void *value)
{
unsigned hash = map->hash(key, map->key_size);
HashmapItem **next = map->root + (hash % map->nbuckets);
while (*next) {
if (map->key_compare(key, (*next)->key, map->key_size))
return (*next)->value;
next = &((*next)->next);
assert(next);
}
(*next) = malloc(sizeof(HashmapItem));
(*next)->key = malloc(map->key_size);
(*next)->value = malloc(map->value_size);
memcpy((*next)->key, key, map->key_size);
memcpy((*next)->value, value, map->value_size);
(*next)->next = 0;
map->count++;
return (*next)->value;
}
void *hashmap_find(Hashmap *map, void *key)
{
unsigned hash = map->hash(key, map->key_size);
HashmapItem *item = map->root[hash % map->nbuckets];
while (item) {
if (map->key_compare(key, item->key, map->key_size)) {
map->hit_count++;
return item->value;
}
item = item->next;
}
map->miss_count++;
return 0;
}
//---------------------------------
// font cache
static unsigned font_desc_hash(void *buf, size_t len)
{
ASS_FontDesc *desc = buf;
unsigned hval;
hval = fnv_32a_str(desc->family, FNV1_32A_INIT);
hval = fnv_32a_buf(&desc->bold, sizeof(desc->bold), hval);
hval = fnv_32a_buf(&desc->italic, sizeof(desc->italic), hval);
return hval;
}
static int font_compare(void *key1, void *key2, size_t key_size)
{
ASS_FontDesc *a = key1;
ASS_FontDesc *b = key2;
if (strcmp(a->family, b->family) != 0)
return 0;
if (a->bold != b->bold)
return 0;
if (a->italic != b->italic)
return 0;
if (a->treat_family_as_pattern != b->treat_family_as_pattern)
return 0;
return 1;
}
static void font_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
ass_font_free(value);
free(key);
}
ASS_Font *ass_font_cache_find(Hashmap *font_cache,
ASS_FontDesc *desc)
{
return hashmap_find(font_cache, desc);
}
/**
* \brief Add a face struct to cache.
* \param font font struct
*/
void *ass_font_cache_add(Hashmap *font_cache, ASS_Font *font)
{
return hashmap_insert(font_cache, &(font->desc), font);
}
Hashmap *ass_font_cache_init(ASS_Library *library)
{
Hashmap *font_cache;
font_cache = hashmap_init(library, sizeof(ASS_FontDesc),
sizeof(ASS_Font),
1000,
font_hash_dtor, font_compare, font_desc_hash);
return font_cache;
}
void ass_font_cache_done(Hashmap *font_cache)
{
hashmap_done(font_cache);
}
// Create hash/compare functions for bitmap and glyph
#define CREATE_HASH_FUNCTIONS
#include "ass_cache_template.h"
#define CREATE_COMPARISON_FUNCTIONS
#include "ass_cache_template.h"
//---------------------------------
// bitmap cache
static void bitmap_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
BitmapHashValue *v = value;
if (v->bm)
ass_free_bitmap(v->bm);
if (v->bm_o)
ass_free_bitmap(v->bm_o);
if (v->bm_s)
ass_free_bitmap(v->bm_s);
free(key);
free(value);
}
void *cache_add_bitmap(Hashmap *bitmap_cache, BitmapHashKey *key,
BitmapHashValue *val)
{
// Note: this is only an approximation
if (val->bm_o)
bitmap_cache->cache_size += val->bm_o->w * val->bm_o->h * 3;
else if (val->bm)
bitmap_cache->cache_size += val->bm->w * val->bm->h * 3;
return hashmap_insert(bitmap_cache, key, val);
}
/**
* \brief Get a bitmap from bitmap cache.
* \param key hash key
* \return requested hash val or 0 if not found
*/
BitmapHashValue *cache_find_bitmap(Hashmap *bitmap_cache,
BitmapHashKey *key)
{
return hashmap_find(bitmap_cache, key);
}
Hashmap *ass_bitmap_cache_init(ASS_Library *library)
{
Hashmap *bitmap_cache;
bitmap_cache = hashmap_init(library,
sizeof(BitmapHashKey),
sizeof(BitmapHashValue),
0xFFFF + 13,
bitmap_hash_dtor, bitmap_compare,
bitmap_hash);
return bitmap_cache;
}
void ass_bitmap_cache_done(Hashmap *bitmap_cache)
{
hashmap_done(bitmap_cache);
}
Hashmap *ass_bitmap_cache_reset(Hashmap *bitmap_cache)
{
ASS_Library *lib = bitmap_cache->library;
ass_bitmap_cache_done(bitmap_cache);
return ass_bitmap_cache_init(lib);
}
//---------------------------------
// glyph cache
static void glyph_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
GlyphHashValue *v = value;
if (v->glyph)
FT_Done_Glyph(v->glyph);
if (v->outline_glyph)
FT_Done_Glyph(v->outline_glyph);
free(key);
free(value);
}
void *cache_add_glyph(Hashmap *glyph_cache, GlyphHashKey *key,
GlyphHashValue *val)
{
return hashmap_insert(glyph_cache, key, val);
}
/**
* \brief Get a glyph from glyph cache.
* \param key hash key
* \return requested hash val or 0 if not found
*/
GlyphHashValue *cache_find_glyph(Hashmap *glyph_cache,
GlyphHashKey *key)
{
return hashmap_find(glyph_cache, key);
}
Hashmap *ass_glyph_cache_init(ASS_Library *library)
{
Hashmap *glyph_cache;
glyph_cache = hashmap_init(library, sizeof(GlyphHashKey),
sizeof(GlyphHashValue),
0xFFFF + 13,
glyph_hash_dtor, glyph_compare, glyph_hash);
return glyph_cache;
}
void ass_glyph_cache_done(Hashmap *glyph_cache)
{
hashmap_done(glyph_cache);
}
Hashmap *ass_glyph_cache_reset(Hashmap *glyph_cache)
{
ASS_Library *lib = glyph_cache->library;
ass_glyph_cache_done(glyph_cache);
return ass_glyph_cache_init(lib);
}
//---------------------------------
// composite cache
static void composite_hash_dtor(void *key, size_t key_size, void *value,
size_t value_size)
{
CompositeHashValue *v = value;
free(v->a);
free(v->b);
free(key);
free(value);
}
void *cache_add_composite(Hashmap *composite_cache,
CompositeHashKey *key,
CompositeHashValue *val)
{
return hashmap_insert(composite_cache, key, val);
}
/**
* \brief Get a composite bitmap from composite cache.
* \param key hash key
* \return requested hash val or 0 if not found
*/
CompositeHashValue *cache_find_composite(Hashmap *composite_cache,
CompositeHashKey *key)
{
return hashmap_find(composite_cache, key);
}
Hashmap *ass_composite_cache_init(ASS_Library *library)
{
Hashmap *composite_cache;
composite_cache = hashmap_init(library, sizeof(CompositeHashKey),
sizeof(CompositeHashValue),
0xFFFF + 13,
composite_hash_dtor, composite_compare,
composite_hash);
return composite_cache;
}
void ass_composite_cache_done(Hashmap *composite_cache)
{
hashmap_done(composite_cache);
}
Hashmap *ass_composite_cache_reset(Hashmap *composite_cache)
{
ASS_Library *lib = composite_cache->library;
ass_composite_cache_done(composite_cache);
return ass_composite_cache_init(lib);
}

View File

@ -1,119 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_CACHE_H
#define LIBASS_CACHE_H
#include "ass.h"
#include "ass_font.h"
#include "ass_bitmap.h"
typedef void (*HashmapItemDtor) (void *key, size_t key_size,
void *value, size_t value_size);
typedef int (*HashmapKeyCompare) (void *key1, void *key2,
size_t key_size);
typedef unsigned (*HashmapHash) (void *key, size_t key_size);
typedef struct hashmap_item {
void *key;
void *value;
struct hashmap_item *next;
} HashmapItem;
typedef HashmapItem *hashmap_item_p;
typedef struct {
int nbuckets;
size_t key_size, value_size;
hashmap_item_p *root;
HashmapItemDtor item_dtor; // a destructor for hashmap key/value pairs
HashmapKeyCompare key_compare;
HashmapHash hash;
size_t cache_size;
// stats
int hit_count;
int miss_count;
int count;
ASS_Library *library;
} Hashmap;
Hashmap *hashmap_init(ASS_Library *library, size_t key_size,
size_t value_size, int nbuckets,
HashmapItemDtor item_dtor,
HashmapKeyCompare key_compare,
HashmapHash hash);
void hashmap_done(Hashmap *map);
void *hashmap_insert(Hashmap *map, void *key, void *value);
void *hashmap_find(Hashmap *map, void *key);
Hashmap *ass_font_cache_init(ASS_Library *library);
ASS_Font *ass_font_cache_find(Hashmap *, ASS_FontDesc *desc);
void *ass_font_cache_add(Hashmap *, ASS_Font *font);
void ass_font_cache_done(Hashmap *);
// Create definitions for bitmap_hash_key and glyph_hash_key
#define CREATE_STRUCT_DEFINITIONS
#include "ass_cache_template.h"
typedef struct {
Bitmap *bm; // the actual bitmaps
Bitmap *bm_o;
Bitmap *bm_s;
} BitmapHashValue;
Hashmap *ass_bitmap_cache_init(ASS_Library *library);
void *cache_add_bitmap(Hashmap *, BitmapHashKey *key,
BitmapHashValue *val);
BitmapHashValue *cache_find_bitmap(Hashmap *bitmap_cache,
BitmapHashKey *key);
Hashmap *ass_bitmap_cache_reset(Hashmap *bitmap_cache);
void ass_bitmap_cache_done(Hashmap *bitmap_cache);
typedef struct {
unsigned char *a;
unsigned char *b;
} CompositeHashValue;
Hashmap *ass_composite_cache_init(ASS_Library *library);
void *cache_add_composite(Hashmap *, CompositeHashKey *key,
CompositeHashValue *val);
CompositeHashValue *cache_find_composite(Hashmap *composite_cache,
CompositeHashKey *key);
Hashmap *ass_composite_cache_reset(Hashmap *composite_cache);
void ass_composite_cache_done(Hashmap *composite_cache);
typedef struct {
FT_Glyph glyph;
FT_Glyph outline_glyph;
FT_BBox bbox_scaled; // bbox after scaling, but before rotation
FT_Vector advance; // 26.6, advance distance to the next bitmap in line
int asc, desc; // ascender/descender of a drawing
} GlyphHashValue;
Hashmap *ass_glyph_cache_init(ASS_Library *library);
void *cache_add_glyph(Hashmap *, GlyphHashKey *key,
GlyphHashValue *val);
GlyphHashValue *cache_find_glyph(Hashmap *glyph_cache,
GlyphHashKey *key);
Hashmap *ass_glyph_cache_reset(Hashmap *glyph_cache);
void ass_glyph_cache_done(Hashmap *glyph_cache);
#endif /* LIBASS_CACHE_H */

View File

@ -1,122 +0,0 @@
#ifdef CREATE_STRUCT_DEFINITIONS
#undef CREATE_STRUCT_DEFINITIONS
#define START(funcname, structname) \
typedef struct structname {
#define GENERIC(type, member) \
type member;
#define FTVECTOR(member) \
FT_Vector member;
#define BITMAPHASHKEY(member) \
BitmapHashKey member;
#define END(typedefnamename) \
} typedefnamename;
#elif defined(CREATE_COMPARISON_FUNCTIONS)
#undef CREATE_COMPARISON_FUNCTIONS
#define START(funcname, structname) \
static int funcname##_compare(void *key1, void *key2, size_t key_size) \
{ \
struct structname *a = key1; \
struct structname *b = key2; \
return // conditions follow
#define GENERIC(type, member) \
a->member == b->member &&
#define FTVECTOR(member) \
a->member.x == b->member.x && a->member.y == b->member.y &&
#define BITMAPHASHKEY(member) \
bitmap_compare(&a->member, &b->member, sizeof(a->member)) &&
#define END(typedefname) \
1; \
}
#elif defined(CREATE_HASH_FUNCTIONS)
#undef CREATE_HASH_FUNCTIONS
#define START(funcname, structname) \
static unsigned funcname##_hash(void *buf, size_t len) \
{ \
struct structname *p = buf; \
unsigned hval = FNV1_32A_INIT;
#define GENERIC(type, member) \
hval = fnv_32a_buf(&p->member, sizeof(p->member), hval);
#define FTVECTOR(member) GENERIC(, member.x); GENERIC(, member.y);
#define BITMAPHASHKEY(member) { \
unsigned temp = bitmap_hash(&p->member, sizeof(p->member)); \
hval = fnv_32a_buf(&temp, sizeof(temp), hval); \
}
#define END(typedefname) \
return hval; \
}
#else
#error missing defines
#endif
// describes a bitmap; bitmaps with equivalents structs are considered identical
START(bitmap, bitmap_hash_key)
GENERIC(char, bitmap) // bool : true = bitmap, false = outline
GENERIC(ASS_Font *, font)
GENERIC(double, size) // font size
GENERIC(uint32_t, ch) // character code
FTVECTOR(outline) // border width, 16.16 fixed point value
GENERIC(int, bold)
GENERIC(int, italic)
GENERIC(char, be) // blur edges
GENERIC(double, blur) // gaussian blur
GENERIC(unsigned, scale_x) // 16.16
GENERIC(unsigned, scale_y) // 16.16
GENERIC(int, frx) // signed 16.16
GENERIC(int, fry) // signed 16.16
GENERIC(int, frz) // signed 16.16
GENERIC(int, fax) // signed 16.16
GENERIC(int, fay) // signed 16.16
// shift vector that was added to glyph before applying rotation
// = 0, if frx = fry = frx = 0
// = (glyph base point) - (rotation origin), otherwise
GENERIC(int, shift_x)
GENERIC(int, shift_y)
FTVECTOR(advance) // subpixel shift vector
FTVECTOR(shadow_offset) // shadow subpixel shift
GENERIC(unsigned, drawing_hash) // hashcode of a drawing
GENERIC(unsigned, flags) // glyph decoration
GENERIC(unsigned, border_style)
END(BitmapHashKey)
// describes an outline glyph
START(glyph, glyph_hash_key)
GENERIC(ASS_Font *, font)
GENERIC(double, size) // font size
GENERIC(uint32_t, ch) // character code
GENERIC(int, bold)
GENERIC(int, italic)
GENERIC(unsigned, scale_x) // 16.16
GENERIC(unsigned, scale_y) // 16.16
FTVECTOR(outline) // border width, 16.16
GENERIC(unsigned, drawing_hash) // hashcode of a drawing
GENERIC(unsigned, flags) // glyph decoration flags
GENERIC(unsigned, border_style)
END(GlyphHashKey)
// Cache for composited bitmaps
START(composite, composite_hash_key)
GENERIC(int, aw)
GENERIC(int, ah)
GENERIC(int, bw)
GENERIC(int, bh)
GENERIC(int, ax)
GENERIC(int, ay)
GENERIC(int, bx)
GENERIC(int, by)
GENERIC(int, as)
GENERIC(int, bs)
GENERIC(unsigned char *, a)
GENERIC(unsigned char *, b)
END(CompositeHashKey)
#undef START
#undef GENERIC
#undef FTVECTOR
#undef BITMAPHASHKEY
#undef END

View File

@ -1,495 +0,0 @@
/*
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* 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 <ft2build.h>
#include FT_GLYPH_H
#include FT_OUTLINE_H
#include FT_BBOX_H
#include <math.h>
#include "ass_utils.h"
#include "ass_font.h"
#include "ass_drawing.h"
#define CURVE_ACCURACY 64.0
#define GLYPH_INITIAL_POINTS 100
#define GLYPH_INITIAL_CONTOURS 5
/*
* \brief Get and prepare a FreeType glyph
*/
static void drawing_make_glyph(ASS_Drawing *drawing, void *fontconfig_priv,
ASS_Font *font, ASS_Hinting hint)
{
FT_OutlineGlyph glyph;
// This is hacky...
glyph = (FT_OutlineGlyph) ass_font_get_glyph(fontconfig_priv, font,
(uint32_t) ' ', hint, 0);
if (glyph) {
FT_Outline_Done(drawing->ftlibrary, &glyph->outline);
FT_Outline_New(drawing->ftlibrary, GLYPH_INITIAL_POINTS,
GLYPH_INITIAL_CONTOURS, &glyph->outline);
glyph->outline.n_contours = 0;
glyph->outline.n_points = 0;
glyph->root.advance.x = glyph->root.advance.y = 0;
}
drawing->glyph = glyph;
}
/*
* \brief Add a single point to a contour.
*/
static inline void drawing_add_point(ASS_Drawing *drawing,
FT_Vector *point)
{
FT_Outline *ol = &drawing->glyph->outline;
if (ol->n_points >= drawing->max_points) {
drawing->max_points *= 2;
ol->points = realloc(ol->points, sizeof(FT_Vector) *
drawing->max_points);
ol->tags = realloc(ol->tags, drawing->max_points);
}
ol->points[ol->n_points].x = point->x;
ol->points[ol->n_points].y = point->y;
ol->tags[ol->n_points] = 1;
ol->n_points++;
}
/*
* \brief Close a contour and check glyph size overflow.
*/
static inline void drawing_close_shape(ASS_Drawing *drawing)
{
FT_Outline *ol = &drawing->glyph->outline;
if (ol->n_contours >= drawing->max_contours) {
drawing->max_contours *= 2;
ol->contours = realloc(ol->contours, sizeof(short) *
drawing->max_contours);
}
if (ol->n_points) {
ol->contours[ol->n_contours] = ol->n_points - 1;
ol->n_contours++;
}
}
/*
* \brief Prepare drawing for parsing. This just sets a few parameters.
*/
static void drawing_prepare(ASS_Drawing *drawing)
{
// Scaling parameters
drawing->point_scale_x = drawing->scale_x *
64.0 / (1 << (drawing->scale - 1));
drawing->point_scale_y = drawing->scale_y *
64.0 / (1 << (drawing->scale - 1));
}
/*
* \brief Finish a drawing. This only sets the horizontal advance according
* to the glyph's bbox at the moment.
*/
static void drawing_finish(ASS_Drawing *drawing, int raw_mode)
{
int i, offset;
FT_BBox bbox;
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);
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);
drawing->asc = bbox.yMax - bbox.yMin + drawing->desc;
// Place it onto the baseline
offset = (bbox.yMax - bbox.yMin) + double_to_d6(-drawing->pbo *
drawing->scale_y);
for (i = 0; i < ol->n_points; i++)
ol->points[i].y += offset;
}
/*
* \brief Check whether a number of items on the list is available
*/
static int token_check_values(ASS_DrawingToken *token, int i, int type)
{
int j;
for (j = 0; j < i; j++) {
if (!token || token->type != type) return 0;
token = token->next;
}
return 1;
}
/*
* \brief Tokenize a drawing string into a list of ASS_DrawingToken
* This also expands points for closing b-splines
*/
static ASS_DrawingToken *drawing_tokenize(char *str)
{
char *p = str;
int i, val, type = -1, is_set = 0;
FT_Vector point = {0, 0};
ASS_DrawingToken *root = NULL, *tail = NULL, *spline_start = NULL;
while (*p) {
if (*p == 'c' && spline_start) {
// Close b-splines: add the first three points of the b-spline
// back to the end
if (token_check_values(spline_start->next, 2, TOKEN_B_SPLINE)) {
for (i = 0; i < 3; i++) {
tail->next = calloc(1, sizeof(ASS_DrawingToken));
tail->next->prev = tail;
tail = tail->next;
tail->type = TOKEN_B_SPLINE;
tail->point = spline_start->point;
spline_start = spline_start->next;
}
spline_start = NULL;
}
} else if (!is_set && mystrtoi(&p, &val)) {
point.x = val;
is_set = 1;
p--;
} else if (is_set == 1 && mystrtoi(&p, &val)) {
point.y = val;
is_set = 2;
p--;
} else if (*p == 'm')
type = TOKEN_MOVE;
else if (*p == 'n')
type = TOKEN_MOVE_NC;
else if (*p == 'l')
type = TOKEN_LINE;
else if (*p == 'b')
type = TOKEN_CUBIC_BEZIER;
else if (*p == 'q')
type = TOKEN_CONIC_BEZIER;
else if (*p == 's')
type = TOKEN_B_SPLINE;
// We're simply ignoring TOKEN_EXTEND_B_SPLINE here.
// This is not harmful at all, since it can be ommitted with
// similar result (the spline is extended anyway).
if (type != -1 && is_set == 2) {
if (root) {
tail->next = calloc(1, sizeof(ASS_DrawingToken));
tail->next->prev = tail;
tail = tail->next;
} else
root = tail = calloc(1, sizeof(ASS_DrawingToken));
tail->type = type;
tail->point = point;
is_set = 0;
if (type == TOKEN_B_SPLINE && !spline_start)
spline_start = tail->prev;
}
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;
}
/*
* \brief Free a list of tokens
*/
static void drawing_free_tokens(ASS_DrawingToken *token)
{
while (token) {
ASS_DrawingToken *at = token;
token = token->next;
free(at);
}
}
/*
* \brief Translate and scale a point coordinate according to baseline
* offset and scale.
*/
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;
}
/*
* \brief Evaluate a curve into lines
* This curve evaluator is also used in VSFilter (RTS.cpp); it's a simple
* implementation of the De Casteljau algorithm.
*/
static void drawing_evaluate_curve(ASS_Drawing *drawing,
ASS_DrawingToken *token, char spline,
int started)
{
double cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
double t, h, max_accel, max_accel1, max_accel2;
FT_Vector cur = {0, 0};
cur = token->point;
translate_point(drawing, &cur);
int x0 = cur.x;
int y0 = cur.y;
token = token->next;
cur = token->point;
translate_point(drawing, &cur);
int x1 = cur.x;
int y1 = cur.y;
token = token->next;
cur = token->point;
translate_point(drawing, &cur);
int x2 = cur.x;
int y2 = cur.y;
token = token->next;
cur = token->point;
translate_point(drawing, &cur);
int x3 = cur.x;
int y3 = cur.y;
if (spline) {
// 1 [-1 +3 -3 +1]
// - * [+3 -6 +3 0]
// 6 [-3 0 +3 0]
// [+1 +4 +1 0]
double div6 = 1.0/6.0;
cx3 = div6*(- x0+3*x1-3*x2+x3);
cx2 = div6*( 3*x0-6*x1+3*x2);
cx1 = div6*(-3*x0 +3*x2);
cx0 = div6*( x0+4*x1+1*x2);
cy3 = div6*(- y0+3*y1-3*y2+y3);
cy2 = div6*( 3*y0-6*y1+3*y2);
cy1 = div6*(-3*y0 +3*y2);
cy0 = div6*( y0+4*y1+1*y2);
} else {
// [-1 +3 -3 +1]
// [+3 -6 +3 0]
// [-3 +3 0 0]
// [+1 0 0 0]
cx3 = - x0+3*x1-3*x2+x3;
cx2 = 3*x0-6*x1+3*x2;
cx1 = -3*x0+3*x1;
cx0 = x0;
cy3 = - y0+3*y1-3*y2+y3;
cy2 = 3*y0-6*y1+3*y2;
cy1 = -3*y0+3*y1;
cy0 = y0;
}
max_accel1 = fabs(2 * cy2) + fabs(6 * cy3);
max_accel2 = fabs(2 * cx2) + fabs(6 * cx3);
max_accel = FFMAX(max_accel1, max_accel2);
h = 1.0;
if (max_accel > CURVE_ACCURACY)
h = sqrt(CURVE_ACCURACY / max_accel);
if (!started) {
cur.x = cx0;
cur.y = cy0;
drawing_add_point(drawing, &cur);
}
for (t = 0; t < 1.0; t += h) {
cur.x = cx0 + t * (cx1 + t * (cx2 + t * cx3));
cur.y = cy0 + t * (cy1 + t * (cy2 + t * cy3));
drawing_add_point(drawing, &cur);
}
cur.x = cx0 + cx1 + cx2 + cx3;
cur.y = cy0 + cy1 + cy2 + cy3;
drawing_add_point(drawing, &cur);
}
/*
* \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)
{
ASS_Drawing *drawing;
drawing = calloc(1, sizeof(*drawing));
drawing->text = calloc(1, DRAWING_INITIAL_SIZE);
drawing->size = DRAWING_INITIAL_SIZE;
drawing->ftlibrary = lib;
if (font) {
drawing->library = font->library;
drawing_make_glyph(drawing, fontconfig_priv, font, hint);
}
drawing->scale_x = 1.;
drawing->scale_y = 1.;
drawing->max_contours = GLYPH_INITIAL_CONTOURS;
drawing->max_points = GLYPH_INITIAL_POINTS;
return drawing;
}
/*
* \brief Free a drawing
*/
void ass_drawing_free(ASS_Drawing* drawing)
{
if (drawing) {
if (drawing->glyph)
FT_Done_Glyph((FT_Glyph) drawing->glyph);
free(drawing->text);
}
free(drawing);
}
/*
* \brief Add one ASCII character to the drawing text buffer
*/
void ass_drawing_add_char(ASS_Drawing* drawing, char symbol)
{
drawing->text[drawing->i++] = symbol;
drawing->text[drawing->i] = 0;
if (drawing->i + 1 >= drawing->size) {
drawing->size *= 2;
drawing->text = realloc(drawing->text, drawing->size);
}
}
/*
* \brief Create a hashcode for the drawing
* XXX: To avoid collisions a better hash algorithm might be useful.
*/
void ass_drawing_hash(ASS_Drawing* drawing)
{
drawing->hash = fnv_32a_str(drawing->text, FNV1_32A_INIT);
}
/*
* \brief Convert token list to outline. Calls the line and curve evaluators.
*/
FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode)
{
int started = 0;
ASS_DrawingToken *token;
FT_Vector pen = {0, 0};
if (!drawing->glyph)
return NULL;
drawing->tokens = drawing_tokenize(drawing->text);
drawing_prepare(drawing);
token = drawing->tokens;
while (token) {
// Draw something according to current command
switch (token->type) {
case TOKEN_MOVE_NC:
pen = token->point;
translate_point(drawing, &pen);
token = token->next;
break;
case TOKEN_MOVE:
pen = token->point;
translate_point(drawing, &pen);
if (started) {
drawing_close_shape(drawing);
started = 0;
}
token = token->next;
break;
case TOKEN_LINE: {
FT_Vector to;
to = token->point;
translate_point(drawing, &to);
if (!started) drawing_add_point(drawing, &pen);
drawing_add_point(drawing, &to);
started = 1;
token = token->next;
break;
}
case TOKEN_CUBIC_BEZIER:
if (token_check_values(token, 3, TOKEN_CUBIC_BEZIER) &&
token->prev) {
drawing_evaluate_curve(drawing, token->prev, 0, started);
token = token->next;
token = token->next;
token = token->next;
started = 1;
} else
token = token->next;
break;
case TOKEN_B_SPLINE:
if (token_check_values(token, 3, TOKEN_B_SPLINE) &&
token->prev) {
drawing_evaluate_curve(drawing, token->prev, 1, started);
token = token->next;
started = 1;
} else
token = token->next;
break;
default:
token = token->next;
break;
}
}
drawing_finish(drawing, raw_mode);
drawing_free_tokens(drawing->tokens);
return &drawing->glyph;
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* 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.
*/
#ifndef LIBASS_DRAWING_H
#define LIBASS_DRAWING_H
#include <ft2build.h>
#include FT_GLYPH_H
#include "ass.h"
#define DRAWING_INITIAL_SIZE 256
typedef enum {
TOKEN_MOVE,
TOKEN_MOVE_NC,
TOKEN_LINE,
TOKEN_CUBIC_BEZIER,
TOKEN_CONIC_BEZIER,
TOKEN_B_SPLINE,
TOKEN_EXTEND_SPLINE,
TOKEN_CLOSE
} ASS_TokenType;
typedef struct ass_drawing_token {
ASS_TokenType type;
FT_Vector point;
struct ass_drawing_token *next;
struct ass_drawing_token *prev;
} ASS_DrawingToken;
typedef struct {
char *text; // drawing string
int i; // text index
int scale; // scale (1-64) for subpixel accuracy
double pbo; // drawing will be shifted in y direction by this amount
double scale_x; // FontScaleX
double scale_y; // FontScaleY
int asc; // ascender
int desc; // descender
FT_OutlineGlyph glyph; // the "fake" glyph created for later rendering
int hash; // hash value (for caching)
// private
FT_Library ftlibrary; // FT library instance, needed for font ops
ASS_Library *library;
int size; // current buffer size
ASS_DrawingToken *tokens; // tokenized drawing
int max_points; // current maximum size
int max_contours;
double point_scale_x;
double point_scale_y;
} ASS_Drawing;
ASS_Drawing *ass_drawing_new(void *fontconfig_priv, ASS_Font *font,
ASS_Hinting hint, 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);
FT_OutlineGlyph *ass_drawing_parse(ASS_Drawing *drawing, int raw_mode);
#endif /* LIBASS_DRAWING_H */

View File

@ -1,532 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#include "config.h"
#include <inttypes.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_SYNTHESIS_H
#include FT_GLYPH_H
#include FT_TRUETYPE_TABLES_H
#include FT_OUTLINE_H
#include "ass.h"
#include "ass_library.h"
#include "ass_font.h"
#include "ass_bitmap.h"
#include "ass_cache.h"
#include "ass_fontconfig.h"
#include "ass_utils.h"
/**
* Select Microfost Unicode CharMap, if the font has one.
* Otherwise, let FreeType decide.
*/
static void charmap_magic(ASS_Library *library, FT_Face face)
{
int i;
for (i = 0; i < face->num_charmaps; ++i) {
FT_CharMap cmap = face->charmaps[i];
unsigned pid = cmap->platform_id;
unsigned eid = cmap->encoding_id;
if (pid == 3 /*microsoft */
&& (eid == 1 /*unicode bmp */
|| eid == 10 /*full unicode */ )) {
FT_Set_Charmap(face, cmap);
return;
}
}
if (!face->charmap) {
if (face->num_charmaps == 0) {
ass_msg(library, MSGL_WARN, "Font face with no charmaps");
return;
}
ass_msg(library, MSGL_WARN,
"No charmap autodetected, trying the first one");
FT_Set_Charmap(face, face->charmaps[0]);
return;
}
}
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
*/
static int find_font(ASS_Library *library, char *name)
{
int i;
for (i = 0; i < library->num_fontdata; ++i)
if (strcasecmp(name, library->fontdata[i].name) == 0)
return i;
return -1;
}
static void face_set_size(FT_Face face, double size);
static void buggy_font_workaround(FT_Face face)
{
// Some fonts have zero Ascender/Descender fields in 'hhea' table.
// In this case, get the information from 'os2' table or, as
// a last resort, from face.bbox.
if (face->ascender + face->descender == 0 || face->height == 0) {
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
if (os2) {
face->ascender = os2->sTypoAscender;
face->descender = os2->sTypoDescender;
face->height = face->ascender - face->descender;
} else {
face->ascender = face->bbox.yMax;
face->descender = face->bbox.yMin;
face->height = face->ascender - face->descender;
}
}
}
/**
* \brief Select a face with the given charcode and add it to ASS_Font
* \return index of the new face in font->faces, -1 if failed
*/
static int add_face(void *fc_priv, ASS_Font *font, uint32_t ch)
{
char *path;
int index;
FT_Face face;
int error;
int mem_idx;
if (font->n_faces == ASS_FONT_MAX_FACES)
return -1;
path =
fontconfig_select(font->library, fc_priv, font->desc.family,
font->desc.treat_family_as_pattern,
font->desc.bold, font->desc.italic, &index, ch);
if (!path)
return -1;
mem_idx = find_font(font->library, path);
if (mem_idx >= 0) {
error =
FT_New_Memory_Face(font->ftlibrary,
(unsigned char *) font->library->
fontdata[mem_idx].data,
font->library->fontdata[mem_idx].size, 0,
&face);
if (error) {
ass_msg(font->library, MSGL_WARN,
"Error opening memory font: '%s'", path);
free(path);
return -1;
}
} else {
error = FT_New_Face(font->ftlibrary, path, index, &face);
if (error) {
ass_msg(font->library, MSGL_WARN,
"Error opening font: '%s', %d", path, index);
free(path);
return -1;
}
}
charmap_magic(font->library, face);
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;
}
/**
* \brief Create a new ASS_Font according to "desc" argument
*/
ASS_Font *ass_font_new(void *font_cache, ASS_Library *library,
FT_Library ftlibrary, void *fc_priv,
ASS_FontDesc *desc)
{
int error;
ASS_Font *fontp;
ASS_Font font;
fontp = ass_font_cache_find((Hashmap *) font_cache, desc);
if (fontp)
return fontp;
font.library = library;
font.ftlibrary = ftlibrary;
font.n_faces = 0;
font.desc.family = strdup(desc->family);
font.desc.treat_family_as_pattern = desc->treat_family_as_pattern;
font.desc.bold = desc->bold;
font.desc.italic = desc->italic;
font.scale_x = font.scale_y = 1.;
font.v.x = font.v.y = 0;
font.size = 0.;
error = add_face(fc_priv, &font, 0);
if (error == -1) {
free(font.desc.family);
return 0;
} else
return ass_font_cache_add((Hashmap *) font_cache, &font);
}
/**
* \brief Set font transformation matrix and shift vector
**/
void ass_font_set_transform(ASS_Font *font, double scale_x,
double scale_y, FT_Vector *v)
{
font->scale_x = scale_x;
font->scale_y = scale_y;
if (v) {
font->v.x = v->x;
font->v.y = v->y;
}
update_transform(font);
}
static void face_set_size(FT_Face face, double size)
{
TT_HoriHeader *hori = FT_Get_Sfnt_Table(face, ft_sfnt_hhea);
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
double mscale = 1.;
FT_Size_RequestRec rq;
FT_Size_Metrics *m = &face->size->metrics;
// VSFilter uses metrics from TrueType OS/2 table
// The idea was borrowed from asa (http://asa.diac24.net)
if (hori && os2) {
int hori_height = hori->Ascender - hori->Descender;
int os2_height = os2->usWinAscent + os2->usWinDescent;
if (hori_height && os2_height)
mscale = (double) hori_height / os2_height;
}
memset(&rq, 0, sizeof(rq));
rq.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
rq.width = 0;
rq.height = double_to_d6(size * mscale);
rq.horiResolution = rq.vertResolution = 0;
FT_Request_Size(face, &rq);
m->ascender /= mscale;
m->descender /= mscale;
m->height /= mscale;
}
/**
* \brief Set font size
**/
void ass_font_set_size(ASS_Font *font, double size)
{
int i;
if (font->size != size) {
font->size = size;
for (i = 0; i < font->n_faces; ++i)
face_set_size(font->faces[i], size);
}
}
/**
* \brief Get maximal font ascender and descender.
* \param ch character code
* The values are extracted from the font face that provides glyphs for the given character
**/
void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
int *desc)
{
int i;
for (i = 0; i < font->n_faces; ++i) {
FT_Face face = font->faces[i];
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
if (FT_Get_Char_Index(face, ch)) {
int y_scale = face->size->metrics.y_scale;
if (os2) {
*asc = FT_MulFix(os2->usWinAscent, y_scale);
*desc = FT_MulFix(os2->usWinDescent, y_scale);
} else {
*asc = FT_MulFix(face->ascender, y_scale);
*desc = FT_MulFix(-face->descender, y_scale);
}
return;
}
}
*asc = *desc = 0;
}
/*
* Strike a glyph with a horizontal line; it's possible to underline it
* and/or strike through it. For the line's position and size, truetype
* tables are consulted. Obviously this relies on the data in the tables
* being accurate.
*
*/
static int ass_strike_outline_glyph(FT_Face face, ASS_Font *font,
FT_Glyph glyph, int under, int through)
{
TT_OS2 *os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
TT_Postscript *ps = FT_Get_Sfnt_Table(face, ft_sfnt_post);
FT_Outline *ol = &((FT_OutlineGlyph) glyph)->outline;
int bear, advance, y_scale, i, dir;
if (!under && !through)
return 0;
// Grow outline
i = (under ? 4 : 0) + (through ? 4 : 0);
ol->points = realloc(ol->points, sizeof(FT_Vector) *
(ol->n_points + i));
ol->tags = realloc(ol->tags, ol->n_points + i);
i = !!under + !!through;
ol->contours = realloc(ol->contours, sizeof(short) *
(ol->n_contours + i));
// If the bearing is negative, the glyph starts left of the current
// pen position
bear = FFMIN(face->glyph->metrics.horiBearingX, 0);
// We're adding half a pixel to avoid small gaps
advance = d16_to_d6(glyph->advance.x) + 32;
y_scale = face->size->metrics.y_scale;
// Reverse drawing direction for non-truetype fonts
dir = FT_Outline_Get_Orientation(ol);
// Add points to the outline
if (under && ps) {
int pos, size;
pos = FT_MulFix(ps->underlinePosition, y_scale * font->scale_y);
size = FT_MulFix(ps->underlineThickness,
y_scale * font->scale_y / 2);
if (pos > 0 || size <= 0)
return 1;
FT_Vector points[4] = {
{.x = bear, .y = pos + size},
{.x = advance, .y = pos + size},
{.x = advance, .y = pos - size},
{.x = bear, .y = pos - size},
};
if (dir == FT_ORIENTATION_TRUETYPE) {
for (i = 0; i < 4; i++) {
ol->points[ol->n_points] = points[i];
ol->tags[ol->n_points++] = 1;
}
} else {
for (i = 3; i >= 0; i--) {
ol->points[ol->n_points] = points[i];
ol->tags[ol->n_points++] = 1;
}
}
ol->contours[ol->n_contours++] = ol->n_points - 1;
}
if (through && os2) {
int pos, size;
pos = FT_MulFix(os2->yStrikeoutPosition, y_scale * font->scale_y);
size = FT_MulFix(os2->yStrikeoutSize, y_scale * font->scale_y / 2);
if (pos < 0 || size <= 0)
return 1;
FT_Vector points[4] = {
{.x = bear, .y = pos + size},
{.x = advance, .y = pos + size},
{.x = advance, .y = pos - size},
{.x = bear, .y = pos - size},
};
if (dir == FT_ORIENTATION_TRUETYPE) {
for (i = 0; i < 4; i++) {
ol->points[ol->n_points] = points[i];
ol->tags[ol->n_points++] = 1;
}
} else {
for (i = 3; i >= 0; i--) {
ol->points[ol->n_points] = points[i];
ol->tags[ol->n_points++] = 1;
}
}
ol->contours[ol->n_contours++] = ol->n_points - 1;
}
return 0;
}
/**
* Slightly embold a glyph without touching its metrics
*/
static void ass_glyph_embolden(FT_GlyphSlot slot)
{
int str;
if (slot->format != FT_GLYPH_FORMAT_OUTLINE)
return;
str = FT_MulFix(slot->face->units_per_EM,
slot->face->size->metrics.y_scale) / 64;
FT_Outline_Embolden(&slot->outline, str);
}
/**
* \brief Get a glyph
* \param ch character code
**/
FT_Glyph ass_font_get_glyph(void *fontconfig_priv, ASS_Font *font,
uint32_t ch, ASS_Hinting hinting, int deco)
{
int error;
int index = 0;
int i;
FT_Glyph glyph;
FT_Face face = 0;
int flags = 0;
if (ch < 0x20)
return 0;
// Handle NBSP like a regular space when rendering the glyph
if (ch == 0xa0)
ch = ' ';
if (font->n_faces == 0)
return 0;
for (i = 0; i < font->n_faces; ++i) {
face = font->faces[i];
index = FT_Get_Char_Index(face, ch);
if (index)
break;
}
#ifdef CONFIG_FONTCONFIG
if (index == 0) {
int face_idx;
ass_msg(font->library, MSGL_INFO,
"Glyph 0x%X not found, selecting one more "
"font for (%s, %d, %d)", ch, font->desc.family,
font->desc.bold, font->desc.italic);
face_idx = add_face(fontconfig_priv, font, ch);
if (face_idx >= 0) {
face = font->faces[face_idx];
index = FT_Get_Char_Index(face, ch);
if (index == 0) {
ass_msg(font->library, MSGL_ERR,
"Glyph 0x%X not found in font for (%s, %d, %d)",
ch, font->desc.family, font->desc.bold,
font->desc.italic);
}
}
}
#endif
switch (hinting) {
case ASS_HINTING_NONE:
flags = FT_LOAD_NO_HINTING;
break;
case ASS_HINTING_LIGHT:
flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT;
break;
case ASS_HINTING_NORMAL:
flags = FT_LOAD_FORCE_AUTOHINT;
break;
case ASS_HINTING_NATIVE:
flags = 0;
break;
}
error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
if (error) {
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
index);
return 0;
}
if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) &&
(font->desc.italic > 55)) {
FT_GlyphSlot_Oblique(face->glyph);
}
if (!(face->style_flags & FT_STYLE_FLAG_BOLD) &&
(font->desc.bold > 80)) {
ass_glyph_embolden(face->glyph);
}
error = FT_Get_Glyph(face->glyph, &glyph);
if (error) {
ass_msg(font->library, MSGL_WARN, "Error loading glyph, index %d",
index);
return 0;
}
ass_strike_outline_glyph(face, font, glyph, deco & DECO_UNDERLINE,
deco & DECO_STRIKETHROUGH);
return glyph;
}
/**
* \brief Get kerning for the pair of glyphs.
**/
FT_Vector ass_font_get_kerning(ASS_Font *font, uint32_t c1, uint32_t c2)
{
FT_Vector v = { 0, 0 };
int i;
for (i = 0; i < font->n_faces; ++i) {
FT_Face face = font->faces[i];
int i1 = FT_Get_Char_Index(face, c1);
int i2 = FT_Get_Char_Index(face, c2);
if (i1 && i2) {
if (FT_HAS_KERNING(face))
FT_Get_Kerning(face, i1, i2, FT_KERNING_DEFAULT, &v);
return v;
}
if (i1 || i2) // these glyphs are from different font faces, no kerning information
return v;
}
return v;
}
/**
* \brief Deallocate ASS_Font
**/
void ass_font_free(ASS_Font *font)
{
int i;
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);
}

View File

@ -1,66 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_FONT_H
#define LIBASS_FONT_H
#include <stdint.h>
#include <ft2build.h>
#include FT_GLYPH_H
#include "ass.h"
#include "ass_types.h"
#define ASS_FONT_MAX_FACES 10
#define DECO_UNDERLINE 1
#define DECO_STRIKETHROUGH 2
typedef struct {
char *family;
unsigned bold;
unsigned italic;
int treat_family_as_pattern;
} ASS_FontDesc;
typedef struct {
ASS_FontDesc desc;
ASS_Library *library;
FT_Library ftlibrary;
FT_Face faces[ASS_FONT_MAX_FACES];
int n_faces;
double scale_x, scale_y; // current transform
FT_Vector v; // current shift
double size;
} ASS_Font;
// FIXME: passing the hashmap via a void pointer is very ugly.
ASS_Font *ass_font_new(void *font_cache, ASS_Library *library,
FT_Library ftlibrary, void *fc_priv,
ASS_FontDesc *desc);
void ass_font_set_transform(ASS_Font *font, double scale_x,
double scale_y, FT_Vector *v);
void ass_font_set_size(ASS_Font *font, double size);
void ass_font_get_asc_desc(ASS_Font *font, uint32_t ch, int *asc,
int *desc);
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);
#endif /* LIBASS_FONT_H */

View File

@ -1,461 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <inttypes.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include "ass_utils.h"
#include "ass.h"
#include "ass_library.h"
#include "ass_fontconfig.h"
#ifdef CONFIG_FONTCONFIG
#include <fontconfig/fontconfig.h>
#include <fontconfig/fcfreetype.h>
#endif
struct fc_instance {
#ifdef CONFIG_FONTCONFIG
FcConfig *config;
#endif
char *family_default;
char *path_default;
int index_default;
};
#ifdef CONFIG_FONTCONFIG
/**
* \brief Low-level font selection.
* \param priv private data
* \param family font family
* \param treat_family_as_pattern treat family as fontconfig pattern
* \param bold font weight value
* \param italic font slant value
* \param index out: font index inside a file
* \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,
const char *family, int treat_family_as_pattern,
unsigned bold, unsigned italic, int *index,
uint32_t code)
{
FcBool rc;
FcResult result;
FcPattern *pat = NULL, *rpat = NULL;
int r_index, r_slant, r_weight;
FcChar8 *r_family, *r_style, *r_file, *r_fullname;
FcBool r_outline, r_embolden;
FcCharSet *r_charset;
FcFontSet *fset = NULL;
int curf;
char *retval = NULL;
int family_cnt = 0;
*index = 0;
if (treat_family_as_pattern)
pat = FcNameParse((const FcChar8 *) family);
else
pat = FcPatternCreate();
if (!pat)
goto error;
if (!treat_family_as_pattern) {
FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family);
// In SSA/ASS fonts are sometimes referenced by their "full name",
// which is usually a concatenation of family name and font
// style (ex. Ottawa Bold). Full name is available from
// FontConfig pattern element FC_FULLNAME, but it is never
// used for font matching.
// Therefore, I'm removing words from the end of the name one
// by one, and adding shortened names to the pattern. It seems
// that the first value (full name in this case) has
// precedence in matching.
// An alternative approach could be to reimplement FcFontSort
// using FC_FULLNAME instead of FC_FAMILY.
family_cnt = 1;
{
char *s = strdup(family);
char *p = s + strlen(s);
while (--p > s)
if (*p == ' ' || *p == '-') {
*p = '\0';
FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) s);
++family_cnt;
}
free(s);
}
}
FcPatternAddBool(pat, FC_OUTLINE, FcTrue);
FcPatternAddInteger(pat, FC_SLANT, italic);
FcPatternAddInteger(pat, FC_WEIGHT, bold);
FcDefaultSubstitute(pat);
rc = FcConfigSubstitute(priv->config, pat, FcMatchPattern);
if (!rc)
goto error;
fset = FcFontSort(priv->config, pat, FcTrue, NULL, &result);
if (!fset)
goto error;
for (curf = 0; curf < fset->nfont; ++curf) {
FcPattern *curp = fset->fonts[curf];
result = FcPatternGetBool(curp, FC_OUTLINE, 0, &r_outline);
if (result != FcResultMatch)
continue;
if (r_outline != FcTrue)
continue;
if (!code)
break;
result = FcPatternGetCharSet(curp, FC_CHARSET, 0, &r_charset);
if (result != FcResultMatch)
continue;
if (FcCharSetHasChar(r_charset, code))
break;
}
if (curf >= fset->nfont)
goto error;
if (!treat_family_as_pattern) {
// Remove all extra family names from original pattern.
// After this, FcFontRenderPrepare will select the most relevant family
// name in case there are more than one of them.
for (; family_cnt > 1; --family_cnt)
FcPatternRemove(pat, FC_FAMILY, family_cnt - 1);
}
rpat = FcFontRenderPrepare(priv->config, pat, fset->fonts[curf]);
if (!rpat)
goto error;
result = FcPatternGetInteger(rpat, FC_INDEX, 0, &r_index);
if (result != FcResultMatch)
goto error;
*index = r_index;
result = FcPatternGetString(rpat, FC_FILE, 0, &r_file);
if (result != FcResultMatch)
goto error;
retval = strdup((const char *) r_file);
result = FcPatternGetString(rpat, FC_FAMILY, 0, &r_family);
if (result != FcResultMatch)
r_family = NULL;
result = FcPatternGetString(rpat, FC_FULLNAME, 0, &r_fullname);
if (result != FcResultMatch)
r_fullname = NULL;
if (!treat_family_as_pattern &&
!(r_family && strcasecmp((const char *) r_family, family) == 0) &&
!(r_fullname && strcasecmp((const char *) r_fullname, family) == 0))
ass_msg(library, MSGL_WARN,
"fontconfig: Selected font is not the requested one: "
"'%s' != '%s'",
(const char *) (r_fullname ? r_fullname : r_family), family);
result = FcPatternGetString(rpat, FC_STYLE, 0, &r_style);
if (result != FcResultMatch)
r_style = NULL;
result = FcPatternGetInteger(rpat, FC_SLANT, 0, &r_slant);
if (result != FcResultMatch)
r_slant = 0;
result = FcPatternGetInteger(rpat, FC_WEIGHT, 0, &r_weight);
if (result != FcResultMatch)
r_weight = 0;
result = FcPatternGetBool(rpat, FC_EMBOLDEN, 0, &r_embolden);
if (result != FcResultMatch)
r_embolden = 0;
ass_msg(library, MSGL_V,
"Font info: family '%s', style '%s', fullname '%s',"
" slant %d, weight %d%s", (const char *) r_family,
(const char *) r_style, (const char *) r_fullname, r_slant,
r_weight, r_embolden ? ", embolden" : "");
error:
if (pat)
FcPatternDestroy(pat);
if (rpat)
FcPatternDestroy(rpat);
if (fset)
FcFontSetDestroy(fset);
return retval;
}
/**
* \brief Find a font. Use default family or path if necessary.
* \param priv_ private data
* \param family font family
* \param treat_family_as_pattern treat family as fontconfig pattern
* \param bold font weight value
* \param italic font slant value
* \param index out: font index inside a file
* \param code: the character that should be present in the font, can be 0
* \return font file path
*/
char *fontconfig_select(ASS_Library *library, FCInstance *priv,
const char *family, int treat_family_as_pattern,
unsigned bold, unsigned italic, int *index,
uint32_t code)
{
char *res = 0;
if (!priv->config) {
*index = priv->index_default;
res = priv->path_default ? strdup(priv->path_default) : 0;
return res;
}
if (family && *family)
res =
_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,
italic, index, code);
if (res)
ass_msg(library, MSGL_WARN, "fontconfig_select: Using default "
"font family: (%s, %d, %d) -> %s, %d",
family, bold, italic, res, *index);
}
if (!res && priv->path_default) {
res = strdup(priv->path_default);
*index = priv->index_default;
ass_msg(library, MSGL_WARN, "fontconfig_select: Using default font: "
"(%s, %d, %d) -> %s, %d", family, bold, italic,
res, *index);
}
if (!res) {
res = _select_font(library, priv, "Arial", 0, bold, italic,
index, code);
if (res)
ass_msg(library, MSGL_WARN, "fontconfig_select: Using 'Arial' "
"font family: (%s, %d, %d) -> %s, %d", family, bold,
italic, res, *index);
}
if (res)
ass_msg(library, MSGL_V,
"fontconfig_select: (%s, %d, %d) -> %s, %d", family, bold,
italic, res, *index);
return res;
}
/**
* \brief Process memory font.
* \param priv private data
* \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.
*/
static void process_fontdata(FCInstance *priv, ASS_Library *library,
FT_Library ftlibrary, int idx)
{
int rc;
const char *name = library->fontdata[idx].name;
const char *data = library->fontdata[idx].data;
int data_size = library->fontdata[idx].size;
FT_Face face;
FcPattern *pattern;
FcFontSet *fset;
FcBool res;
int face_index, num_faces = 1;
for (face_index = 0; face_index < num_faces; ++face_index) {
rc = FT_New_Memory_Face(ftlibrary, (unsigned char *) data,
data_size, face_index, &face);
if (rc) {
ass_msg(library, MSGL_WARN, "Error opening memory font: %s",
name);
return;
}
num_faces = face->num_faces;
pattern =
FcFreeTypeQueryFace(face, (unsigned char *) name, 0,
FcConfigGetBlanks(priv->config));
if (!pattern) {
ass_msg(library, MSGL_WARN, "%s failed", "FcFreeTypeQueryFace");
FT_Done_Face(face);
return;
}
fset = FcConfigGetFonts(priv->config, FcSetSystem); // somehow it failes when asked for FcSetApplication
if (!fset) {
ass_msg(library, MSGL_WARN, "%s failed", "FcConfigGetFonts");
FT_Done_Face(face);
return;
}
res = FcFontSetAdd(fset, pattern);
if (!res) {
ass_msg(library, MSGL_WARN, "%s failed", "FcFontSetAdd");
FT_Done_Face(face);
return;
}
FT_Done_Face(face);
}
}
/**
* \brief Init fontconfig.
* \param library libass library object
* \param ftlibrary freetype library object
* \param family default font family
* \param path default font path
* \param fc whether fontconfig should be used
* \param config path to a fontconfig configuration file, or NULL
* \param update whether the fontconfig cache should be built/updated
* \return pointer to fontconfig private data
*/
FCInstance *fontconfig_init(ASS_Library *library,
FT_Library ftlibrary, const char *family,
const char *path, int fc, const char *config,
int update)
{
int rc;
FCInstance *priv = calloc(1, sizeof(FCInstance));
const char *dir = library->fonts_dir;
int i;
if (!fc) {
ass_msg(library, MSGL_WARN,
"Fontconfig disabled, only default font will be used.");
goto exit;
}
priv->config = FcConfigCreate();
rc = FcConfigParseAndLoad(priv->config, (unsigned char *) config, FcTrue);
if (!rc) {
ass_msg(library, MSGL_WARN, "No usable fontconfig configuration "
"file found, using fallback.");
FcConfigDestroy(priv->config);
priv->config = FcInitLoadConfig();
rc++;
}
if (rc && update) {
FcConfigBuildFonts(priv->config);
}
if (!rc || !priv->config) {
ass_msg(library, MSGL_FATAL,
"No valid fontconfig configuration found!");
FcConfigDestroy(priv->config);
goto exit;
}
for (i = 0; i < library->num_fontdata; ++i)
process_fontdata(priv, library, ftlibrary, i);
if (dir) {
ass_msg(library, MSGL_INFO, "Updating font cache");
rc = FcConfigAppFontAddDir(priv->config, (const FcChar8 *) dir);
if (!rc) {
ass_msg(library, MSGL_WARN, "%s failed", "FcConfigAppFontAddDir");
}
}
priv->family_default = family ? strdup(family) : NULL;
exit:
priv->path_default = path ? strdup(path) : NULL;
priv->index_default = 0;
return priv;
}
int fontconfig_update(FCInstance *priv)
{
return FcConfigBuildFonts(priv->config);
}
#else /* CONFIG_FONTCONFIG */
char *fontconfig_select(ASS_Library *library, FCInstance *priv,
const char *family, int treat_family_as_pattern,
unsigned bold, unsigned italic, int *index,
uint32_t code)
{
*index = priv->index_default;
char* res = priv->path_default ? strdup(priv->path_default) : 0;
return res;
}
FCInstance *fontconfig_init(ASS_Library *library,
FT_Library ftlibrary, const char *family,
const char *path, int fc, const char *config,
int update)
{
FCInstance *priv;
ass_msg(library, MSGL_WARN,
"Fontconfig disabled, only default font will be used.");
priv = calloc(1, sizeof(FCInstance));
priv->path_default = path ? strdup(path) : 0;
priv->index_default = 0;
return priv;
}
int fontconfig_update(FCInstance *priv)
{
// Do nothing
return 1;
}
#endif
void fontconfig_done(FCInstance *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);
}

View File

@ -1,47 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_FONTCONFIG_H
#define LIBASS_FONTCONFIG_H
#include <stdint.h>
#include "ass_types.h"
#include "ass.h"
#include <ft2build.h>
#include FT_FREETYPE_H
#ifdef CONFIG_FONTCONFIG
#include <fontconfig/fontconfig.h>
#endif
typedef struct fc_instance FCInstance;
FCInstance *fontconfig_init(ASS_Library *library,
FT_Library ftlibrary, const char *family,
const char *path, int fc, const char *config,
int update);
char *fontconfig_select(ASS_Library *library, FCInstance *priv,
const char *family, int treat_family_as_pattern,
unsigned bold, unsigned italic, int *index,
uint32_t code);
void fontconfig_done(FCInstance *priv);
int fontconfig_update(FCInstance *priv);
#endif /* LIBASS_FONTCONFIG_H */

View File

@ -1,147 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "ass.h"
#include "ass_library.h"
#include "ass_utils.h"
static void ass_msg_handler(int level, const char *fmt, va_list va, void *data)
{
if (level > MSGL_INFO)
return;
fprintf(stderr, "[ass] ");
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
}
ASS_Library *ass_library_init(void)
{
ASS_Library* lib = calloc(1, sizeof(*lib));
lib->msg_callback = ass_msg_handler;
return lib;
}
void ass_library_done(ASS_Library *priv)
{
if (priv) {
ass_set_fonts_dir(priv, NULL);
ass_set_style_overrides(priv, NULL);
ass_clear_fonts(priv);
free(priv);
}
}
void ass_set_fonts_dir(ASS_Library *priv, const char *fonts_dir)
{
if (priv->fonts_dir)
free(priv->fonts_dir);
priv->fonts_dir = fonts_dir ? strdup(fonts_dir) : 0;
}
void ass_set_extract_fonts(ASS_Library *priv, int extract)
{
priv->extract_fonts = !!extract;
}
void ass_set_style_overrides(ASS_Library *priv, char **list)
{
char **p;
char **q;
int cnt;
if (priv->style_overrides) {
for (p = priv->style_overrides; *p; ++p)
free(*p);
free(priv->style_overrides);
}
if (!list)
return;
for (p = list, cnt = 0; *p; ++p, ++cnt) {
}
priv->style_overrides = malloc((cnt + 1) * sizeof(char *));
for (p = list, q = priv->style_overrides; *p; ++p, ++q)
*q = strdup(*p);
priv->style_overrides[cnt] = NULL;
}
static void grow_array(void **array, int nelem, size_t elsize)
{
if (!(nelem & 31))
*array = realloc(*array, (nelem + 32) * elsize);
}
void ass_add_font(ASS_Library *priv, char *name, char *data, int size)
{
int idx = priv->num_fontdata;
if (!name || !data || !size)
return;
grow_array((void **) &priv->fontdata, priv->num_fontdata,
sizeof(*priv->fontdata));
priv->fontdata[idx].name = strdup(name);
priv->fontdata[idx].data = malloc(size);
memcpy(priv->fontdata[idx].data, data, size);
priv->fontdata[idx].size = size;
priv->num_fontdata++;
}
void ass_clear_fonts(ASS_Library *priv)
{
int i;
for (i = 0; i < priv->num_fontdata; ++i) {
free(priv->fontdata[i].name);
free(priv->fontdata[i].data);
}
free(priv->fontdata);
priv->fontdata = NULL;
priv->num_fontdata = 0;
}
/*
* Register a message callback function with libass. Without setting one,
* a default handler is used which prints everything with MSGL_INFO or
* higher to the standard output.
*
* \param msg_cb the callback function
* \param data additional data that will be passed to the callback
*/
void ass_set_message_cb(ASS_Library *priv,
void (*msg_cb)(int, const char *, va_list, void *),
void *data)
{
if (msg_cb) {
priv->msg_callback = msg_cb;
priv->msg_callback_data = data;
}
}

View File

@ -1,43 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_LIBRARY_H
#define LIBASS_LIBRARY_H
#include <stdarg.h>
typedef struct {
char *name;
char *data;
int size;
} ASS_Fontdata;
struct ass_library {
char *fonts_dir;
int extract_fonts;
char **style_overrides;
ASS_Fontdata *fontdata;
int num_fontdata;
void (*msg_callback)(int, const char *, va_list, void *);
void *msg_callback_data;
};
#endif /* LIBASS_LIBRARY_H */

View File

@ -1,926 +0,0 @@
/*
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ass_render.h"
#include "ass_parse.h"
#define MAX_BE 127
#define NBSP 0xa0 // unicode non-breaking space character
#define skip_to(x) while ((*p != (x)) && (*p != '}') && (*p != 0)) { ++p;}
#define skip(x) if (*p == (x)) ++p; else { return p; }
#define skipopt(x) if (*p == (x)) { ++p; }
/**
* \brief Check if starting part of (*p) matches sample.
* If true, shift p to the first symbol after the matching part.
*/
static inline int mystrcmp(char **p, const char *sample)
{
int len = strlen(sample);
if (strncmp(*p, sample, len) == 0) {
(*p) += len;
return 1;
} else
return 0;
}
static void change_font_size(ASS_Renderer *render_priv, double sz)
{
double size = sz * render_priv->font_scale;
if (size < 1)
size = 1;
else if (size > render_priv->height * 2)
size = render_priv->height * 2;
ass_font_set_size(render_priv->state.font, size);
render_priv->state.font_size = sz;
}
/**
* \brief Change current font, using setting from render_priv->state.
*/
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;
val = render_priv->state.bold;
// 0 = normal, 1 = bold, >1 = exact weight
if (val == 1 || val == -1)
val = 200; // bold
else if (val <= 0)
val = 80; // normal
desc.bold = val;
val = render_priv->state.italic;
if (val == 1 || val == -1)
val = 110; // italic
else if (val <= 0)
val = 0; // normal
desc.italic = val;
render_priv->state.font =
ass_font_new(render_priv->cache.font_cache, render_priv->library,
render_priv->ftlibrary, render_priv->fontconfig_priv,
&desc);
free(desc.family);
if (render_priv->state.font)
change_font_size(render_priv, render_priv->state.font_size);
}
/**
* \brief Change border width
* negative value resets border to style value
*/
void change_border(ASS_Renderer *render_priv, double border_x,
double border_y)
{
int bord;
if (!render_priv->state.font)
return;
if (border_x < 0 && border_y < 0) {
if (render_priv->state.style->BorderStyle == 1 ||
render_priv->state.style->BorderStyle == 3)
border_x = border_y = render_priv->state.style->Outline;
else
border_x = border_y = 1.;
}
render_priv->state.border_x = border_x;
render_priv->state.border_y = border_y;
bord = 64 * border_x * render_priv->border_scale;
if (bord > 0 && border_x == border_y) {
if (!render_priv->state.stroker) {
int error;
error =
FT_Stroker_New(render_priv->ftlibrary,
&render_priv->state.stroker);
if (error) {
ass_msg(render_priv->library, MSGL_V,
"failed to get stroker");
render_priv->state.stroker = 0;
}
}
if (render_priv->state.stroker)
FT_Stroker_Set(render_priv->state.stroker, bord,
FT_STROKER_LINECAP_ROUND,
FT_STROKER_LINEJOIN_ROUND, 0);
} else {
FT_Stroker_Done(render_priv->state.stroker);
render_priv->state.stroker = 0;
}
}
/**
* \brief Calculate a weighted average of two colors
* calculates c1*(1-a) + c2*a, but separately for each component except alpha
*/
static void change_color(uint32_t *var, uint32_t new, double pwr)
{
(*var) = ((uint32_t) (_r(*var) * (1 - pwr) + _r(new) * pwr) << 24) +
((uint32_t) (_g(*var) * (1 - pwr) + _g(new) * pwr) << 16) +
((uint32_t) (_b(*var) * (1 - pwr) + _b(new) * pwr) << 8) + _a(*var);
}
// like change_color, but for alpha component only
inline void change_alpha(uint32_t *var, uint32_t new, double pwr)
{
*var =
(_r(*var) << 24) + (_g(*var) << 16) + (_b(*var) << 8) +
(uint32_t) (_a(*var) * (1 - pwr) + _a(new) * pwr);
}
/**
* \brief Multiply two alpha values
* \param a first value
* \param b second value
* \return result of multiplication
* Parameters and result are limited by 0xFF.
*/
inline uint32_t mult_alpha(uint32_t a, uint32_t b)
{
return 0xFF - (0xFF - a) * (0xFF - b) / 0xFF;
}
/**
* \brief Calculate alpha value by piecewise linear function
* Used for \fad, \fade implementation.
*/
static unsigned
interpolate_alpha(long long now, long long t1, long long t2, long long t3,
long long t4, unsigned a1, unsigned a2, unsigned a3)
{
unsigned a;
double cf;
if (now <= t1) {
a = a1;
} else if (now >= t4) {
a = a3;
} else if (now < t2) { // and > t1
cf = ((double) (now - t1)) / (t2 - t1);
a = a1 * (1 - cf) + a2 * cf;
} else if (now > t3) {
cf = ((double) (now - t3)) / (t4 - t3);
a = a2 * (1 - cf) + a3 * cf;
} else { // t2 <= now <= t3
a = a2;
}
return a;
}
/**
* Parse a vector clip into an outline, using the proper scaling
* parameters. Translate it to correct for screen borders, if needed.
*/
static char *parse_vector_clip(ASS_Renderer *render_priv, char *p)
{
int scale = 1;
int res = 0;
ASS_Drawing *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('(');
res = mystrtoi(&p, &scale);
skipopt(',')
if (!res)
scale = 1;
drawing->scale = scale;
drawing->scale_x = render_priv->font_scale_x * render_priv->font_scale;
drawing->scale_y = render_priv->font_scale;
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;
}
/**
* \brief Parse style override tag.
* \param p string to parse
* \param pwr multiplier for some tag effects (comes from \t tags)
*/
static char *parse_tag(ASS_Renderer *render_priv, char *p, double pwr)
{
skip_to('\\');
skip('\\');
if ((*p == '}') || (*p == 0))
return p;
// New tags introduced in vsfilter 2.39
if (mystrcmp(&p, "xbord")) {
double val;
if (mystrtod(&p, &val))
val = render_priv->state.border_x * (1 - pwr) + val * pwr;
else
val = -1.;
change_border(render_priv, val, render_priv->state.border_y);
} else if (mystrcmp(&p, "ybord")) {
double val;
if (mystrtod(&p, &val))
val = render_priv->state.border_y * (1 - pwr) + val * pwr;
else
val = -1.;
change_border(render_priv, render_priv->state.border_x, val);
} else if (mystrcmp(&p, "xshad")) {
double val;
if (mystrtod(&p, &val))
val = render_priv->state.shadow_x * (1 - pwr) + val * pwr;
else
val = 0.;
render_priv->state.shadow_x = val;
} else if (mystrcmp(&p, "yshad")) {
double val;
if (mystrtod(&p, &val))
val = render_priv->state.shadow_y * (1 - pwr) + val * pwr;
else
val = 0.;
render_priv->state.shadow_y = val;
} else if (mystrcmp(&p, "fax")) {
double val;
if (mystrtod(&p, &val))
render_priv->state.fax =
val * pwr + render_priv->state.fax * (1 - pwr);
else
render_priv->state.fax = 0.;
} else if (mystrcmp(&p, "fay")) {
double val;
if (mystrtod(&p, &val))
render_priv->state.fay =
val * pwr + render_priv->state.fay * (1 - pwr);
else
render_priv->state.fay = 0.;
} else if (mystrcmp(&p, "iclip")) {
int x0, y0, x1, y1;
int res = 1;
char *start = p;
skipopt('(');
res &= mystrtoi(&p, &x0);
skipopt(',');
res &= mystrtoi(&p, &y0);
skipopt(',');
res &= mystrtoi(&p, &x1);
skipopt(',');
res &= mystrtoi(&p, &y1);
skipopt(')');
if (res) {
render_priv->state.clip_x0 =
render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr;
render_priv->state.clip_x1 =
render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr;
render_priv->state.clip_y0 =
render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr;
render_priv->state.clip_y1 =
render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr;
render_priv->state.clip_mode = 1;
} else if (!render_priv->state.clip_drawing) {
p = parse_vector_clip(render_priv, start);
render_priv->state.clip_drawing_mode = 1;
} else
render_priv->state.clip_mode = 0;
} else if (mystrcmp(&p, "blur")) {
double val;
if (mystrtod(&p, &val)) {
val = render_priv->state.blur * (1 - pwr) + val * pwr;
val = (val < 0) ? 0 : val;
val = (val > BLUR_MAX_RADIUS) ? BLUR_MAX_RADIUS : val;
render_priv->state.blur = val;
} else
render_priv->state.blur = 0.0;
// ASS standard tags
} else if (mystrcmp(&p, "fsc")) {
char tp = *p++;
double val;
if (tp == 'x') {
if (mystrtod(&p, &val)) {
val /= 100;
render_priv->state.scale_x =
render_priv->state.scale_x * (1 - pwr) + val * pwr;
} else
render_priv->state.scale_x =
render_priv->state.style->ScaleX;
} else if (tp == 'y') {
if (mystrtod(&p, &val)) {
val /= 100;
render_priv->state.scale_y =
render_priv->state.scale_y * (1 - pwr) + val * pwr;
} else
render_priv->state.scale_y =
render_priv->state.style->ScaleY;
}
} else if (mystrcmp(&p, "fsp")) {
double val;
if (mystrtod(&p, &val))
render_priv->state.hspacing =
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 * (1 - pwr) + val * pwr;
else
val = render_priv->state.style->FontSize;
if (render_priv->state.font)
change_font_size(render_priv, val);
} else if (mystrcmp(&p, "bord")) {
double val;
if (mystrtod(&p, &val)) {
if (render_priv->state.border_x == render_priv->state.border_y)
val = render_priv->state.border_x * (1 - pwr) + val * pwr;
} else
val = -1.; // reset to default
change_border(render_priv, val, val);
} else if (mystrcmp(&p, "move")) {
double x1, x2, y1, y2;
long long t1, t2, delta_t, t;
double x, y;
double k;
skip('(');
mystrtod(&p, &x1);
skip(',');
mystrtod(&p, &y1);
skip(',');
mystrtod(&p, &x2);
skip(',');
mystrtod(&p, &y2);
if (*p == ',') {
skip(',');
mystrtoll(&p, &t1);
skip(',');
mystrtoll(&p, &t2);
ass_msg(render_priv->library, MSGL_DBG2,
"movement6: (%f, %f) -> (%f, %f), (%" PRId64 " .. %"
PRId64 ")\n", x1, y1, x2, y2, (int64_t) t1,
(int64_t) t2);
} else {
t1 = 0;
t2 = render_priv->state.event->Duration;
ass_msg(render_priv->library, MSGL_DBG2,
"movement: (%f, %f) -> (%f, %f)", x1, y1, x2, y2);
}
skip(')');
delta_t = t2 - t1;
t = render_priv->time - render_priv->state.event->Start;
if (t < t1)
k = 0.;
else if (t > t2)
k = 1.;
else
k = ((double) (t - t1)) / delta_t;
x = k * (x2 - x1) + x1;
y = k * (y2 - y1) + y1;
if (render_priv->state.evt_type != EVENT_POSITIONED) {
render_priv->state.pos_x = x;
render_priv->state.pos_y = y;
render_priv->state.detect_collisions = 0;
render_priv->state.evt_type = EVENT_POSITIONED;
}
} else if (mystrcmp(&p, "frx")) {
double val;
if (mystrtod(&p, &val)) {
val *= M_PI / 180;
render_priv->state.frx =
val * pwr + render_priv->state.frx * (1 - pwr);
} else
render_priv->state.frx = 0.;
} else if (mystrcmp(&p, "fry")) {
double val;
if (mystrtod(&p, &val)) {
val *= M_PI / 180;
render_priv->state.fry =
val * pwr + render_priv->state.fry * (1 - pwr);
} else
render_priv->state.fry = 0.;
} else if (mystrcmp(&p, "frz") || mystrcmp(&p, "fr")) {
double val;
if (mystrtod(&p, &val)) {
val *= M_PI / 180;
render_priv->state.frz =
val * pwr + render_priv->state.frz * (1 - pwr);
} else
render_priv->state.frz =
M_PI * render_priv->state.style->Angle / 180.;
} else if (mystrcmp(&p, "fn")) {
char *start = p;
char *family;
skip_to('\\');
if (p > start) {
family = malloc(p - start + 1);
strncpy(family, start, p - start);
family[p - start] = '\0';
} else
family = strdup(render_priv->state.style->FontName);
if (render_priv->state.family)
free(render_priv->state.family);
render_priv->state.family = family;
update_font(render_priv);
} else if (mystrcmp(&p, "alpha")) {
uint32_t val;
int i;
int hex = render_priv->track->track_type == TRACK_TYPE_ASS;
if (strtocolor(render_priv->library, &p, &val, hex)) {
unsigned char a = val >> 24;
for (i = 0; i < 4; ++i)
change_alpha(&render_priv->state.c[i], a, pwr);
} else {
change_alpha(&render_priv->state.c[0],
render_priv->state.style->PrimaryColour, pwr);
change_alpha(&render_priv->state.c[1],
render_priv->state.style->SecondaryColour, pwr);
change_alpha(&render_priv->state.c[2],
render_priv->state.style->OutlineColour, pwr);
change_alpha(&render_priv->state.c[3],
render_priv->state.style->BackColour, pwr);
}
// FIXME: simplify
} else if (mystrcmp(&p, "an")) {
int val;
if (mystrtoi(&p, &val) && val) {
int v = (val - 1) / 3; // 0, 1 or 2 for vertical alignment
ass_msg(render_priv->library, MSGL_DBG2, "an %d", val);
if (v != 0)
v = 3 - v;
val = ((val - 1) % 3) + 1; // horizontal alignment
val += v * 4;
ass_msg(render_priv->library, MSGL_DBG2, "align %d", val);
render_priv->state.alignment = val;
} else
render_priv->state.alignment =
render_priv->state.style->Alignment;
} else if (mystrcmp(&p, "a")) {
int val;
if (mystrtoi(&p, &val) && val)
// take care of a vsfilter quirk: handle illegal \a8 like \a5
render_priv->state.alignment = (val == 8) ? 5 : val;
else
render_priv->state.alignment =
render_priv->state.style->Alignment;
} else if (mystrcmp(&p, "pos")) {
double v1, v2;
skip('(');
mystrtod(&p, &v1);
skip(',');
mystrtod(&p, &v2);
skip(')');
ass_msg(render_priv->library, MSGL_DBG2, "pos(%f, %f)", v1, v2);
if (render_priv->state.evt_type == EVENT_POSITIONED) {
ass_msg(render_priv->library, MSGL_V, "Subtitle has a new \\pos "
"after \\move or \\pos, ignoring");
} else {
render_priv->state.evt_type = EVENT_POSITIONED;
render_priv->state.detect_collisions = 0;
render_priv->state.pos_x = v1;
render_priv->state.pos_y = v2;
}
} else if (mystrcmp(&p, "fad")) {
int a1, a2, a3;
long long t1, t2, t3, t4;
if (*p == 'e')
++p; // either \fad or \fade
skip('(');
mystrtoi(&p, &a1);
skip(',');
mystrtoi(&p, &a2);
if (*p == ')') {
// 2-argument version (\fad, according to specs)
// a1 and a2 are fade-in and fade-out durations
t1 = 0;
t4 = render_priv->state.event->Duration;
t2 = a1;
t3 = t4 - a2;
a1 = 0xFF;
a2 = 0;
a3 = 0xFF;
} else {
// 6-argument version (\fade)
// a1 and a2 (and a3) are opacity values
skip(',');
mystrtoi(&p, &a3);
skip(',');
mystrtoll(&p, &t1);
skip(',');
mystrtoll(&p, &t2);
skip(',');
mystrtoll(&p, &t3);
skip(',');
mystrtoll(&p, &t4);
}
skip(')');
render_priv->state.fade =
interpolate_alpha(render_priv->time -
render_priv->state.event->Start, t1, t2,
t3, t4, a1, a2, a3);
} else if (mystrcmp(&p, "org")) {
int v1, v2;
skip('(');
mystrtoi(&p, &v1);
skip(',');
mystrtoi(&p, &v2);
skip(')');
ass_msg(render_priv->library, MSGL_DBG2, "org(%d, %d)", v1, v2);
if (!render_priv->state.have_origin) {
render_priv->state.org_x = v1;
render_priv->state.org_y = v2;
render_priv->state.have_origin = 1;
render_priv->state.detect_collisions = 0;
}
} else if (mystrcmp(&p, "t")) {
double v[3];
int v1, v2;
double v3;
int cnt;
long long t1, t2, t, delta_t;
double k;
skip('(');
for (cnt = 0; cnt < 3; ++cnt) {
if (*p == '\\')
break;
v[cnt] = strtod(p, &p);
skip(',');
}
if (cnt == 3) {
v1 = v[0];
v2 = (v[1] < v1) ? render_priv->state.event->Duration : v[1];
v3 = v[2];
} else if (cnt == 2) {
v1 = v[0];
v2 = (v[1] < v1) ? render_priv->state.event->Duration : v[1];
v3 = 1.;
} else if (cnt == 1) {
v1 = 0;
v2 = render_priv->state.event->Duration;
v3 = v[0];
} else { // cnt == 0
v1 = 0;
v2 = render_priv->state.event->Duration;
v3 = 1.;
}
render_priv->state.detect_collisions = 0;
t1 = v1;
t2 = v2;
delta_t = v2 - v1;
if (v3 < 0.)
v3 = 0.;
t = render_priv->time - render_priv->state.event->Start; // FIXME: move to render_context
if (t <= t1)
k = 0.;
else if (t >= t2)
k = 1.;
else {
assert(delta_t != 0.);
k = pow(((double) (t - t1)) / delta_t, v3);
}
while (*p == '\\')
p = parse_tag(render_priv, p, k); // maybe k*pwr ? no, specs forbid nested \t's
skip_to(')'); // in case there is some unknown tag or a comment
skip(')');
} else if (mystrcmp(&p, "clip")) {
char *start = p;
int x0, y0, x1, y1;
int res = 1;
skipopt('(');
res &= mystrtoi(&p, &x0);
skipopt(',');
res &= mystrtoi(&p, &y0);
skipopt(',');
res &= mystrtoi(&p, &x1);
skipopt(',');
res &= mystrtoi(&p, &y1);
skipopt(')');
if (res) {
render_priv->state.clip_x0 =
render_priv->state.clip_x0 * (1 - pwr) + x0 * pwr;
render_priv->state.clip_x1 =
render_priv->state.clip_x1 * (1 - pwr) + x1 * pwr;
render_priv->state.clip_y0 =
render_priv->state.clip_y0 * (1 - pwr) + y0 * pwr;
render_priv->state.clip_y1 =
render_priv->state.clip_y1 * (1 - pwr) + y1 * pwr;
// Might be a vector clip
} else if (!render_priv->state.clip_drawing) {
p = parse_vector_clip(render_priv, start);
render_priv->state.clip_drawing_mode = 0;
} else {
render_priv->state.clip_x0 = 0;
render_priv->state.clip_y0 = 0;
render_priv->state.clip_x1 = render_priv->track->PlayResX;
render_priv->state.clip_y1 = render_priv->track->PlayResY;
}
} else if (mystrcmp(&p, "c")) {
uint32_t val;
int hex = render_priv->track->track_type == TRACK_TYPE_ASS;
if (!strtocolor(render_priv->library, &p, &val, hex))
val = render_priv->state.style->PrimaryColour;
ass_msg(render_priv->library, MSGL_DBG2, "color: %X", val);
change_color(&render_priv->state.c[0], val, pwr);
} else if ((*p >= '1') && (*p <= '4') && (++p)
&& (mystrcmp(&p, "c") || mystrcmp(&p, "a"))) {
char n = *(p - 2);
int cidx = n - '1';
char cmd = *(p - 1);
uint32_t val;
int hex = render_priv->track->track_type == TRACK_TYPE_ASS;
assert((n >= '1') && (n <= '4'));
if (!strtocolor(render_priv->library, &p, &val, hex))
switch (n) {
case '1':
val = render_priv->state.style->PrimaryColour;
break;
case '2':
val = render_priv->state.style->SecondaryColour;
break;
case '3':
val = render_priv->state.style->OutlineColour;
break;
case '4':
val = render_priv->state.style->BackColour;
break;
default:
val = 0;
break; // impossible due to assert; avoid compilation warning
}
switch (cmd) {
case 'c':
change_color(render_priv->state.c + cidx, val, pwr);
break;
case 'a':
change_alpha(render_priv->state.c + cidx, val >> 24, pwr);
break;
default:
ass_msg(render_priv->library, MSGL_WARN, "Bad command: %c%c",
n, cmd);
break;
}
ass_msg(render_priv->library, MSGL_DBG2, "single c/a at %f: %c%c = %X",
pwr, n, cmd, render_priv->state.c[cidx]);
} else if (mystrcmp(&p, "r")) {
reset_render_context(render_priv);
} else if (mystrcmp(&p, "be")) {
int val;
if (mystrtoi(&p, &val)) {
// Clamp to a safe upper limit, since high values need excessive CPU
val = (val < 0) ? 0 : val;
val = (val > MAX_BE) ? MAX_BE : val;
render_priv->state.be = val;
} else
render_priv->state.be = 0;
} else if (mystrcmp(&p, "b")) {
int b;
if (mystrtoi(&p, &b)) {
if (pwr >= .5)
render_priv->state.bold = b;
} else
render_priv->state.bold = render_priv->state.style->Bold;
update_font(render_priv);
} else if (mystrcmp(&p, "i")) {
int i;
if (mystrtoi(&p, &i)) {
if (pwr >= .5)
render_priv->state.italic = i;
} else
render_priv->state.italic = render_priv->state.style->Italic;
update_font(render_priv);
} else if (mystrcmp(&p, "kf") || mystrcmp(&p, "K")) {
int val = 0;
mystrtoi(&p, &val);
render_priv->state.effect_type = EF_KARAOKE_KF;
if (render_priv->state.effect_timing)
render_priv->state.effect_skip_timing +=
render_priv->state.effect_timing;
render_priv->state.effect_timing = val * 10;
} else if (mystrcmp(&p, "ko")) {
int val = 0;
mystrtoi(&p, &val);
render_priv->state.effect_type = EF_KARAOKE_KO;
if (render_priv->state.effect_timing)
render_priv->state.effect_skip_timing +=
render_priv->state.effect_timing;
render_priv->state.effect_timing = val * 10;
} else if (mystrcmp(&p, "k")) {
int val = 0;
mystrtoi(&p, &val);
render_priv->state.effect_type = EF_KARAOKE;
if (render_priv->state.effect_timing)
render_priv->state.effect_skip_timing +=
render_priv->state.effect_timing;
render_priv->state.effect_timing = val * 10;
} else if (mystrcmp(&p, "shad")) {
double val;
if (mystrtod(&p, &val)) {
if (render_priv->state.shadow_x == render_priv->state.shadow_y)
val = render_priv->state.shadow_x * (1 - pwr) + val * pwr;
} else
val = 0.;
render_priv->state.shadow_x = render_priv->state.shadow_y = val;
} else if (mystrcmp(&p, "s")) {
int val;
if (mystrtoi(&p, &val) && val)
render_priv->state.flags |= DECO_STRIKETHROUGH;
else
render_priv->state.flags &= ~DECO_STRIKETHROUGH;
} else if (mystrcmp(&p, "u")) {
int val;
if (mystrtoi(&p, &val) && val)
render_priv->state.flags |= DECO_UNDERLINE;
else
render_priv->state.flags &= ~DECO_UNDERLINE;
} else if (mystrcmp(&p, "pbo")) {
double val = 0;
if (mystrtod(&p, &val))
render_priv->state.drawing->pbo = val;
} else if (mystrcmp(&p, "p")) {
int val;
if (!mystrtoi(&p, &val))
val = 0;
if (val)
render_priv->state.drawing->scale = val;
render_priv->state.drawing_mode = !!val;
} else if (mystrcmp(&p, "q")) {
int val;
if (!mystrtoi(&p, &val))
val = render_priv->track->WrapStyle;
render_priv->state.wrap_style = val;
}
return p;
}
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event)
{
int v[4];
int cnt;
char *p = event->Effect;
if (!p || !*p)
return;
cnt = 0;
while (cnt < 4 && (p = strchr(p, ';'))) {
v[cnt++] = atoi(++p);
}
if (strncmp(event->Effect, "Banner;", 7) == 0) {
int delay;
if (cnt < 1) {
ass_msg(render_priv->library, MSGL_V,
"Error parsing effect: '%s'", event->Effect);
return;
}
if (cnt >= 2 && v[1] == 0) // right-to-left
render_priv->state.scroll_direction = SCROLL_RL;
else // left-to-right
render_priv->state.scroll_direction = SCROLL_LR;
delay = v[0];
if (delay == 0)
delay = 1; // ?
render_priv->state.scroll_shift =
(render_priv->time - render_priv->state.event->Start) / delay;
render_priv->state.evt_type = EVENT_HSCROLL;
return;
}
if (strncmp(event->Effect, "Scroll up;", 10) == 0) {
render_priv->state.scroll_direction = SCROLL_BT;
} else if (strncmp(event->Effect, "Scroll down;", 12) == 0) {
render_priv->state.scroll_direction = SCROLL_TB;
} else {
ass_msg(render_priv->library, MSGL_V,
"Unknown transition effect: '%s'", event->Effect);
return;
}
// parse scroll up/down parameters
{
int delay;
int y0, y1;
if (cnt < 3) {
ass_msg(render_priv->library, MSGL_V,
"Error parsing effect: '%s'", event->Effect);
return;
}
delay = v[2];
if (delay == 0)
delay = 1; // ?
render_priv->state.scroll_shift =
(render_priv->time - render_priv->state.event->Start) / delay;
if (v[0] < v[1]) {
y0 = v[0];
y1 = v[1];
} else {
y0 = v[1];
y1 = v[0];
}
if (y1 == 0)
y1 = render_priv->track->PlayResY; // y0=y1=0 means fullscreen scrolling
render_priv->state.clip_y0 = y0;
render_priv->state.clip_y1 = y1;
render_priv->state.evt_type = EVENT_VSCROLL;
render_priv->state.detect_collisions = 0;
}
}
/**
* \brief Get next ucs4 char from string, parsing and executing style overrides
* \param str string pointer
* \return ucs4 code of the next char
* On return str points to the unparsed part of the string
*/
unsigned get_next_char(ASS_Renderer *render_priv, char **str)
{
char *p = *str;
unsigned chr;
if (*p == '{') { // '\0' goes here
p++;
while (1) {
p = parse_tag(render_priv, p, 1.);
if (*p == '}') { // end of tag
p++;
if (*p == '{') {
p++;
continue;
} else
break;
} else if (*p != '\\')
ass_msg(render_priv->library, MSGL_V,
"Unable to parse: '%s'", p);
if (*p == 0)
break;
}
}
if (*p == '\t') {
++p;
*str = p;
return ' ';
}
if (*p == '\\') {
if ((p[1] == 'N') || ((p[1] == 'n') &&
(render_priv->state.wrap_style == 2))) {
p += 2;
*str = p;
return '\n';
} else if (p[1] == 'n') {
p += 2;
*str = p;
return ' ';
} else if (p[1] == 'h') {
p += 2;
*str = p;
return NBSP;
}
}
chr = ass_utf8_get_char((char **) &p);
*str = p;
return chr;
}

View File

@ -1,38 +0,0 @@
/*
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* 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.
*/
#ifndef LIBASS_PARSE_H
#define LIBASS_PARSE_H
#define BLUR_MAX_RADIUS 100.0
#define _r(c) ((c) >> 24)
#define _g(c) (((c) >> 16) & 0xFF)
#define _b(c) (((c) >> 8) & 0xFF)
#define _a(c) ((c) & 0xFF)
void update_font(ASS_Renderer *render_priv);
void change_border(ASS_Renderer *render_priv, double border_x,
double border_y);
void apply_transition_effects(ASS_Renderer *render_priv, ASS_Event *event);
unsigned get_next_char(ASS_Renderer *render_priv, char **str);
extern void change_alpha(uint32_t *var, uint32_t new, double pwr);
extern uint32_t mult_alpha(uint32_t a, uint32_t b);
#endif /* LIBASS_PARSE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,262 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
* Copyright (C) 2009 Grigori Goronzy <greg@geekmind.org>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_RENDER_H
#define LIBASS_RENDER_H
#include <inttypes.h>
#include <ft2build.h>
#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"
typedef struct {
double xMin;
double xMax;
double yMin;
double yMax;
} DBBox;
typedef struct {
double x;
double y;
} DVector;
typedef struct free_list {
void *object;
struct free_list *next;
} FreeList;
typedef struct {
int frame_width;
int frame_height;
double font_size_coeff; // font size multiplier
double line_spacing; // additional line spacing (in frame pixels)
int top_margin; // height of top margin. Everything except toptitles is shifted down by top_margin.
int bottom_margin; // height of bottom margin. (frame_height - top_margin - bottom_margin) is original video height.
int left_margin;
int right_margin;
int use_margins; // 0 - place all subtitles inside original frame
// 1 - use margins for placing toptitles and subtitles
double aspect; // frame aspect ratio, d_width / d_height.
double storage_aspect; // pixel ratio of the source image
ASS_Hinting hinting;
char *default_font;
char *default_family;
} ASS_Settings;
// a rendered event
typedef struct {
ASS_Image *imgs;
int top, height, left, width;
int detect_collisions;
int shift_direction;
ASS_Event *event;
} EventImages;
typedef enum {
EF_NONE = 0,
EF_KARAOKE,
EF_KARAOKE_KF,
EF_KARAOKE_KO
} Effect;
// describes a glyph
// GlyphInfo and TextInfo are used for text centering and word-wrapping operations
typedef struct {
unsigned symbol;
unsigned skip; // skip glyph when layouting text
FT_Glyph glyph;
FT_Glyph outline_glyph;
Bitmap *bm; // glyph bitmap
Bitmap *bm_o; // outline bitmap
Bitmap *bm_s; // shadow bitmap
FT_BBox bbox;
FT_Vector pos;
char linebreak; // the first (leading) glyph of some line ?
uint32_t c[4]; // colors
FT_Vector advance; // 26.6
Effect effect_type;
int effect_timing; // time duration of current karaoke word
// after process_karaoke_effects: distance in pixels from the glyph origin.
// part of the glyph to the left of it is displayed in a different color.
int effect_skip_timing; // delay after the end of last karaoke word
int asc, desc; // font max ascender and descender
int be; // blur edges
double blur; // gaussian blur
double shadow_x;
double shadow_y;
double frx, fry, frz; // rotation
double fax, fay; // text shearing
BitmapHashKey hash_key;
} GlyphInfo;
typedef struct {
double asc, desc;
} LineInfo;
typedef struct {
GlyphInfo *glyphs;
int length;
LineInfo *lines;
int n_lines;
double height;
int max_glyphs;
int max_lines;
} TextInfo;
// Renderer state.
// Values like current font face, color, screen position, clipping and so on are stored here.
typedef struct {
ASS_Event *event;
ASS_Style *style;
ASS_Font *font;
char *font_path;
double font_size;
int flags; // decoration flags (underline/strike-through)
FT_Stroker stroker;
int alignment; // alignment overrides go here; if zero, style value will be used
double frx, fry, frz;
double fax, fay; // text shearing
enum {
EVENT_NORMAL, // "normal" top-, sub- or mid- title
EVENT_POSITIONED, // happens after pos(,), margins are ignored
EVENT_HSCROLL, // "Banner" transition effect, text_width is unlimited
EVENT_VSCROLL // "Scroll up", "Scroll down" transition effects
} evt_type;
double pos_x, pos_y; // position
double org_x, org_y; // origin
char have_origin; // origin is explicitly defined; if 0, get_base_point() is used
double scale_x, scale_y;
double hspacing; // distance between letters, in pixels
double border_x; // outline width
double border_y;
uint32_t c[4]; // colors(Primary, Secondary, so on) in RGBA
int clip_x0, clip_y0, clip_x1, clip_y1;
char clip_mode; // 1 = iclip
char detect_collisions;
uint32_t fade; // alpha from \fad
char be; // blur edges
double blur; // gaussian blur
double shadow_x;
double shadow_y;
int drawing_mode; // not implemented; when != 0 text is discarded, except for style override tags
ASS_Drawing *drawing; // current drawing
ASS_Drawing *clip_drawing; // clip vector
int clip_drawing_mode; // 0 = regular clip, 1 = inverse clip
Effect effect_type;
int effect_timing;
int effect_skip_timing;
enum {
SCROLL_LR, // left-to-right
SCROLL_RL,
SCROLL_TB, // top-to-bottom
SCROLL_BT
} scroll_direction; // for EVENT_HSCROLL, EVENT_VSCROLL
int scroll_shift;
// face properties
char *family;
unsigned bold;
unsigned italic;
int treat_family_as_pattern;
int wrap_style;
} RenderContext;
typedef struct {
Hashmap *font_cache;
Hashmap *glyph_cache;
Hashmap *bitmap_cache;
Hashmap *composite_cache;
size_t glyph_max;
size_t bitmap_max_size;
} CacheStore;
struct ass_renderer {
ASS_Library *library;
FT_Library ftlibrary;
FCInstance *fontconfig_priv;
ASS_Settings settings;
int render_id;
ASS_SynthPriv *synth_priv;
ASS_Image *images_root; // rendering result is stored here
ASS_Image *prev_images_root;
EventImages *eimg; // temporary buffer for sorting rendered events
int eimg_size; // allocated buffer size
// frame-global data
int width, height; // screen dimensions
int orig_height; // frame height ( = screen height - margins )
int orig_width; // frame width ( = screen width - margins )
int orig_height_nocrop; // frame height ( = screen height - margins + cropheight)
int orig_width_nocrop; // frame width ( = screen width - margins + cropwidth)
ASS_Track *track;
long long time; // frame's timestamp, ms
double font_scale;
double font_scale_x; // x scale applied to all glyphs to preserve text aspect ratio
double border_scale;
RenderContext state;
TextInfo text_info;
CacheStore cache;
FreeList *free_head;
FreeList *free_tail;
};
typedef struct render_priv {
int top, height, left, width;
int render_id;
} RenderPriv;
typedef struct {
int x0;
int y0;
int x1;
int y1;
} Rect;
typedef struct {
int a, b; // top and height
int ha, hb; // left and width
} Segment;
void reset_render_context(ASS_Renderer *render_priv);
#endif /* LIBASS_RENDER_H */

View File

@ -1,247 +0,0 @@
/*
* Copyright (c) 1988-1993 The Regents of the University of California.
* Copyright (c) 1994 Sun Microsystems, Inc.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*
*/
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
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.
*/
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. */
1.0e4,
1.0e8,
1.0e16,
1.0e32,
1.0e64,
1.0e128,
1.0e256
};
/*
*----------------------------------------------------------------------
*
* strtod --
*
* This procedure converts a floating-point number from an ASCII
* decimal representation to internal double-precision format.
*
* Results:
* The return value is the double-precision floating-point
* representation of the characters in string. If endPtr isn't
* NULL, then *endPtr is filled in with the address of the
* next character after the last one that was part of the
* floating-point number.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
double
ass_strtod(string, endPtr)
const char *string; /* A decimal ASCII floating-point number,
* optionally preceded by white space.
* Must have form "-I.FE-X", where I is the
* integer part of the mantissa, F is the
* fractional part of the mantissa, and X
* is the exponent. Either of the signs
* may be "+", "-", or omitted. Either I
* or F may be omitted, or both. The decimal
* point isn't necessary unless F is present.
* The "E" may actually be an "e". E and X
* may both be omitted (but not just one).
*/
char **endPtr; /* If non-NULL, store terminating character's
* address here. */
{
int sign, expSign = 0;
double fraction, dblExp, *d;
register const char *p;
register int c;
int exp = 0; /* Exponent read from "EX" field. */
int fracExp = 0; /* Exponent that derives from the fractional
* part. Under normal circumstatnces, it is
* the negative of the number of digits in F.
* However, if I is very long, the last digits
* of I get dropped (otherwise a long I with a
* large negative exponent could cause an
* unnecessary overflow on I alone). In this
* case, fracExp is incremented one for each
* dropped digit. */
int mantSize; /* Number of digits in mantissa. */
int decPt; /* Number of mantissa digits BEFORE decimal
* point. */
const char *pExp; /* Temporarily holds location of exponent
* in string. */
/*
* Strip off leading blanks and check for a sign.
*/
p = string;
while (isspace(*p)) {
p += 1;
}
if (*p == '-') {
sign = 1;
p += 1;
} else {
if (*p == '+') {
p += 1;
}
sign = 0;
}
/*
* Count the number of digits in the mantissa (including the decimal
* point), and also locate the decimal point.
*/
decPt = -1;
for (mantSize = 0; ; mantSize += 1)
{
c = *p;
if (!isdigit(c)) {
if ((c != '.') || (decPt >= 0)) {
break;
}
decPt = mantSize;
}
p += 1;
}
/*
* Now suck up the digits in the mantissa. Use two integers to
* collect 9 digits each (this is faster than using floating-point).
* If the mantissa has more than 18 digits, ignore the extras, since
* they can't affect the value anyway.
*/
pExp = p;
p -= mantSize;
if (decPt < 0) {
decPt = mantSize;
} else {
mantSize -= 1; /* One of the digits was the point. */
}
if (mantSize > 18) {
fracExp = decPt - 18;
mantSize = 18;
} else {
fracExp = decPt - mantSize;
}
if (mantSize == 0) {
fraction = 0.0;
p = string;
goto done;
} else {
int frac1, frac2;
frac1 = 0;
for ( ; mantSize > 9; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.') {
c = *p;
p += 1;
}
frac1 = 10*frac1 + (c - '0');
}
frac2 = 0;
for (; mantSize > 0; mantSize -= 1)
{
c = *p;
p += 1;
if (c == '.') {
c = *p;
p += 1;
}
frac2 = 10*frac2 + (c - '0');
}
fraction = (1.0e9 * frac1) + frac2;
}
/*
* Skim off the exponent.
*/
p = pExp;
if ((*p == 'E') || (*p == 'e')) {
p += 1;
if (*p == '-') {
expSign = 1;
p += 1;
} else {
if (*p == '+') {
p += 1;
}
expSign = 0;
}
while (isdigit(*p)) {
exp = exp * 10 + (*p - '0');
p += 1;
}
}
if (expSign) {
exp = fracExp - exp;
} else {
exp = fracExp + exp;
}
/*
* Generate a floating-point number that represents the exponent.
* Do this by processing the exponent one bit at a time to combine
* many powers of 2 of 10. Then combine the exponent with the
* fraction.
*/
if (exp < 0) {
expSign = 1;
exp = -exp;
} else {
expSign = 0;
}
if (exp > maxExponent) {
exp = maxExponent;
errno = ERANGE;
}
dblExp = 1.0;
for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
if (exp & 01) {
dblExp *= *d;
}
}
if (expSign) {
fraction /= dblExp;
} else {
fraction *= dblExp;
}
done:
if (endPtr != NULL) {
*endPtr = (char *) p;
}
if (sign) {
return -fraction;
}
return fraction;
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_TYPES_H
#define LIBASS_TYPES_H
#include <stdint.h>
#define VALIGN_SUB 0
#define VALIGN_CENTER 8
#define VALIGN_TOP 4
#define HALIGN_LEFT 1
#define HALIGN_CENTER 2
#define HALIGN_RIGHT 3
/* Opaque objects internally used by libass. Contents are private. */
typedef struct ass_renderer ASS_Renderer;
typedef struct render_priv ASS_RenderPriv;
typedef struct parser_priv ASS_ParserPriv;
typedef struct ass_library ASS_Library;
/* ASS Style: line */
typedef struct ass_style {
char *Name;
char *FontName;
double FontSize;
uint32_t PrimaryColour;
uint32_t SecondaryColour;
uint32_t OutlineColour;
uint32_t BackColour;
int Bold;
int Italic;
int Underline;
int StrikeOut;
double ScaleX;
double ScaleY;
double Spacing;
int Angle;
int BorderStyle;
double Outline;
double Shadow;
int Alignment;
int MarginL;
int MarginR;
int MarginV;
int Encoding;
int treat_fontname_as_pattern;
} ASS_Style;
/*
* ASS_Event corresponds to a single Dialogue line;
* text is stored as-is, style overrides will be parsed later.
*/
typedef struct ass_event {
long long Start; // ms
long long Duration; // ms
int ReadOrder;
int Layer;
int Style;
char *Name;
int MarginL;
int MarginR;
int MarginV;
char *Effect;
char *Text;
ASS_RenderPriv *render_priv;
} ASS_Event;
/*
* ass track represent either an external script or a matroska subtitle stream
* (no real difference between them); it can be used in rendering after the
* headers are parsed (i.e. events format line read).
*/
typedef struct ass_track {
int n_styles; // amount used
int max_styles; // amount allocated
int n_events;
int max_events;
ASS_Style *styles; // array of styles, max_styles length, n_styles used
ASS_Event *events; // the same as styles
char *style_format; // style format line (everything after "Format: ")
char *event_format; // event format line
enum {
TRACK_TYPE_UNKNOWN = 0,
TRACK_TYPE_ASS,
TRACK_TYPE_SSA
} track_type;
// Script header fields
int PlayResX;
int PlayResY;
double Timer;
int WrapStyle;
int ScaledBorderAndShadow;
int Kerning;
int default_style; // index of default style
char *name; // file name in case of external subs, 0 for streams
ASS_Library *library;
ASS_ParserPriv *parser_priv;
} ASS_Track;
#endif /* LIBASS_TYPES_H */

View File

@ -1,207 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <ft2build.h>
#include FT_GLYPH_H
#include "ass_library.h"
#include "ass.h"
#include "ass_utils.h"
int mystrtoi(char **p, int *res)
{
double temp_res;
char *start = *p;
temp_res = ass_strtod(*p, p);
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
if (*p != start)
return 1;
else
return 0;
}
int mystrtoll(char **p, long long *res)
{
double temp_res;
char *start = *p;
temp_res = ass_strtod(*p, p);
*res = (int) (temp_res + (temp_res > 0 ? 0.5 : -0.5));
if (*p != start)
return 1;
else
return 0;
}
int mystrtou32(char **p, int base, uint32_t *res)
{
char *start = *p;
*res = strtoll(*p, p, base);
if (*p != start)
return 1;
else
return 0;
}
int mystrtod(char **p, double *res)
{
char *start = *p;
*res = ass_strtod(*p, p);
if (*p != start)
return 1;
else
return 0;
}
int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex)
{
uint32_t color = 0;
int result;
char *p = *q;
int base = hex ? 16 : 10;
if (*p == '&')
++p;
else
ass_msg(library, MSGL_DBG2, "suspicious color format: \"%s\"\n", p);
if (*p == 'H' || *p == 'h') {
++p;
result = mystrtou32(&p, 16, &color);
} else {
result = mystrtou32(&p, base, &color);
}
{
unsigned char *tmp = (unsigned char *) (&color);
unsigned char b;
b = tmp[0];
tmp[0] = tmp[3];
tmp[3] = b;
b = tmp[1];
tmp[1] = tmp[2];
tmp[2] = b;
}
if (*p == '&')
++p;
*q = p;
*res = color;
return result;
}
// Return a boolean value for a string
char parse_bool(char *str)
{
while (*str == ' ' || *str == '\t')
str++;
if (!strncasecmp(str, "yes", 3))
return 1;
else if (strtol(str, NULL, 10) > 0)
return 1;
return 0;
}
void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...)
{
va_list va;
va_start(va, fmt);
priv->msg_callback(lvl, fmt, va, priv->msg_callback_data);
va_end(va);
}
unsigned ass_utf8_get_char(char **str)
{
uint8_t *strp = (uint8_t *) * str;
unsigned c = *strp++;
unsigned mask = 0x80;
int len = -1;
while (c & mask) {
mask >>= 1;
len++;
}
if (len <= 0 || len > 4)
goto no_utf8;
c &= mask - 1;
while ((*strp & 0xc0) == 0x80) {
if (len-- <= 0)
goto no_utf8;
c = (c << 6) | (*strp++ & 0x3f);
}
if (len)
goto no_utf8;
*str = (char *) strp;
return c;
no_utf8:
strp = (uint8_t *) * str;
c = *strp++;
*str = (char *) strp;
return c;
}
#ifdef CONFIG_ENCA
void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
int buflen, char *preferred_language,
char *fallback)
{
const char **languages;
size_t langcnt;
EncaAnalyser analyser;
EncaEncoding encoding;
char *detected_sub_cp = NULL;
int i;
languages = enca_get_languages(&langcnt);
ass_msg(library, MSGL_V, "ENCA supported languages");
for (i = 0; i < langcnt; i++) {
ass_msg(library, MSGL_V, "lang %s", languages[i]);
}
for (i = 0; i < langcnt; i++) {
const char *tmp;
if (strcasecmp(languages[i], preferred_language) != 0)
continue;
analyser = enca_analyser_alloc(languages[i]);
encoding = enca_analyse_const(analyser, buffer, buflen);
tmp = enca_charset_name(encoding.charset, ENCA_NAME_STYLE_ICONV);
if (tmp && encoding.charset != ENCA_CS_UNKNOWN) {
detected_sub_cp = strdup(tmp);
ass_msg(library, MSGL_INFO, "ENCA detected charset: %s", tmp);
}
enca_analyser_free(analyser);
}
free(languages);
if (!detected_sub_cp) {
detected_sub_cp = strdup(fallback);
ass_msg(library, MSGL_INFO,
"ENCA detection failed: fallback to %s", fallback);
}
return detected_sub_cp;
}
#endif

View File

@ -1,147 +0,0 @@
/*
* Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
*
* 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.
*
* 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.
*/
#ifndef LIBASS_UTILS_H
#define LIBASS_UTILS_H
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#ifdef CONFIG_ENCA
#include <enca.h>
#endif
#include "ass.h"
#define MSGL_FATAL 0
#define MSGL_ERR 1
#define MSGL_WARN 2
#define MSGL_INFO 4
#define MSGL_V 6
#define MSGL_DBG2 7
#define FFMAX(a,b) ((a) > (b) ? (a) : (b))
#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
#define FFMINMAX(c,a,b) FFMIN(FFMAX(c, a), b)
int mystrtoi(char **p, int *res);
int mystrtoll(char **p, long long *res);
int mystrtou32(char **p, int base, uint32_t *res);
int mystrtod(char **p, double *res);
int strtocolor(ASS_Library *library, char **q, uint32_t *res, int hex);
char parse_bool(char *str);
unsigned ass_utf8_get_char(char **str);
void ass_msg(ASS_Library *priv, int lvl, char *fmt, ...);
#ifdef CONFIG_ENCA
void *ass_guess_buffer_cp(ASS_Library *library, unsigned char *buffer,
int buflen, char *preferred_language,
char *fallback);
#endif
/* defined in ass_strtod.c */
double ass_strtod(const char *string, char **endPtr);
static inline int d6_to_int(int x)
{
return (x + 32) >> 6;
}
static inline int d16_to_int(int x)
{
return (x + 32768) >> 16;
}
static inline int int_to_d6(int x)
{
return x << 6;
}
static inline int int_to_d16(int x)
{
return x << 16;
}
static inline int d16_to_d6(int x)
{
return (x + 512) >> 10;
}
static inline int d6_to_d16(int x)
{
return x << 10;
}
static inline double d6_to_double(int x)
{
return x / 64.;
}
static inline int double_to_d6(double x)
{
return (int) (x * 64);
}
static inline double d16_to_double(int x)
{
return ((double) x) / 0x10000;
}
static inline int double_to_d16(double x)
{
return (int) (x * 0x10000);
}
static inline double d22_to_double(int x)
{
return ((double) x) / 0x400000;
}
static inline int double_to_d22(double x)
{
return (int) (x * 0x400000);
}
// Calculate cache key for a rotational angle in degrees
static inline int rot_key(double a)
{
const int m = double_to_d22(360.0);
return double_to_d22(a) % m;
}
#define FNV1_32A_INIT (unsigned)0x811c9dc5
static inline unsigned fnv_32a_buf(void *buf, size_t len, unsigned hval)
{
unsigned char *bp = buf;
unsigned char *be = bp + len;
while (bp < be) {
hval ^= (unsigned) *bp++;
hval +=
(hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) +
(hval << 24);
}
return hval;
}
static inline unsigned fnv_32a_str(char *str, unsigned hval)
{
unsigned char *s = (unsigned char *) str;
while (*s) {
hval ^= (unsigned) *s++;
hval +=
(hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) +
(hval << 24);
}
return hval;
}
#endif /* LIBASS_UTILS_H */

View File

@ -1,55 +0,0 @@
#ifndef __LIBASS_HELP_MP_H__
#define __LIBASS_HELP_MP_H__
#define MSGTR_LIBASS_FT_Glyph_To_BitmapError "[ass] FT_Glyph_To_Bitmap error %d \n"
#define MSGTR_LIBASS_UnsupportedPixelMode "[ass] Unsupported pixel mode: %d\n"
#define MSGTR_LIBASS_GlyphBBoxTooLarge "[ass] Glyph bounding box too large: %dx%dpx\n"
#define MSGTR_LIBASS_NoStyleNamedXFoundUsingY "[ass] [%p] Warning: no style named '%s' found, using '%s'\n"
#define MSGTR_LIBASS_BadTimestamp "[ass] bad timestamp\n"
#define MSGTR_LIBASS_BadEncodedDataSize "[ass] bad encoded data size\n"
#define MSGTR_LIBASS_FontLineTooLong "[ass] Font line too long: %d, %s\n"
#define MSGTR_LIBASS_EventFormatHeaderMissing "[ass] Event format header missing\n"
#define MSGTR_LIBASS_ErrorOpeningIconvDescriptor "[ass] error opening iconv descriptor.\n"
#define MSGTR_LIBASS_ErrorRecodingFile "[ass] error recoding file.\n"
#define MSGTR_LIBASS_FopenFailed "[ass] ass_read_file(%s): fopen failed\n"
#define MSGTR_LIBASS_FseekFailed "[ass] ass_read_file(%s): fseek failed\n"
#define MSGTR_LIBASS_RefusingToLoadSubtitlesLargerThan10M "[ass] ass_read_file(%s): Refusing to load subtitles larger than 10M\n"
#define MSGTR_LIBASS_ReadFailed "Read failed, %d: %s\n"
#define MSGTR_LIBASS_AddedSubtitleFileMemory "[ass] Added subtitle file: <memory> (%d styles, %d events)\n"
#define MSGTR_LIBASS_AddedSubtitleFileFname "[ass] Added subtitle file: %s (%d styles, %d events)\n"
#define MSGTR_LIBASS_FailedToCreateDirectory "[ass] Failed to create directory %s\n"
#define MSGTR_LIBASS_NotADirectory "[ass] Not a directory: %s\n"
#define MSGTR_LIBASS_TooManyFonts "[ass] Too many fonts\n"
#define MSGTR_LIBASS_ErrorOpeningFont "[ass] Error opening font: %s, %d\n"
#define MSGTR_LIBASS_SelectedFontFamilyIsNotTheRequestedOne "[ass] fontconfig: Selected font is not the requested one: '%s' != '%s'\n"
#define MSGTR_LIBASS_UsingDefaultFontFamily "[ass] fontconfig_select: Using default font family: (%s, %d, %d) -> %s, %d\n"
#define MSGTR_LIBASS_UsingDefaultFont "[ass] fontconfig_select: Using default font: (%s, %d, %d) -> %s, %d\n"
#define MSGTR_LIBASS_UsingArialFontFamily "[ass] fontconfig_select: Using 'Arial' font family: (%s, %d, %d) -> %s, %d\n"
#define MSGTR_LIBASS_FcInitLoadConfigAndFontsFailed "[ass] FcInitLoadConfigAndFonts failed.\n"
#define MSGTR_LIBASS_UpdatingFontCache "[ass] Updating font cache.\n"
#define MSGTR_LIBASS_BetaVersionsOfFontconfigAreNotSupported "[ass] Beta versions of fontconfig are not supported.\n[ass] Update before reporting any bugs.\n"
#define MSGTR_LIBASS_FcStrSetAddFailed "[ass] FcStrSetAdd failed.\n"
#define MSGTR_LIBASS_FcDirScanFailed "[ass] FcDirScan failed.\n"
#define MSGTR_LIBASS_FcDirSave "[ass] FcDirSave failed.\n"
#define MSGTR_LIBASS_FcConfigAppFontAddDirFailed "[ass] FcConfigAppFontAddDir failed\n"
#define MSGTR_LIBASS_FontconfigDisabledDefaultFontWillBeUsed "[ass] Fontconfig disabled, only default font will be used.\n"
#define MSGTR_LIBASS_FunctionCallFailed "[ass] %s failed\n"
#define MSGTR_LIBASS_NeitherPlayResXNorPlayResYDefined "[ass] Neither PlayResX nor PlayResY defined. Assuming 384x288.\n"
#define MSGTR_LIBASS_PlayResYUndefinedSettingY "[ass] PlayResY undefined, setting %d.\n"
#define MSGTR_LIBASS_PlayResXUndefinedSettingX "[ass] PlayResX undefined, setting %d.\n"
#define MSGTR_LIBASS_FT_Init_FreeTypeFailed "[ass] FT_Init_FreeType failed.\n"
#define MSGTR_LIBASS_Init "[ass] Init\n"
#define MSGTR_LIBASS_InitFailed "[ass] Init failed.\n"
#define MSGTR_LIBASS_BadCommand "[ass] Bad command: %c%c\n"
#define MSGTR_LIBASS_ErrorLoadingGlyph "[ass] Error loading glyph.\n"
#define MSGTR_LIBASS_FT_Glyph_Stroke_Error "[ass] FT_Glyph_Stroke error %d \n"
#define MSGTR_LIBASS_UnknownEffectType_InternalError "[ass] Unknown effect type (internal error)\n"
#define MSGTR_LIBASS_NoStyleFound "[ass] No style found!\n"
#define MSGTR_LIBASS_EmptyEvent "[ass] Empty event!\n"
#define MSGTR_LIBASS_MAX_GLYPHS_Reached "[ass] MAX_GLYPHS reached: event %d, start = %llu, duration = %llu\n Text = %s\n"
#define MSGTR_LIBASS_EventHeightHasChanged "[ass] Warning! Event height has changed! \n"
#define MSGTR_LIBASS_GlyphNotFoundReselectingFont "[ass] Glyph 0x%X not found, selecting one more font for (%s, %d, %d)\n"
#define MSGTR_LIBASS_GlyphNotFound "[ass] Glyph 0x%X not found in font for (%s, %d, %d)\n"
#define MSGTR_LIBASS_ErrorOpeningMemoryFont "[ass] Error opening memory font: %s\n"
#define MSGTR_LIBASS_NoCharmaps "[ass] font face with no charmaps\n"
#define MSGTR_LIBASS_NoCharmapAutodetected "[ass] no charmap autodetected, trying the first one\n"
#endif

View File

@ -98,9 +98,9 @@ aegisub_2_1_LDADD += libsubtitle_provider.a
if WITH_LIBASS
noinst_LIBRARIES += libsubtitle_ass.a
libsubtitle_ass_a_SOURCES = subtitles_provider_libass.cpp
libsubtitle_ass_a_CPPFLAGS = @LIBASS_CFLAGS@ @ICONV_CFLAGS@
libsubtitle_ass_a_CPPFLAGS = @LIBASS_CFLAGS@
LIBS += @LIBASS_LIBS@
aegisub_2_1_LDADD += libsubtitle_ass.a @FONTCONFIG_LIBS@
aegisub_2_1_LDADD += libsubtitle_ass.a
endif
if HAVE_AUTO4_LUA
@ -342,7 +342,7 @@ aegisub_2_1_SOURCES = \
aegisub_2_1_SOURCES += \
$(srcdir)/*.h \
$(srcdir)/include/aegisub/*.h \
$(srcdir)/config/*.h
$(srcdir)/config/*.h
noinst_HEADERS = \
$(srcdir)/boost/*.hpp \
@ -352,3 +352,4 @@ noinst_HEADERS = \
EXTRA_DIST = \
auto4_perldata.inc \
$(srcdir)/*.hxx

View File

@ -44,7 +44,7 @@ extern "C" {
#include "stdint.h"
#endif
#include "../libass/ass.h"
#include <ass/ass.h>
}
///////////////////