mirror of https://gitee.com/openkylin/atril.git
Import Upstream version 1.24.0
This commit is contained in:
commit
c2026d8250
|
@ -0,0 +1,9 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
custom: https://mate-desktop.org/donate/
|
|
@ -0,0 +1,19 @@
|
|||
#### Expected behaviour
|
||||
|
||||
|
||||
#### Actual behaviour
|
||||
|
||||
|
||||
#### Steps to reproduce the behaviour
|
||||
|
||||
|
||||
#### MATE general version
|
||||
|
||||
|
||||
#### Package version
|
||||
|
||||
|
||||
#### Linux Distribution
|
||||
|
||||
|
||||
#### link to downstream report of your Distribution
|
|
@ -0,0 +1,231 @@
|
|||
# vim: set ts=2 sts=2 sw=2 expandtab :
|
||||
dist: xenial
|
||||
sudo: required
|
||||
language: bash
|
||||
services:
|
||||
- docker
|
||||
|
||||
branches:
|
||||
except:
|
||||
- gh-pages
|
||||
|
||||
before_install:
|
||||
- curl -Ls -o docker-build https://github.com/mate-desktop/mate-dev-scripts/raw/master/travis/docker-build
|
||||
- curl -Ls -o gen-index https://github.com/mate-desktop/mate-dev-scripts/raw/master/travis/gen-index.sh
|
||||
- chmod +x docker-build gen-index
|
||||
|
||||
install:
|
||||
- sudo apt-get install -y python3-pip python3-setuptools
|
||||
- sudo pip3 install --upgrade pip
|
||||
- sudo pip install PyGithub
|
||||
- ./docker-build --name ${DISTRO} --config .travis.yml --install
|
||||
|
||||
script:
|
||||
- ./docker-build --name ${DISTRO} --verbose --config .travis.yml --build scripts
|
||||
|
||||
deploy:
|
||||
- provider: pages
|
||||
github-token: $GITHUB_TOKEN
|
||||
#keep-history: true
|
||||
skip_cleanup: true
|
||||
committer-from-gh: true
|
||||
target-branch: gh-pages
|
||||
local-dir: html-report
|
||||
on:
|
||||
all_branches: true
|
||||
condition: ${DISTRO} =~ ^fedora.*$
|
||||
- provider: script
|
||||
script: ./docker-build --verbose --config .travis.yml --release github
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
condition: "${TRAVIS_TAG} =~ ^v.*$ && ${DISTRO} =~ ^fedora.*$"
|
||||
|
||||
after_success:
|
||||
- 'if [[ "$TRAVIS_SECURE_ENV_VARS" == "true" && "$TRAVIS_PULL_REQUEST" != "false" && ${DISTRO} =~ ^fedora.*$ ]]; then
|
||||
REPO_SLUG_ARRAY=(${TRAVIS_REPO_SLUG//\// });
|
||||
REPO_NAME=${REPO_SLUG_ARRAY[1]};
|
||||
URL="https://${REPO_NAME}.mate-desktop.dev";
|
||||
COMMENT="Code analysis completed";
|
||||
curl -H "Authorization: token $GITHUB_TOKEN" -X POST
|
||||
-d "{\"state\": \"success\", \"description\": \"$COMMENT\", \"context\":\"scan-build\", \"target_url\": \"$URL\"}"
|
||||
https://api.github.com/repos/${TRAVIS_REPO_SLUG}/statuses/${TRAVIS_PULL_REQUEST_SHA};
|
||||
fi'
|
||||
|
||||
env:
|
||||
- DISTRO="archlinux/base"
|
||||
- DISTRO="debian:testing"
|
||||
- DISTRO="fedora:latest"
|
||||
- DISTRO="ubuntu:19.10"
|
||||
|
||||
##########################################################
|
||||
# THE FOLLOWING LINES IS USED BY docker-build
|
||||
##########################################################
|
||||
requires:
|
||||
archlinux:
|
||||
# Useful URL: https://git.archlinux.org/svntogit/community.git/tree/atril
|
||||
- clang
|
||||
- caja
|
||||
- djvulibre
|
||||
- gcc
|
||||
- git
|
||||
- gobject-introspection
|
||||
- itstool
|
||||
- libgxps
|
||||
- make
|
||||
- mate-common
|
||||
- poppler-glib
|
||||
- texlive-bin
|
||||
- webkit2gtk
|
||||
- which
|
||||
- yelp-tools
|
||||
|
||||
debian:
|
||||
# Useful URL: https://github.com/mate-desktop/debian-packages
|
||||
# Useful URL: https://salsa.debian.org/debian-mate-team/atril
|
||||
- autopoint
|
||||
- clang
|
||||
- clang-tools
|
||||
- cppcheck
|
||||
- git
|
||||
- gobject-introspection
|
||||
- libcaja-extension-dev
|
||||
- libdjvulibre-dev
|
||||
- libgail-3-dev
|
||||
- libgirepository1.0-dev
|
||||
- libglib2.0-dev
|
||||
- libgtk-3-dev
|
||||
- libgxps-dev
|
||||
- libkpathsea-dev
|
||||
- libsynctex-dev
|
||||
- libpoppler-glib-dev
|
||||
- libsecret-1-dev
|
||||
- libsm-dev
|
||||
- libspectre-dev
|
||||
- libtiff-dev
|
||||
- libwebkit2gtk-4.0-dev
|
||||
- libx11-dev
|
||||
- libxml2-dev
|
||||
- lsb-release
|
||||
- make
|
||||
- mate-common
|
||||
- xsltproc
|
||||
- yelp-tools
|
||||
- zlib1g-dev
|
||||
|
||||
fedora:
|
||||
# Useful URL: https://src.fedoraproject.org/cgit/rpms/atril.git
|
||||
- cairo-gobject-devel
|
||||
- caja-devel
|
||||
- clang
|
||||
- clang-analyzer
|
||||
- cppcheck-htmlreport
|
||||
- desktop-file-utils
|
||||
- djvulibre-devel
|
||||
- gcc
|
||||
- gcc-c++
|
||||
- git
|
||||
- gobject-introspection-devel
|
||||
- gtk3-devel
|
||||
- libXt-devel
|
||||
- libglade2-devel
|
||||
- libgxps-devel
|
||||
- libjpeg-turbo-devel
|
||||
- libsecret-devel
|
||||
- libspectre-devel
|
||||
- libtiff-devel
|
||||
- make
|
||||
- mate-common
|
||||
- poppler-glib-devel
|
||||
- redhat-rpm-config
|
||||
- texlive-lib-devel
|
||||
- webkitgtk4-devel
|
||||
- yelp-tools
|
||||
|
||||
ubuntu:
|
||||
- autopoint
|
||||
- clang
|
||||
- clang-tools
|
||||
- git
|
||||
- gobject-introspection
|
||||
- libcaja-extension-dev
|
||||
- libdjvulibre-dev
|
||||
- libgail-3-dev
|
||||
- libgirepository1.0-dev
|
||||
- libglib2.0-dev
|
||||
- libgtk-3-dev
|
||||
- libgxps-dev
|
||||
- libkpathsea-dev
|
||||
- libsynctex-dev
|
||||
- libpoppler-glib-dev
|
||||
- libsecret-1-dev
|
||||
- libsm-dev
|
||||
- libspectre-dev
|
||||
- libtiff-dev
|
||||
- libwebkit2gtk-4.0-dev
|
||||
- libx11-dev
|
||||
- libxml2-dev
|
||||
- lsb-release
|
||||
- make
|
||||
- mate-common
|
||||
- xsltproc
|
||||
- yelp-tools
|
||||
- zlib1g-dev
|
||||
|
||||
variables:
|
||||
- CFLAGS="-Wall -Werror=format-security -Wredundant-decls"
|
||||
- 'CHECKERS="
|
||||
-enable-checker deadcode.DeadStores
|
||||
-enable-checker alpha.deadcode.UnreachableCode
|
||||
-enable-checker alpha.core.CastSize
|
||||
-enable-checker alpha.core.CastToStruct
|
||||
-enable-checker alpha.core.IdenticalExpr
|
||||
-enable-checker alpha.core.SizeofPtr
|
||||
-enable-checker alpha.security.ArrayBoundV2
|
||||
-enable-checker alpha.security.MallocOverflow
|
||||
-enable-checker alpha.security.ReturnPtrRange
|
||||
-enable-checker alpha.unix.SimpleStream
|
||||
-enable-checker alpha.unix.cstring.BufferOverlap
|
||||
-enable-checker alpha.unix.cstring.NotNullTerminated
|
||||
-enable-checker alpha.unix.cstring.OutOfBounds
|
||||
-enable-checker alpha.core.FixedAddr
|
||||
-enable-checker security.insecureAPI.strcpy"'
|
||||
|
||||
before_scripts:
|
||||
- if [ ${DISTRO_NAME} == "debian" ];then
|
||||
- egrep -lRZ 'G_GNUC_BEGIN_IGNORE_DEPRECATIONS' . | xargs -0 -l sed -i -e 's/G_GNUC_BEGIN_IGNORE_DEPRECATIONS/ /g'
|
||||
- egrep -lRZ 'G_GNUC_END_IGNORE_DEPRECATIONS' . | xargs -0 -l sed -i -e 's/G_GNUC_END_IGNORE_DEPRECATIONS/ /g'
|
||||
- fi
|
||||
|
||||
build_scripts:
|
||||
- ./autogen.sh
|
||||
- scan-build $CHECKERS ./configure
|
||||
- if [ $CPU_COUNT -gt 1 ]; then
|
||||
- scan-build $CHECKERS --keep-cc -o html-report make -j $CPU_COUNT
|
||||
- else
|
||||
- scan-build $CHECKERS --keep-cc -o html-report make
|
||||
- fi
|
||||
- if [ ${DISTRO_NAME} == "debian" ];then
|
||||
- cppcheck --enable=warning,style,performance,portability,information,missingInclude --force -D__cplusplus .
|
||||
- fi
|
||||
|
||||
after_scripts:
|
||||
- if [ ${DISTRO_NAME} == "fedora" ];then
|
||||
- cppcheck --xml --output-file=cppcheck.xml --enable=warning,style,performance,portability,information,missingInclude --force -D__cplusplus .
|
||||
- cppcheck-htmlreport --title=${REPO_NAME} --file=cppcheck.xml --report-dir=cppcheck-htmlreport
|
||||
- ./gen-index -l 20 -i https://github.com/${OWNER_NAME}/atril/raw/master/data/icons/16x16/apps/atril.png
|
||||
- fi
|
||||
- make distcheck
|
||||
|
||||
releases:
|
||||
draft: false
|
||||
prerelease: false
|
||||
checksum: true
|
||||
file_glob: true
|
||||
files: atril-*.tar.xz
|
||||
github_release:
|
||||
tags: true
|
||||
overwrite: true
|
||||
base_version: 1.20.0
|
||||
notify_servers:
|
||||
- https://release.mate-desktop.org/release
|
|
@ -0,0 +1,16 @@
|
|||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[MATE.master--atril]
|
||||
file_filter = po/<lang>.po
|
||||
source_file = atril.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
minimum_perc = 2
|
||||
|
||||
[MATE.master--atril-user-guide]
|
||||
file_filter = help/<lang>/<lang>.po
|
||||
source_file = help/atril.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
minimum_perc = 2
|
|
@ -0,0 +1,14 @@
|
|||
The Xpdf software and documentation are
|
||||
Copyright 1996-2003 Glyph & Cog, LLC.
|
||||
|
||||
Martin Kretzschmar <m_kretzschmar@gmx.net>
|
||||
Marco Pesenti Gritti <marco@gnome.org>
|
||||
Jonathan Blandford <jrb@gnome.org>
|
||||
Nickolay V. Shmyrev <nshmyrev@yandex.ru>
|
||||
Bryan Clark <clarkbw@gnome.org>
|
||||
Carlos Garcia Campos <carlosgc@gnome.org>
|
||||
Wouter Bolsterlee <wbolster@gnome.org>
|
||||
|
||||
Perberos <perberos@gmail.com>
|
||||
|
||||
And many others
|
|
@ -0,0 +1,340 @@
|
|||
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 Library 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 Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,2 @@
|
|||
The ChangeLog is auto-generated when releasing. If you are seeing this, use
|
||||
'git log' for a detailed list of changes.
|
|
@ -0,0 +1,90 @@
|
|||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
|
||||
SUBDIRS = \
|
||||
po \
|
||||
cut-n-paste \
|
||||
data \
|
||||
libdocument \
|
||||
backend \
|
||||
libview \
|
||||
libmisc \
|
||||
properties \
|
||||
shell \
|
||||
help
|
||||
|
||||
if ENABLE_TESTS
|
||||
SUBDIRS += test
|
||||
endif
|
||||
|
||||
if ENABLE_THUMBNAILER
|
||||
SUBDIRS += thumbnailer
|
||||
endif
|
||||
|
||||
if ENABLE_PREVIEWER
|
||||
SUBDIRS += previewer
|
||||
endif
|
||||
|
||||
NULL =
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = \
|
||||
atril-document-$(EV_API_VERSION).pc \
|
||||
atril-view-$(EV_API_VERSION).pc \
|
||||
$(NULL)
|
||||
|
||||
headerdir = $(includedir)/atril/$(EV_API_VERSION)
|
||||
header_DATA = \
|
||||
atril-document.h \
|
||||
atril-view.h \
|
||||
$(NULL)
|
||||
|
||||
# Applications
|
||||
EXTRA_DIST = \
|
||||
$(header_DATA) \
|
||||
autogen.sh
|
||||
|
||||
DISTCLEANFILES =
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
ChangeLog \
|
||||
$(srcdir)/INSTALL \
|
||||
$(srcdir)/aclocal.m4 \
|
||||
$(srcdir)/autoscan.log \
|
||||
$(srcdir)/compile \
|
||||
$(srcdir)/config.guess \
|
||||
$(srcdir)/config.h.in \
|
||||
$(srcdir)/config.sub \
|
||||
$(srcdir)/configure \
|
||||
$(srcdir)/configure.scan \
|
||||
$(srcdir)/depcomp \
|
||||
$(srcdir)/install-sh \
|
||||
$(srcdir)/ltmain.sh \
|
||||
$(srcdir)/missing \
|
||||
$(srcdir)/mkinstalldirs \
|
||||
$(srcdir)/omf.make \
|
||||
$(srcdir)/xmldocs.make \
|
||||
$(srcdir)/gtk-doc.make \
|
||||
$(srcdir)/po/Makefile.in.in \
|
||||
`find "$(srcdir)" -type f -name Makefile.in -print`
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = \
|
||||
--disable-schemas-compile \
|
||||
--enable-gtk-doc \
|
||||
--disable-caja \
|
||||
--disable-tests \
|
||||
--disable-silent-rules \
|
||||
CFLAGS='-Wno-deprecated-declarations'
|
||||
|
||||
distuninstallcheck_listfiles = find . -type f -print | grep -v /share/mate/help/ | grep -v \.omf
|
||||
|
||||
# Build ChangeLog from GIT history
|
||||
ChangeLog:
|
||||
$(AM_V_GEN) if test -d $(top_srcdir)/.git; then \
|
||||
GIT_DIR="$(top_srcdir)/.git" git log --stat > $@; \
|
||||
fi
|
||||
|
||||
dist: ChangeLog
|
||||
|
||||
.PHONY: ChangeLog
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,610 @@
|
|||
### atril 1.24.0
|
||||
|
||||
* update translations
|
||||
* thumbnailer: Fix memory leak
|
||||
* Fix year 2038 issue with signed 32-bit integers
|
||||
|
||||
### atril 1.23.2
|
||||
|
||||
* update translations
|
||||
* Fix atril.desktop file
|
||||
* Fix memory leak ev_sidebar_thumbnails_document_changed_cb()
|
||||
* pdf: Fix memory leak when adding new text annotations
|
||||
* Update Copyright year
|
||||
* libview: fixing memory leak
|
||||
* Revert "First page should not reloaded"
|
||||
* avoid redundant redeclarations
|
||||
* libview: Reset `pressed_button` when starting Drag and Drop
|
||||
* show SyncTeX version in about dialog
|
||||
* add hint for translators
|
||||
* migrate from intltool to gettext
|
||||
* Added accelerator 'o' for toggling Odd Pages Left.
|
||||
* Added accelerator 't' for toggling visibility of the toolbar.
|
||||
* remove 'synctex' internally, work with external library instead
|
||||
* remove -Wunused-but-set-variable warning
|
||||
* ephy-zoom-control.c:274:20: warning: variable ‘tool_item_class’ set but not used [-Wunused-but-set-
|
||||
* build: require webkit2gtk-4.0 >= 2.6.0
|
||||
* build: drop fallback check for webkit2gtk-3.0
|
||||
* End the va_list before returning from _synctex_merge_strings
|
||||
* build: Use synctex system library if available
|
||||
* Remove synctex warning
|
||||
* Bump synctex to 1.21
|
||||
* fixed greek translation for user guide
|
||||
|
||||
### atril 1.23.1
|
||||
|
||||
* update translations
|
||||
* tx: sync with transifex
|
||||
* Travis CI: 'cppcheck' with '-D__cplusplus'
|
||||
* ev-view: Remove unused variables and assignment
|
||||
* ev-page-action: avoid 'g_type_class_add_private'
|
||||
* tiff: Handle failure from TIFFReadRGBAImageOriented
|
||||
* view-presentation: Use monitor instead of screen
|
||||
* shell: Use monitor instead of screen to determine window size
|
||||
* ev-link: avoid 'g_type_class_add_private'
|
||||
* ev-document: avoid 'g_type_class_add_private'
|
||||
* ev-link-action: avoid 'g_type_class_add_private'
|
||||
* ev-attachment: avoid 'g_type_class_add_private'
|
||||
* ev-image: avoid 'g_type_class_add_private'
|
||||
* ev-layer: avoid 'g_type_class_add_private'
|
||||
* ev-link-dest: avoid 'g_type_class_add_private'
|
||||
* ev-transition-effect: avoid 'g_type_class_add_private'
|
||||
* egg-editable-toolbar: avoid 'g_type_class_add_private'
|
||||
* egg-toolbar-editor: avoid 'g_type_class_add_private'
|
||||
* egg-toolbars-model: avoid 'g_type_class_add_private'
|
||||
* ev-link-accessible: avoid 'g_type_class_add_private'
|
||||
* ev-timeline: avoid 'g_type_class_add_private'
|
||||
* ev-form-field-accessible: avoid 'g_type_class_add_private'
|
||||
* ev-image-accessible: avoid 'g_type_class_add_private'
|
||||
* ev-transition-animation: avoid 'g_type_class_add_private'
|
||||
* ev-page-accessible: avoid 'g_type_class_add_private'
|
||||
* ev-view-accessible: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar-bookmarks: avoid 'g_type_class_add_private'
|
||||
* ev-history: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar-layers: avoid 'g_type_class_add_private'
|
||||
* eggfindbar: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar-links: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar-thumbnails: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar-attachments: avoid 'g_type_class_add_private'
|
||||
* ev-sidebar-annotations: avoid 'g_type_class_add_private'
|
||||
* ev-progress-message-area: avoid 'g_type_class_add_private'
|
||||
* ev-password-view: avoid 'g_type_class_add_private'
|
||||
* ev-window: avoid 'g_type_class_add_private'
|
||||
* ev-navigation-action: avoid 'g_type_class_add_private'
|
||||
* ev-file-monitor: avoid 'g_type_class_add_private'
|
||||
* ev-message-area: avoid 'g_type_class_add_private'
|
||||
* shell: fix get_monitor_dpi when widget’s window is not realized
|
||||
* DPI: compute monitor resolution or get screen resolution
|
||||
* prevent segfaults when no document loaded
|
||||
* require GLib 2.54.0
|
||||
* Fix build warning on marshalling
|
||||
* previewer-window: suppress GtkAction warnings
|
||||
* sidebar-bookmarks: suppress GtkAction warnings
|
||||
* ev-window: suppress GtkAction warnings
|
||||
* ev-open-recent-action: suppress GtkAction warnings
|
||||
* ev-navigation-action: suppress GtkAction warnings
|
||||
* ev-bookmark-action: suppress GtkAction warnings
|
||||
* ev-page-action: suppress GtkAction warnings
|
||||
* egg-toolbar-editor: suppress GtkAction warnings
|
||||
* egg-editable-toolbar: suppress GtkAction warnings
|
||||
* egg-toolbar-editor{c/h}: tabs to spaces
|
||||
* egg-editable-toolbar{c/h}: tabs to spaces
|
||||
* ephy-zoom-action: suppress GtkAction warnings
|
||||
* document: Replace deprecated gdk_color_equal
|
||||
* Fix buffer overflow in backend/tiff-document.c
|
||||
|
||||
### atril 1.23.0
|
||||
|
||||
* update translations
|
||||
* Remove trailing whitespaces
|
||||
* test: get focus on frame
|
||||
* let test7.py can works
|
||||
* force get focus on atril when testing
|
||||
* migrate to python3 for test cases
|
||||
* Bump Cairo version to 1.14.0
|
||||
* Change url project's website
|
||||
* [ci] Add cppcheck html report
|
||||
* [ci] Enable Clang Static Analyzer
|
||||
* help: update copyright
|
||||
* Add documenters to translation resource
|
||||
* Use program-name and title in gtk_show_about_dialog call
|
||||
* Update copyright in about dialog
|
||||
* Use g_strjoin to build license text in about dialog
|
||||
|
||||
### atril 1.22.0
|
||||
|
||||
* update translations
|
||||
* Add update-authors.pl script which helps to update atril.about
|
||||
* Read authors (updated) from atril.about gresource
|
||||
* Initialize Travis CI support
|
||||
* Update Documenters
|
||||
* [ephy-zoom-control] Avoid deprecated g_type_class_add_private
|
||||
* [ephy-zoom-action] Avoid deprecated g_type_class_add_private
|
||||
* Add pixbuf, tiff and xps TypeDescription to POTFILES.in
|
||||
* eggsmclient: avoid deprecated 'g_type_class_add_private'
|
||||
* move appdata to metainfo directory
|
||||
* message-area: set a11y object name from actual icon name
|
||||
* shell: remove duplicate condition check
|
||||
* tiff: fix possible NULL pointer dereference
|
||||
* pdf: add missing break statement
|
||||
* libdocument: drop useless freeing of NULL pointer
|
||||
* comics: fix incorrect mimetype saying to open and thumbnail all rarfiles
|
||||
* disable deprecation warnings for distcheck
|
||||
|
||||
### atril 1.21.1
|
||||
|
||||
* update translations
|
||||
* Use make functions for HELP_LINGUAS
|
||||
* comics: support application/vnd.rar MIME type
|
||||
* shell: Save document to the same path it was opened from
|
||||
* Reduce the chattiness of atril daemon
|
||||
* EvView: Fix cursor movement when logical and visual line order differs
|
||||
* Update atril_start_window.png
|
||||
* moveable (older spelling) -> movable
|
||||
* Update Catalan screenshot
|
||||
* presentation: avoid deprecated 'gtk_style_context_set_background'
|
||||
* ev-sidebar-bookmarks: use NULL instead of uninitialized variable
|
||||
* navigation-action-widget: replace deprecated gtk_menu_popup function
|
||||
* shell: replace deprecated gtk_menu_popup function
|
||||
* ev-sidebar-links: replace deprecated gtk_menu_popup function
|
||||
* ev-sidebar-bookmarks: replace deprecated gtk_menu_popup function
|
||||
* ev-sidebar: replace deprecated gtk_menu_popup function
|
||||
* editable-toolbar: replace deprecated gtk_menu_popup function
|
||||
* libview: replace deprecated gdk_flush
|
||||
* disable StartPresentation action in fullscreen if document has no pages
|
||||
* disable ViewPresentation action if document has no pages
|
||||
* libdocument: Use gdk_pixbuf_get_from_surface()
|
||||
* thumbnailer: Remove unused code
|
||||
* view: Fix page background rendering while loading
|
||||
* libdocument: Deprecate misc_get_page_border_size()
|
||||
* view: Use a rendered frame instead of custom border
|
||||
* a11y: Return correct start and end offsets
|
||||
* a11y: Fix crash with Orca screen reader
|
||||
* libview: drop deprecated unneeded code
|
||||
* ev-loading-message: Remove unused variables
|
||||
* libview: fix text selection with mouse in annotation window
|
||||
* libview: fix build without epub
|
||||
|
||||
### atril 1.21.0
|
||||
|
||||
* shell: Don't dist generated files
|
||||
* Disable view presentation if there is no document.
|
||||
* Allow changing the page of a presentation
|
||||
* libview: Fix goto window in presentation mode
|
||||
* libview: avoid deprecated gdk_screen_get_monitor
|
||||
* EvPresentationView: Render correctly on hi-dpi displays
|
||||
* libview: Fix g_return condition in set_device_scale_on_surface()
|
||||
* EvView: render correctly on hi-dpi displays
|
||||
* libview: use css to draw the background of presentations
|
||||
* shell: Use GResource for data files
|
||||
* toolbar-editor: Add methods to load from GResource
|
||||
* previewer: Use GResource for data files
|
||||
* build: Add configure check for glib-compile-resources
|
||||
* update resource for translations
|
||||
* libview: Check number of pages when processing button events
|
||||
* libview: Add check for pageless documents to ev_view_accessible_focus_changed
|
||||
* libview: Check number of pages on ev_view_document_changed_cb
|
||||
* Use GtkOverlay to show the loading message
|
||||
* shell: Remove unused marshalers
|
||||
* thumbnailer: Send error messages to stderr
|
||||
* shell: Use GtkApplication to inhibit the screensaver
|
||||
* shell: Port to GtkApplication
|
||||
* shell: Use g_printerr instead of g_warning
|
||||
* daemon: Port to GApplication
|
||||
* daemon: Use gdbus-codegen for the org.mate.atril.Daemon interface
|
||||
* shell: Use gdbus-codegen for the org.mate.atril.Window interface
|
||||
* shell: Use gdbus-codegen for the org.mate.atril.Application interface
|
||||
* libview: save inverted colors in a document
|
||||
* Save/restore context when getting colors for a different state
|
||||
* epub: allow to save epub documents
|
||||
* epub: fix loading epub thumbnails
|
||||
* Check legal boundaries of accessible pages
|
||||
* shell: fix menu-accel for inverted colors
|
||||
* shell: add keypad accels for zoom_reset
|
||||
* Add zoom reset
|
||||
* avoid deprecated GtkStock
|
||||
|
||||
### atril 1.20.0
|
||||
|
||||
* Translations update
|
||||
* require GTK+ 3.22 and GLib 2.50
|
||||
* build: remove pre-GTK+3 option (how did I miss that?)
|
||||
* epub: make minizip support more BSD variants
|
||||
* update copyright year to 2018
|
||||
|
||||
### atril 1.19.6
|
||||
|
||||
* Translations update
|
||||
* Revert "libview: Update the current page also when pending scroll is to find a location"
|
||||
* previewer: add style class atril-previewer-window
|
||||
* WidthOfScreen and HeightOfScreen implementation
|
||||
|
||||
### atril 1.19.5
|
||||
|
||||
* Translations update
|
||||
* shell: show caret navigation in menu
|
||||
* ev-link-accessible: Improve efficiency of methods to get start and end indices
|
||||
* Expose form fields as AtkObject children of the page
|
||||
* Expose images as AtkObject children of the page
|
||||
* Expose links as AtkObject children of the page
|
||||
* ev-view-accessible: Add a method to determine if a given doc rect is showing
|
||||
* ev-page-cache: Add method to check if a given page has been cached
|
||||
* libview: Update the caret cursor when jumping to a find result
|
||||
* libview: Update ATK_STATE_SHOWING when the visible page range changes
|
||||
* libview: Implement AtkComponent for pages
|
||||
* libview: Fix shift+click text selection
|
||||
* a11y: ensure text cached when you request an EvPageAccessible
|
||||
* a11y: managing atk states on EvPageAccessible
|
||||
* a11y: add if applies ATK_RELATION_FLOWS_TO/FROM on EvPageAccessible
|
||||
* a11y: move AtkHyperText implementation from EvViewAccessible to EvPageAccessible
|
||||
* a11y: move AtkText implementation from EvViewAccessible to EvPageAccessible
|
||||
* a11y: expose EvPageAccessible as children of EvViewAccessible
|
||||
* a11y: new EvPageAccessible
|
||||
* libview: Fix some broken aspects EvViewAccessible text support
|
||||
* libview: Take caret navigation into account when getting AtkHyperlink indices
|
||||
* a11y: cleaning implementation for atk_text_get_caret_offset
|
||||
* a11y: fixing implementation for atk_text_set_caret_offset
|
||||
* view: set_caret_cursor_position should emit "cursor-moved" if applies
|
||||
* Remove support for deprecated atk_text_get_text_{before,after}_offset()
|
||||
* a11y: implement AtkDocument on EvViewAccessible
|
||||
* a11y: with caret navigation enabled, accessibility current page is cursor page
|
||||
* ev-view-accessible: call document_changed_cb when setting the model
|
||||
* Some text fixes for caret message area
|
||||
* ev-view-accessible: Fix a crash in ev_view_accessible_get_link
|
||||
* ev-view-accessible: Clear the cached data when the current page
|
||||
* shell: remove view_actions_focus_out_cb
|
||||
* shell: Remove ev_window_set_view_accels_sensitivity
|
||||
* shell: forward accels to the focused widget
|
||||
* Use a global array for view accel action
|
||||
* fix crash when selecting text in djvu documents
|
||||
|
||||
### atril 1.19.4
|
||||
|
||||
* Translations update
|
||||
* shell: fix stock item for message area
|
||||
* docs: libview: Re-add type builtins section
|
||||
* Fix crashes of epub documents with caret-navigation
|
||||
* Store the caret cursor position in document metadata
|
||||
* libview: Add ev_view_set_caret_cursor_position
|
||||
* libview: Update the current page also when pending scroll is to find a location
|
||||
* libview: Do not schedule a redraw when enabling/disabling caret navigation
|
||||
* libview: Stop caret cursor blinking when cursor is not in a visible page
|
||||
* shell: Enable/disable the caret navigation with F7
|
||||
* libview: Add ev_view_supports_caret_navigation()
|
||||
* ev-link-accesible: Return the index/offset after the last character in the link
|
||||
* help: Remove references to removed selection mode
|
||||
* libview: Fix selections starting/ending in page margins
|
||||
* libview: Reduce the pages to scan for selections
|
||||
* libview: Remove unused rectangle selection mode
|
||||
* libview: Rework ev_view_accessible_get_selection
|
||||
* libview: do not redraw the whole view when caret cursor moves
|
||||
* libview: Update the cursor area after positioning the cursor when moving between lines
|
||||
* ev-view-accessible: Fix ev_view_accesssible_get_n_selections
|
||||
* ev-view-accessibl: Fix get_caret_offset when the caret navigation is enabled
|
||||
* libview: Use error bell and return early when moving between lines fails
|
||||
* libview: do not schedule a resize in ensure_rectangle_is_visible
|
||||
* libview: Stop the cursor blink when there are selections active
|
||||
* libview: Deprecate ev_view_scroll in favor of g_signal_emit_by_name
|
||||
* ev-window: Use g_signal_emit_by name instead of ev_view_scroll
|
||||
* previewer: Remove scroll accelerators
|
||||
* ev-window: Remove scroll accelerators
|
||||
* libview: Add more scroll key bindings to EvView
|
||||
* libview: Fix second parameter type of scroll signal for h, j, k and l bindings
|
||||
* libview: Use merge_selection_region passing NULL to clear the selections
|
||||
* ev-pixbuf-cache: Clear the selection region also when clearing the job selection
|
||||
* ev-pixbuf-cache: fix the condition for when a new selection is needed
|
||||
* ev-view-accessible: Rewrite get_run_attributes to return the text attributes from the document
|
||||
* pdf: Implement ev_document_text_get_text_attrs()
|
||||
* libview: Get text attributes from backend and save them in page cache
|
||||
* libdocument: Add ev_document_text_get_text_attrs()
|
||||
* libview: Emit the AtkText text-caret-moved and text-selection-changed signals
|
||||
* libview: clear the selection when cursor is moved
|
||||
* libview: Do not show the caret cursor when there are active selections
|
||||
* libview: Return NULL instead of empty regions from the pixbuf cache
|
||||
* libview: Don't draw the caret cursor when the view is not focused
|
||||
* libview: Fix moving caret cursor between lines in multicolumn documents
|
||||
* libview: Pre-cache some prev/next pages to the current page range.
|
||||
* ev-pixbuf-cache: schedule prev or next jobs first depending on the scroll direction
|
||||
* ev-pixbuf-cache: Schedule jobs to render previous pages in inverse order
|
||||
* libview: Added 'cursor-moved' signal to notify when the caret cursor has been moved.
|
||||
* libview: Avoid unnecessary region copies when selecting text
|
||||
* libview: Use a larger damage area to redraw selections
|
||||
* libview: Don't queue a redraw when damaged region hasn't changed
|
||||
* libview: Invalidate union of old and new selection
|
||||
* libview: Move the caret cursor when clicking outside a selection
|
||||
* libview: Remove unused in_selection member from SelectionInfo struct
|
||||
* libview: Keep the offset inside a line when moving the caret between lines
|
||||
* libview: Position the caret cursor at beginning/end of the line
|
||||
* libview: Do not schedule a redraw when selecting all text
|
||||
* libview: Use prepend + reverse instead of append to create selections list
|
||||
* libview: Use GSlice to allocate EvViewSelection
|
||||
* libview: Text selection using the caret cursor.
|
||||
* libview: Update the caret cursor after selecting text with the mouse
|
||||
* libview: Take page border into account when computing selections
|
||||
* libview: Fix a crash when selecting more than one page
|
||||
* libview: Make sure the cursor blinks after moving it by a click
|
||||
* libview: merge get_caret_cursor_rect_from_offset and get_caret_cursor_area
|
||||
* libview: Notify about caret navigation errors using the error bell.
|
||||
* libview: Do not redraw after a click if cursor position hasn't changed
|
||||
* libview: Use GtkBindings for caret navigation
|
||||
* libview: Rename EvView::binding-activated signal as EvView::scroll
|
||||
* libview: Position the caret cursor by clicking
|
||||
* libview: Use EvPixbufCache to find selection region
|
||||
* libview: Split ev_pixbuf_cache_get_selection_surface into two functions
|
||||
* libview: Draw selection highlight from region
|
||||
* libview: Fix the damage area used to redraw the caret cursor
|
||||
* libview: Actually update the page when moving the care from a different page
|
||||
* libview: Avoid to update the current page and scroll to the cursor position,
|
||||
if the caret cursor was not updated
|
||||
* libview: Make caret cursor blink
|
||||
* libview: Use logical attributes instead text layout to move the caret cursor
|
||||
* libview: Add a way to get the text logical attributes from the page cache
|
||||
* libview: Initial implementation of caret navigation
|
||||
* libview: Refactor code for drawing page and selection surfaces
|
||||
|
||||
### atril 1.19.3
|
||||
|
||||
* Translations update
|
||||
* shell: disable ViewDualOddLeft in menus for epubs
|
||||
* libview: only access the relevant page cache for the height request
|
||||
* Activate shortcut keys for dual and continuous layout
|
||||
* ev-view: Forward key events to the focused form field
|
||||
* Add shortcut keys for fit-page and fit-width options
|
||||
* shell: Do not open single page pdfs in dual mode by default
|
||||
* libview: Don't update current_page to negative number
|
||||
* libview: Make page layout a mode
|
||||
* libview: Add new zoom mode that optimizes for readability
|
||||
* Rename Fit Page Width as Fit Width
|
||||
* Rename Best Fit mode as Fit Page
|
||||
* Move dual page with odd pages left to the view menu
|
||||
* libview: drop deprecated usage of gtk_container_set_resize_mode
|
||||
|
||||
### atril 1.19.2
|
||||
|
||||
* Translations update
|
||||
* shell: Check if doc implements Annotations interface before cast
|
||||
* Refreshing annotations' sidebar upon deletion
|
||||
* libdocument: Make ev_mapping_list_remove void
|
||||
* page-cache: Add flags parameter to ev_page_cache_mark_dirty()
|
||||
* pdf: Reset the annotation mapping when there are no more annotations
|
||||
* Add an option to remove annotations to the view popup menu
|
||||
* libview: add ev_view_remove_annotation
|
||||
* pdf: Implement remove_annotation virtual func
|
||||
* libdocument: add ev_mapping_list_remove
|
||||
* libdocument: Add remove_annotation to DocumentAnnotations.
|
||||
* pdf: Make annotation names unique
|
||||
* pdf: Add support for adding other types of annotations
|
||||
* libview: Rename ev_view_set_focused_element and make it public internally
|
||||
* Change the opacity of the annotation window
|
||||
* Change color of annotation window
|
||||
* libview: Grab focus for form fields and links on mouse press
|
||||
* libdocument: Added ev_mapping_list_get
|
||||
* pdf: Add activation link for Fields that have it.
|
||||
* libview: Handle activation link of a Form Field if present
|
||||
* libdocument: Add activation_link to EvFormField struct
|
||||
* ev-properties-licence: don't use deprecated GtkAlignment
|
||||
* libview: : avoid deprecated gtk_adjustment_changed
|
||||
* ev-job-find: mark two methods as skip
|
||||
* ev-jobs: have ev_job_failed_from_error shadow ev_job_failed
|
||||
* libview: add missing transfer and element-type annotations
|
||||
* ev-mapping-list: make a boxed type
|
||||
* libdocument: add missing transfer and element-type annotations
|
||||
* gtk 3.22: avoid deprecated gdk_screen_get_monitor... functions:
|
||||
* avoid gdk_screen_get_primary_monitor/gdk_screen_get_monitor_scale_factor
|
||||
* ev-document-misc.c: avoid deprecated gdk_screen_get_width/height_mm
|
||||
* dvi: Mitigate command injection attacks by quoting filename
|
||||
* mdvi-lib: Fix compilation warning (const-correctness)
|
||||
* libmisc: set width chars for page label
|
||||
* libview: Scroll small pages in non-continuous mode
|
||||
* libview: Enable GDK_SMOOTH_SCROLL events for view
|
||||
* libview: Ctrl+mouse wheel zoom should be pointer-centered, not window-centered
|
||||
* ev-view: Add pan gesture to switch page
|
||||
* ev-view: explicitly require a GtkScrolledWindow as the parent widget
|
||||
* ev-view: Add pinch/zoom gesture to handle document zooming
|
||||
|
||||
### atril 1.19.1
|
||||
|
||||
* sidebar-thumbnails: fix unwanted move to start after fullscreen
|
||||
* sidebar-thumbnails: preload one extra visible range while scrolling
|
||||
* sidebar-thumbnails: keep thumbnails already rendered
|
||||
* sidebar-thumbnails: fix clunky scrolling
|
||||
* update copyright year in Caja extension
|
||||
* annotations-sidebar: Clean up the styling
|
||||
* ev-annotation-window: Fix setting the color of the window border
|
||||
* libview: fix annotation window focus change after creation
|
||||
* libview: Fix focus on ev_annotation_window
|
||||
* libview: Don't change the font color of the annotation window
|
||||
* shell: Use GdkRGBA for annotations
|
||||
* libdocument: Add EvAnnotation API using GdkRGBA
|
||||
* libdocument: Use the new deprecation macros
|
||||
* Add deprecation macros
|
||||
* fix runtime warnings caused by previous HDPI commit
|
||||
* Take monitor scale factor into account when calculating zoom.
|
||||
* Add hi-dpi support for main view.
|
||||
* shell: Ditch gimpcellrenderertoggle
|
||||
* sidebar-layers: Make it actually usable and fix a runtime warning
|
||||
* libview: setting annotation window icons sizes
|
||||
* libview: save changes to a dropdown in an embedded form
|
||||
* libdocument: adjust rendering of shadow for active and inactive pages
|
||||
* avoid deprecated gdk_screen_make_display_name
|
||||
* ev-window: remove deprecated GtkToolbar-shadow-type
|
||||
* annotation-properties-dialog: don't use a headerbar
|
||||
* avoid deprecated gdk_display_get_screen and gdk_display_get_n_screens
|
||||
* ev-window: don't use deprecated gtk_show_uri
|
||||
* Translations update
|
||||
* avoid deprecated gdk_screen_get_number
|
||||
* Restore Polish translation credits from GNOME
|
||||
|
||||
### atril 1.19.0
|
||||
|
||||
* Translations update
|
||||
* update copyright year to 2017
|
||||
* build: properly clean the generated .caja-extension file
|
||||
* build: require cairo >= 1.10.0 and drop some old code
|
||||
* shell: remove unused code from utils
|
||||
* ev-view: avoid deprecated gtk_drag_begin
|
||||
* egg-editable-toolbar: avoid deprecated gtk_drag_begin
|
||||
* message-area: replace some GtkStock deprecations
|
||||
* ev-sidebar: avoid deprecated GTK_STOCK_CLOSE icon
|
||||
* password-view: replace some GtkStock deprecations
|
||||
* password-view: don't use deprecated GtkAlignment
|
||||
* toolbar-editor: don't use deprecated GtkAlignment
|
||||
|
||||
### atril 1.18.0
|
||||
|
||||
* NEWS: use consistent, project wide, markdown-like formatting to make
|
||||
generating release announcements easier
|
||||
* Build: require caja >= 1.17.1
|
||||
* Move to GTK+3 (require GTK+ >= 3.14), drop GTK+2 code and --with-gtk
|
||||
build option
|
||||
* [comics] add support for unarchiver (unar and lsar)
|
||||
* [libview] increase page cache size to reduce number of page reloads
|
||||
* Remove metadata migration code
|
||||
* Force X11 backend
|
||||
* Fix lots of GTK+ deprecations
|
||||
* Fix some a11y issues
|
||||
* Some more fixes and cleanups
|
||||
* Translations update
|
||||
|
||||
### atril 1.16.1
|
||||
|
||||
* Build: require poppler 0.22.0 (for case-sensitive search in PDFs)
|
||||
* [comics] fix MIME type comparisons
|
||||
* [comics] support application/vnd.comicbook+zip MIME type
|
||||
* [djvu] support image/vnd.djvu+multipage MIME type
|
||||
* [pdf] fix case-sensitive search
|
||||
* thumbnailer: skip epub files (thumbnail generation never worked
|
||||
there and caused segfaults)
|
||||
* Some code cleanups
|
||||
* Translations update
|
||||
|
||||
### atril 1.16.0
|
||||
|
||||
* Build: require poppler 0.18.0
|
||||
* Use GtkAboutDialog instead of MateAboutDialog
|
||||
* Drop dependency on libmate-desktop and --without-matedesktop
|
||||
build option
|
||||
* Update toolbar-editor from libegg
|
||||
* Update synctex to 1.18
|
||||
* Split dual mode option into dual mode with odd and even pages
|
||||
on the left
|
||||
* Add Ctrl+Up/Down keybindings for previous/next search result
|
||||
* Add caja-sendto support for sending current document by email,
|
||||
to removable device, etc.
|
||||
* Improve named destinations support with --named-dest command line
|
||||
argument and dbus support
|
||||
* [dvi] Use t1 font mapping files
|
||||
* GTK+3: add style class for view
|
||||
* GTK+3: fix possible crash when building with introspection enabled
|
||||
* GTK+3: fix lots of deprecations
|
||||
* Some more fixes and cleanups
|
||||
* Translations update
|
||||
|
||||
### atril 1.14.2
|
||||
|
||||
* Add setting to set page cache size
|
||||
* Add setting to disable auto-reload
|
||||
* Fix some issues with rotated documents
|
||||
* Some more fixes and cleanups
|
||||
* Translations update
|
||||
* Make distcheck use currently selected GTK+ version
|
||||
|
||||
### atril 1.14.1
|
||||
|
||||
* Translations update
|
||||
* fix several random webview related crashes
|
||||
|
||||
### atril 1.14.0
|
||||
|
||||
* Drop MateConf migration script
|
||||
* Update copyrights, mention MATE team in Caja extension
|
||||
* Use org.gnome.SessionManager DBus name to inhibit screensaver
|
||||
* GTK+3: add atril-window style class to top level
|
||||
* GTK+3: add css name EggToolbarEditor for 3.20
|
||||
* Some more fixes and cleanups
|
||||
* Translations update
|
||||
* Fix Changelog generation
|
||||
|
||||
### atril 1.12.2
|
||||
|
||||
* [epub] Fix crash when accessibility is enabled
|
||||
|
||||
### atril 1.12.1
|
||||
|
||||
* [dvi] Fix crash due to regression
|
||||
* Translations update
|
||||
|
||||
### atril 1.12.0
|
||||
|
||||
* Drop support for win32/osx/hildon
|
||||
* Drop useless mate-icon-theme dependency
|
||||
* Make smclient mandatory
|
||||
* [epub] drop embedded MathJax in favor of using distro-packaged one
|
||||
* Retrieve strings directly from gschema (requires intltool 0.50.1)
|
||||
* Several code cleanups
|
||||
|
||||
### atril 1.10.2
|
||||
|
||||
* Fix several command line options
|
||||
* Fix several findbar issues
|
||||
* Make libmatedesktop optional
|
||||
* [pdf] Fix saving annotations added to different pages
|
||||
|
||||
### atril 1.10.1
|
||||
|
||||
* Fix crash when pressing Esc with no document opened
|
||||
* Gtk3: Add webkit2gtk-4.0 and prefer it over 3.0
|
||||
* Help fixes
|
||||
|
||||
### atril 1.10.0
|
||||
|
||||
* Fix some crashes
|
||||
* comics backend: add support for bsdtar
|
||||
* Add ini file for caja extension
|
||||
* Add appdata file
|
||||
* Many fixed memory leaks from monsta
|
||||
* sidebar-thumbnails: connect to job finished signal before scheduling the job
|
||||
* zero-init all signals arrays
|
||||
* Add support for external links to EvViewPresentation
|
||||
* Save zoom factor in default settings when sizing mode is free
|
||||
* [pdf] Add support for OCG State actions
|
||||
* [pdf] Update to poppler api changes
|
||||
* [pdf] Do not resolve named destinations in the backend
|
||||
* [pdf] Bump poppler requirements to 0.16.0
|
||||
* [pdf] Implement document_links_find_link_page()
|
||||
* [djvu] Implement document_links_find_link_page()
|
||||
* [libdocument] Use find_link_page() instead of find_link_dest() in get_dest_page()
|
||||
* GDK_KEY_* keys are Gtk+2 as well.
|
||||
* [shell] Add timestamp parameter to SyncView
|
||||
* [shell] Use new methods to get page and page label from a link
|
||||
* [libview] The updated GtkComboBox api is in Gtk+2.24
|
||||
* [dvi] Fix drawing glyphs with transparency
|
||||
* [shell] Send the URI of the input file instead of the filename in SyncSource
|
||||
* [libdocument] Add xz compression support
|
||||
* [pdf] Support .pdf.xz files
|
||||
* [shell] Add EvBookmarks to handle internal document bookmarks
|
||||
* [backends] Fix several security issues in the dvi-backend
|
||||
* Small a11y fixes
|
||||
* Remember the current page when document is reloaded in presentation mode
|
||||
* presentation: Allow to change rotation in presentation mode
|
||||
* Rotate with CTRL+Left/Right in presentation mode too
|
||||
* Add .png extension when saving images using DnD
|
||||
* Gtk3: Use gtk_paned_new() instead gtk_[h|v]paned_new()
|
||||
* Gtk3: Add GtkStyleContect support
|
||||
* Gtk3: Don't use gdk_cursor_unref()
|
||||
* Gtk3: Use gtk_widget_render_icon_pixbuf()
|
||||
* Gtk3: presentation: Make sure background window is black by default in presentation mode
|
||||
* Add epub support (part of GSoC 2014).
|
||||
* Use MateAboutDialog from libmate-desktop.
|
||||
|
||||
### atril 1.8.0
|
||||
|
||||
* Drop libmatekeyring and use libsecret.
|
||||
* Move from mate-doc-utils to yelp-tools.
|
||||
* Better sort files by name in commic book archives.
|
||||
* Enable case sensitive search (not available on all backends).
|
||||
* Move Atril to "Offcie" in the menu.
|
||||
* Show "filename (title)" in the window title.
|
||||
* Gtk+3, add support to build against Gtk+3, still unsupported.
|
||||
* Add Gtk3 primary toolbar style.
|
|
@ -0,0 +1,29 @@
|
|||
Atril
|
||||
==================================================
|
||||
Atril is a document viewer capable of displaying
|
||||
multiple and single page document formats like PDF
|
||||
and Postscript. For more general information about
|
||||
Atril please visit our website at
|
||||
|
||||
https://github.com/mate-desktop/atril
|
||||
|
||||
Atril is a fork of Evince
|
||||
|
||||
This software is licensed under the GPL
|
||||
|
||||
Atril Requirements
|
||||
==================================================
|
||||
MATE Platform libraries [ https://github.com/mate-desktop/ ]
|
||||
Poppler for PDF viewing [ http://poppler.freedesktop.org/ ]
|
||||
GhostScript for Postscript viewing [ http://www.cs.wisc.edu/~ghost/ ]
|
||||
|
||||
Atril Optional Backend Libraries
|
||||
==================================================
|
||||
DjVuLibre for DjVu viewing [ http://djvulibre.djvuzone.org/ ]
|
||||
Rar for viewing CBR comics [ http://www.rarsoft.com/ ]
|
||||
libgxps for XPS documents [ https://wiki.gnome.org/libgxps ]
|
||||
|
||||
Atril Requirements to Run Tests
|
||||
==================================================
|
||||
python-dogtail [ https://fedorahosted.org/dogtail/ ]
|
||||
python-pyatspi2 [ http://download.gnome.org/sources/pyatspi/ ]
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright © 2009 Christian Persch
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This 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 Lesser
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.
|
||||
*/
|
||||
|
||||
#ifndef ATRIL_DOCUMENT_H
|
||||
#define ATRIL_DOCUMENT_H
|
||||
|
||||
#define __EV_ATRIL_DOCUMENT_H_INSIDE__
|
||||
|
||||
#include <libdocument/ev-annotation.h>
|
||||
#include <libdocument/ev-async-renderer.h>
|
||||
#include <libdocument/ev-attachment.h>
|
||||
#include <libdocument/ev-backends-manager.h>
|
||||
#include <libdocument/ev-document-attachments.h>
|
||||
#include <libdocument/ev-document-factory.h>
|
||||
#include <libdocument/ev-document-find.h>
|
||||
#include <libdocument/ev-document-fonts.h>
|
||||
#include <libdocument/ev-document-forms.h>
|
||||
#include <libdocument/ev-document.h>
|
||||
#include <libdocument/ev-document-images.h>
|
||||
#include <libdocument/ev-document-info.h>
|
||||
#include <libdocument/ev-document-layers.h>
|
||||
#include <libdocument/ev-document-print.h>
|
||||
#include <libdocument/ev-document-links.h>
|
||||
#include <libdocument/ev-document-misc.h>
|
||||
#include <libdocument/ev-document-security.h>
|
||||
#include <libdocument/ev-document-thumbnails.h>
|
||||
#include <libdocument/ev-document-transition.h>
|
||||
#include <libdocument/ev-document-type-builtins.h>
|
||||
#include <libdocument/ev-file-exporter.h>
|
||||
#include <libdocument/ev-file-helpers.h>
|
||||
#include <libdocument/ev-form-field.h>
|
||||
#include <libdocument/ev-image.h>
|
||||
#include <libdocument/ev-init.h>
|
||||
#include <libdocument/ev-layer.h>
|
||||
#include <libdocument/ev-link-action.h>
|
||||
#include <libdocument/ev-link-dest.h>
|
||||
#include <libdocument/ev-link.h>
|
||||
#include <libdocument/ev-mapping-list.h>
|
||||
#include <libdocument/ev-page.h>
|
||||
#include <libdocument/ev-render-context.h>
|
||||
#include <libdocument/ev-selection.h>
|
||||
#include <libdocument/ev-transition-effect.h>
|
||||
#include <libdocument/ev-version.h>
|
||||
#include <libdocument/ev-macros.h>
|
||||
|
||||
#undef __EV_ATRIL_DOCUMENT_H_INSIDE__
|
||||
|
||||
#endif /* !ATRIL_DOCUMENT_H */
|
|
@ -0,0 +1,12 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@/atril/@EV_API_VERSION@
|
||||
backenddir=@libdir@/atril/@EV_BINARY_VERSION@/backends
|
||||
|
||||
Name: Atril Document
|
||||
Description: MATE document viewer backend library
|
||||
Version: @VERSION@
|
||||
Requires: gio-2.0 >= @GLIB_REQUIRED@ gtk+-3.0 >= @GTK_REQUIRED@
|
||||
Libs: -L${libdir} -latrildocument
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright © 2009 Christian Persch
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation; either version 2.1 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This 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 Lesser
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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.
|
||||
*/
|
||||
|
||||
#ifndef ATRIL_VIEW_H
|
||||
#define ATRIL_VIEW_H
|
||||
|
||||
#define __EV_ATRIL_VIEW_H_INSIDE__
|
||||
|
||||
#include <libview/ev-job-scheduler.h>
|
||||
#include <libview/ev-jobs.h>
|
||||
#include <libview/ev-document-model.h>
|
||||
#include <libview/ev-print-operation.h>
|
||||
#include <libview/ev-view.h>
|
||||
#include <libview/ev-web-view.h>
|
||||
#include <libview/ev-view-type-builtins.h>
|
||||
#include <libview/ev-stock-icons.h>
|
||||
|
||||
#undef __EV_ATRIL_VIEW_H_INSIDE__
|
||||
|
||||
#endif /* !ATRIL_VIEW_H */
|
|
@ -0,0 +1,11 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@/atril/@EV_API_VERSION@
|
||||
|
||||
Name: Atril View
|
||||
Description: MATE document viewer view library
|
||||
Version: @VERSION@
|
||||
Requires: atril-document-@EV_API_VERSION@ = @VERSION@ gthread-2.0
|
||||
Libs: -L${libdir} -latrilview
|
||||
Cflags: -I${includedir}
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/sh
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
PKG_NAME="atril"
|
||||
|
||||
(test -f $srcdir/configure.ac) || {
|
||||
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
||||
echo " top-level $PKG_NAME directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
which mate-autogen || {
|
||||
echo "You need to install mate-common"
|
||||
exit 1
|
||||
}
|
||||
|
||||
which yelp-build || {
|
||||
echo "You need to install yelp-tools"
|
||||
exit 1
|
||||
}
|
||||
|
||||
REQUIRED_AUTOMAKE_VERSION=1.10
|
||||
REQUIRED_GTK_DOC_VERSION=1.13
|
||||
USE_MATE2_MACROS=1
|
||||
|
||||
. mate-autogen
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
SUBDIRS =
|
||||
|
||||
# Backends
|
||||
|
||||
if ENABLE_PDF
|
||||
SUBDIRS += pdf
|
||||
endif
|
||||
|
||||
if ENABLE_EPUB
|
||||
SUBDIRS += epub
|
||||
endif
|
||||
|
||||
if ENABLE_PS
|
||||
SUBDIRS += ps
|
||||
endif
|
||||
|
||||
if ENABLE_PIXBUF
|
||||
SUBDIRS += pixbuf
|
||||
endif
|
||||
|
||||
if ENABLE_DJVU
|
||||
SUBDIRS += djvu
|
||||
endif
|
||||
|
||||
if ENABLE_TIFF
|
||||
SUBDIRS += tiff
|
||||
endif
|
||||
|
||||
if ENABLE_DVI
|
||||
SUBDIRS += dvi
|
||||
endif
|
||||
|
||||
if ENABLE_COMICS
|
||||
SUBDIRS += comics
|
||||
endif
|
||||
|
||||
if ENABLE_XPS
|
||||
SUBDIRS += xps
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
backend.symbols
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1 @@
|
|||
register_atril_backend
|
|
@ -0,0 +1,32 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(LIB_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libcomicsdocument.la
|
||||
|
||||
libcomicsdocument_la_SOURCES = \
|
||||
comics-document.c \
|
||||
comics-document.h
|
||||
|
||||
libcomicsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libcomicsdocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS) \
|
||||
$(LIB_LIBS)
|
||||
|
||||
backend_in_files = comicsdocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
/* comics-document.h: Implementation of EvDocument for comic book archives
|
||||
* Copyright (C) 2005, Teemu Tervo <teemu.tervo@gmx.net>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __COMICS_DOCUMENT_H__
|
||||
#define __COMICS_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define COMICS_TYPE_DOCUMENT (comics_document_get_type ())
|
||||
#define COMICS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), COMICS_TYPE_DOCUMENT, ComicsDocument))
|
||||
#define COMICS_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), COMICS_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _ComicsDocument ComicsDocument;
|
||||
|
||||
GType comics_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __COMICS_DOCUMENT_H__ */
|
|
@ -0,0 +1,4 @@
|
|||
[Atril Backend]
|
||||
Module=comicsdocument
|
||||
TypeDescription=Comic Books
|
||||
MimeType=application/x-cbr;application/x-cbz;application/x-cb7;application/x-cbt;application/vnd.comicbook+zip;application/vnd.comicbook-rar;
|
|
@ -0,0 +1,38 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-DMATEICONDIR=\""${prefix}/${DATADIRNAME}/pixmaps"\" \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(DJVU_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libdjvudocument.la
|
||||
|
||||
libdjvudocument_la_SOURCES = \
|
||||
djvu-document.c \
|
||||
djvu-document.h \
|
||||
djvu-document-private.h \
|
||||
djvu-links.c \
|
||||
djvu-links.h \
|
||||
djvu-text-page.c \
|
||||
djvu-text-page.h
|
||||
|
||||
libdjvudocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libdjvudocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS) \
|
||||
$(DJVU_LIBS)
|
||||
|
||||
backend_in_files = djvudocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Declarations used throughout the djvu classes
|
||||
*
|
||||
* Copyright (C) 2006, Michael Hofmann <mh21@piware.de>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DJVU_DOCUMENT_INTERNAL_H__
|
||||
#define __DJVU_DOCUMENT_INTERNAL_H__
|
||||
|
||||
#include "djvu-document.h"
|
||||
|
||||
#include <libdjvu/ddjvuapi.h>
|
||||
|
||||
struct _DjvuDocument {
|
||||
EvDocument parent_instance;
|
||||
|
||||
ddjvu_context_t *d_context;
|
||||
ddjvu_document_t *d_document;
|
||||
ddjvu_format_t *d_format;
|
||||
ddjvu_format_t *thumbs_format;
|
||||
|
||||
gchar *uri;
|
||||
|
||||
/* PS exporter */
|
||||
gchar *ps_filename;
|
||||
GString *opts;
|
||||
};
|
||||
|
||||
int djvu_document_get_n_pages (EvDocument *document);
|
||||
void djvu_handle_events (DjvuDocument *djvu_document,
|
||||
int wait,
|
||||
GError **error);
|
||||
|
||||
#endif /* __DJVU_DOCUMENT_INTERNAL_H__ */
|
|
@ -0,0 +1,704 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
|
||||
/*
|
||||
* Copyright (C) 2005, Nickolay V. Shmyrev <nshmyrev@yandex.ru>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <config.h>
|
||||
#include "djvu-document.h"
|
||||
#include "djvu-text-page.h"
|
||||
#include "djvu-links.h"
|
||||
#include "djvu-document-private.h"
|
||||
#include "ev-document-thumbnails.h"
|
||||
#include "ev-file-exporter.h"
|
||||
#include "ev-document-misc.h"
|
||||
#include "ev-document-find.h"
|
||||
#include "ev-document-links.h"
|
||||
#include "ev-selection.h"
|
||||
#include "ev-file-helpers.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SCALE_FACTOR 0.2
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TITLE
|
||||
};
|
||||
|
||||
struct _DjvuDocumentClass
|
||||
{
|
||||
EvDocumentClass parent_class;
|
||||
};
|
||||
|
||||
typedef struct _DjvuDocumentClass DjvuDocumentClass;
|
||||
|
||||
static void djvu_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
|
||||
static void djvu_document_file_exporter_iface_init (EvFileExporterInterface *iface);
|
||||
static void djvu_document_find_iface_init (EvDocumentFindInterface *iface);
|
||||
static void djvu_document_document_links_iface_init (EvDocumentLinksInterface *iface);
|
||||
static void djvu_selection_iface_init (EvSelectionInterface *iface);
|
||||
|
||||
EV_BACKEND_REGISTER_WITH_CODE (DjvuDocument, djvu_document,
|
||||
{
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, djvu_document_document_thumbnails_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER, djvu_document_file_exporter_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, djvu_document_find_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_LINKS, djvu_document_document_links_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_SELECTION, djvu_selection_iface_init);
|
||||
});
|
||||
|
||||
|
||||
#define EV_DJVU_ERROR ev_djvu_error_quark ()
|
||||
|
||||
static GQuark
|
||||
ev_djvu_error_quark (void)
|
||||
{
|
||||
static GQuark q = 0;
|
||||
if (q == 0)
|
||||
q = g_quark_from_string ("ev-djvu-quark");
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_message (const ddjvu_message_t *msg, GError **error)
|
||||
{
|
||||
switch (msg->m_any.tag) {
|
||||
case DDJVU_ERROR: {
|
||||
gchar *error_str;
|
||||
|
||||
if (msg->m_error.filename) {
|
||||
error_str = g_strdup_printf ("DjvuLibre error: %s:%d",
|
||||
msg->m_error.filename,
|
||||
msg->m_error.lineno);
|
||||
} else {
|
||||
error_str = g_strdup_printf ("DjvuLibre error: %s",
|
||||
msg->m_error.message);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
g_set_error_literal (error, EV_DJVU_ERROR, 0, error_str);
|
||||
} else {
|
||||
g_warning ("%s", error_str);
|
||||
}
|
||||
|
||||
g_free (error_str);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
djvu_handle_events (DjvuDocument *djvu_document, int wait, GError **error)
|
||||
{
|
||||
ddjvu_context_t *ctx = djvu_document->d_context;
|
||||
const ddjvu_message_t *msg;
|
||||
|
||||
if (!ctx)
|
||||
return;
|
||||
|
||||
if (wait)
|
||||
ddjvu_message_wait (ctx);
|
||||
|
||||
while ((msg = ddjvu_message_peek (ctx))) {
|
||||
handle_message (msg, error);
|
||||
ddjvu_message_pop (ctx);
|
||||
if (error && *error)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_wait_for_message (DjvuDocument *djvu_document, ddjvu_message_tag_t message, GError **error)
|
||||
{
|
||||
ddjvu_context_t *ctx = djvu_document->d_context;
|
||||
const ddjvu_message_t *msg;
|
||||
|
||||
ddjvu_message_wait (ctx);
|
||||
while ((msg = ddjvu_message_peek (ctx)) && (msg->m_any.tag != message)) {
|
||||
handle_message (msg, error);
|
||||
ddjvu_message_pop (ctx);
|
||||
if (error && *error)
|
||||
return;
|
||||
}
|
||||
if (msg && msg->m_any.tag == message)
|
||||
ddjvu_message_pop (ctx);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
djvu_document_load (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
ddjvu_document_t *doc;
|
||||
gchar *filename;
|
||||
gboolean missing_files = FALSE;
|
||||
GError *djvu_error = NULL;
|
||||
|
||||
/* FIXME: We could actually load uris */
|
||||
filename = g_filename_from_uri (uri, NULL, error);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
doc = ddjvu_document_create_by_filename (djvu_document->d_context, filename, TRUE);
|
||||
|
||||
if (!doc) {
|
||||
g_free (filename);
|
||||
g_set_error_literal (error,
|
||||
EV_DOCUMENT_ERROR,
|
||||
EV_DOCUMENT_ERROR_INVALID,
|
||||
_("DjVu document has incorrect format"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (djvu_document->d_document)
|
||||
ddjvu_document_release (djvu_document->d_document);
|
||||
|
||||
djvu_document->d_document = doc;
|
||||
|
||||
djvu_wait_for_message (djvu_document, DDJVU_DOCINFO, &djvu_error);
|
||||
if (djvu_error) {
|
||||
g_set_error_literal (error,
|
||||
EV_DOCUMENT_ERROR,
|
||||
EV_DOCUMENT_ERROR_INVALID,
|
||||
djvu_error->message);
|
||||
g_error_free (djvu_error);
|
||||
g_free (filename);
|
||||
ddjvu_document_release (djvu_document->d_document);
|
||||
djvu_document->d_document = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ddjvu_document_decoding_error (djvu_document->d_document))
|
||||
djvu_handle_events (djvu_document, TRUE, &djvu_error);
|
||||
|
||||
if (djvu_error) {
|
||||
g_set_error_literal (error,
|
||||
EV_DOCUMENT_ERROR,
|
||||
EV_DOCUMENT_ERROR_INVALID,
|
||||
djvu_error->message);
|
||||
g_error_free (djvu_error);
|
||||
g_free (filename);
|
||||
ddjvu_document_release (djvu_document->d_document);
|
||||
djvu_document->d_document = NULL;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (djvu_document->uri);
|
||||
djvu_document->uri = g_strdup (uri);
|
||||
|
||||
if (ddjvu_document_get_type (djvu_document->d_document) == DDJVU_DOCTYPE_INDIRECT) {
|
||||
gint n_files;
|
||||
gint i;
|
||||
gchar *base;
|
||||
|
||||
base = g_path_get_dirname (filename);
|
||||
|
||||
n_files = ddjvu_document_get_filenum (djvu_document->d_document);
|
||||
for (i = 0; i < n_files; i++) {
|
||||
struct ddjvu_fileinfo_s fileinfo;
|
||||
gchar *file;
|
||||
|
||||
ddjvu_document_get_fileinfo (djvu_document->d_document,
|
||||
i, &fileinfo);
|
||||
|
||||
if (fileinfo.type != 'P')
|
||||
continue;
|
||||
|
||||
file = g_build_filename (base, fileinfo.id, NULL);
|
||||
if (!g_file_test (file, G_FILE_TEST_EXISTS)) {
|
||||
missing_files = TRUE;
|
||||
g_free (file);
|
||||
|
||||
break;
|
||||
}
|
||||
g_free (file);
|
||||
}
|
||||
g_free (base);
|
||||
}
|
||||
g_free (filename);
|
||||
|
||||
if (missing_files) {
|
||||
g_set_error_literal (error,
|
||||
G_FILE_ERROR,
|
||||
G_FILE_ERROR_EXIST,
|
||||
_("The document is composed of several files. "
|
||||
"One or more of these files cannot be accessed."));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
djvu_document_save (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
|
||||
return ev_xfer_uri_simple (djvu_document->uri, uri, error);
|
||||
}
|
||||
|
||||
int
|
||||
djvu_document_get_n_pages (EvDocument *document)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
|
||||
g_return_val_if_fail (djvu_document->d_document, 0);
|
||||
|
||||
return ddjvu_document_get_pagenum (djvu_document->d_document);
|
||||
}
|
||||
|
||||
static void
|
||||
document_get_page_size (DjvuDocument *djvu_document,
|
||||
gint page,
|
||||
double *width,
|
||||
double *height)
|
||||
{
|
||||
ddjvu_pageinfo_t info;
|
||||
ddjvu_status_t r;
|
||||
|
||||
while ((r = ddjvu_document_get_pageinfo(djvu_document->d_document, page, &info)) < DDJVU_JOB_OK)
|
||||
djvu_handle_events(djvu_document, TRUE, NULL);
|
||||
|
||||
if (r >= DDJVU_JOB_FAILED)
|
||||
djvu_handle_events(djvu_document, TRUE, NULL);
|
||||
|
||||
*width = info.width * SCALE_FACTOR;
|
||||
*height = info.height * SCALE_FACTOR;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_get_page_size (EvDocument *document,
|
||||
EvPage *page,
|
||||
double *width,
|
||||
double *height)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
|
||||
g_return_if_fail (djvu_document->d_document);
|
||||
|
||||
document_get_page_size (djvu_document, page->index,
|
||||
width, height);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
djvu_document_render (EvDocument *document,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
cairo_surface_t *surface;
|
||||
gchar *pixels;
|
||||
gint rowstride;
|
||||
ddjvu_rect_t rrect;
|
||||
ddjvu_rect_t prect;
|
||||
ddjvu_page_t *d_page;
|
||||
ddjvu_page_rotation_t rotation;
|
||||
double page_width, page_height, tmp;
|
||||
|
||||
d_page = ddjvu_page_create_by_pageno (djvu_document->d_document, rc->page->index);
|
||||
|
||||
while (!ddjvu_page_decoding_done (d_page))
|
||||
djvu_handle_events(djvu_document, TRUE, NULL);
|
||||
|
||||
page_width = ddjvu_page_get_width (d_page) * rc->scale * SCALE_FACTOR + 0.5;
|
||||
page_height = ddjvu_page_get_height (d_page) * rc->scale * SCALE_FACTOR + 0.5;
|
||||
|
||||
switch (rc->rotation) {
|
||||
case 90:
|
||||
rotation = DDJVU_ROTATE_90;
|
||||
tmp = page_height;
|
||||
page_height = page_width;
|
||||
page_width = tmp;
|
||||
|
||||
break;
|
||||
case 180:
|
||||
rotation = DDJVU_ROTATE_180;
|
||||
|
||||
break;
|
||||
case 270:
|
||||
rotation = DDJVU_ROTATE_270;
|
||||
tmp = page_height;
|
||||
page_height = page_width;
|
||||
page_width = tmp;
|
||||
|
||||
break;
|
||||
default:
|
||||
rotation = DDJVU_ROTATE_0;
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
|
||||
page_width, page_height);
|
||||
rowstride = cairo_image_surface_get_stride (surface);
|
||||
pixels = (gchar *)cairo_image_surface_get_data (surface);
|
||||
|
||||
prect.x = 0;
|
||||
prect.y = 0;
|
||||
prect.w = page_width;
|
||||
prect.h = page_height;
|
||||
rrect = prect;
|
||||
|
||||
ddjvu_page_set_rotation (d_page, rotation);
|
||||
|
||||
ddjvu_page_render (d_page, DDJVU_RENDER_COLOR,
|
||||
&prect,
|
||||
&rrect,
|
||||
djvu_document->d_format,
|
||||
rowstride,
|
||||
pixels);
|
||||
|
||||
cairo_surface_mark_dirty (surface);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_finalize (GObject *object)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (object);
|
||||
|
||||
if (djvu_document->d_document)
|
||||
ddjvu_document_release (djvu_document->d_document);
|
||||
|
||||
if (djvu_document->opts)
|
||||
g_string_free (djvu_document->opts, TRUE);
|
||||
|
||||
if (djvu_document->ps_filename)
|
||||
g_free (djvu_document->ps_filename);
|
||||
|
||||
ddjvu_context_release (djvu_document->d_context);
|
||||
ddjvu_format_release (djvu_document->d_format);
|
||||
ddjvu_format_release (djvu_document->thumbs_format);
|
||||
g_free (djvu_document->uri);
|
||||
|
||||
G_OBJECT_CLASS (djvu_document_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_class_init (DjvuDocumentClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = djvu_document_finalize;
|
||||
|
||||
ev_document_class->load = djvu_document_load;
|
||||
ev_document_class->save = djvu_document_save;
|
||||
ev_document_class->get_n_pages = djvu_document_get_n_pages;
|
||||
ev_document_class->get_page_size = djvu_document_get_page_size;
|
||||
ev_document_class->render = djvu_document_render;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
djvu_text_copy (DjvuDocument *djvu_document,
|
||||
gint page,
|
||||
EvRectangle *rectangle)
|
||||
{
|
||||
miniexp_t page_text;
|
||||
gchar *text = NULL;
|
||||
|
||||
while ((page_text =
|
||||
ddjvu_document_get_pagetext (djvu_document->d_document,
|
||||
page, "char")) == miniexp_dummy)
|
||||
djvu_handle_events (djvu_document, TRUE, NULL);
|
||||
|
||||
if (page_text != miniexp_nil) {
|
||||
DjvuTextPage *page = djvu_text_page_new (page_text);
|
||||
|
||||
text = djvu_text_page_copy (page, rectangle);
|
||||
djvu_text_page_free (page);
|
||||
ddjvu_miniexp_release (djvu_document->d_document, page_text);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
djvu_selection_get_selected_text (EvSelection *selection,
|
||||
EvPage *page,
|
||||
EvSelectionStyle style,
|
||||
EvRectangle *points)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (selection);
|
||||
double width, height;
|
||||
EvRectangle rectangle;
|
||||
gchar *text;
|
||||
|
||||
djvu_document_get_page_size (EV_DOCUMENT (djvu_document),
|
||||
page, &width, &height);
|
||||
rectangle.x1 = points->x1 / SCALE_FACTOR;
|
||||
rectangle.y1 = (height - points->y2) / SCALE_FACTOR;
|
||||
rectangle.x2 = points->x2 / SCALE_FACTOR;
|
||||
rectangle.y2 = (height - points->y1) / SCALE_FACTOR;
|
||||
|
||||
text = djvu_text_copy (djvu_document, page->index, &rectangle);
|
||||
|
||||
if (text == NULL)
|
||||
text = g_strdup ("");
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_selection_iface_init (EvSelectionInterface *iface)
|
||||
{
|
||||
iface->get_selected_text = djvu_selection_get_selected_text;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
gdouble page_width, page_height;
|
||||
|
||||
djvu_document_get_page_size (EV_DOCUMENT(djvu_document), rc->page,
|
||||
&page_width, &page_height);
|
||||
|
||||
if (rc->rotation == 90 || rc->rotation == 270) {
|
||||
*width = (gint) (page_height * rc->scale);
|
||||
*height = (gint) (page_width * rc->scale);
|
||||
} else {
|
||||
*width = (gint) (page_width * rc->scale);
|
||||
*height = (gint) (page_height * rc->scale);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
djvu_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gboolean border)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
GdkPixbuf *pixbuf, *rotated_pixbuf;
|
||||
gdouble page_width, page_height;
|
||||
gint thumb_width, thumb_height;
|
||||
guchar *pixels;
|
||||
|
||||
g_return_val_if_fail (djvu_document->d_document, NULL);
|
||||
|
||||
djvu_document_get_page_size (EV_DOCUMENT(djvu_document), rc->page,
|
||||
&page_width, &page_height);
|
||||
|
||||
thumb_width = (gint) (page_width * rc->scale);
|
||||
thumb_height = (gint) (page_height * rc->scale);
|
||||
|
||||
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
|
||||
thumb_width, thumb_height);
|
||||
gdk_pixbuf_fill (pixbuf, 0xffffffff);
|
||||
pixels = gdk_pixbuf_get_pixels (pixbuf);
|
||||
|
||||
while (ddjvu_thumbnail_status (djvu_document->d_document, rc->page->index, 1) < DDJVU_JOB_OK)
|
||||
djvu_handle_events(djvu_document, TRUE, NULL);
|
||||
|
||||
ddjvu_thumbnail_render (djvu_document->d_document, rc->page->index,
|
||||
&thumb_width, &thumb_height,
|
||||
djvu_document->thumbs_format,
|
||||
gdk_pixbuf_get_rowstride (pixbuf),
|
||||
(gchar *)pixels);
|
||||
|
||||
rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
if (border) {
|
||||
GdkPixbuf *tmp_pixbuf = rotated_pixbuf;
|
||||
|
||||
rotated_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
|
||||
g_object_unref (tmp_pixbuf);
|
||||
}
|
||||
|
||||
return rotated_pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
|
||||
{
|
||||
iface->get_thumbnail = djvu_document_thumbnails_get_thumbnail;
|
||||
iface->get_dimensions = djvu_document_thumbnails_get_dimensions;
|
||||
}
|
||||
|
||||
/* EvFileExporterIface */
|
||||
static void
|
||||
djvu_document_file_exporter_begin (EvFileExporter *exporter,
|
||||
EvFileExporterContext *fc)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
|
||||
|
||||
if (djvu_document->ps_filename)
|
||||
g_free (djvu_document->ps_filename);
|
||||
djvu_document->ps_filename = g_strdup (fc->filename);
|
||||
|
||||
g_string_assign (djvu_document->opts, "-page=");
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_file_exporter_do_page (EvFileExporter *exporter,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
|
||||
|
||||
g_string_append_printf (djvu_document->opts, "%d,", (rc->page->index) + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_file_exporter_end (EvFileExporter *exporter)
|
||||
{
|
||||
int d_optc = 1;
|
||||
const char *d_optv[d_optc];
|
||||
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (exporter);
|
||||
|
||||
FILE *fn = fopen (djvu_document->ps_filename, "w");
|
||||
if (fn == NULL) {
|
||||
g_warning ("Cannot open file “%s”.", djvu_document->ps_filename);
|
||||
return;
|
||||
}
|
||||
|
||||
d_optv[0] = djvu_document->opts->str;
|
||||
|
||||
ddjvu_job_t * job = ddjvu_document_print(djvu_document->d_document, fn, d_optc, d_optv);
|
||||
while (!ddjvu_job_done(job)) {
|
||||
djvu_handle_events (djvu_document, TRUE, NULL);
|
||||
}
|
||||
|
||||
fclose(fn);
|
||||
}
|
||||
|
||||
static EvFileExporterCapabilities
|
||||
djvu_document_file_exporter_get_capabilities (EvFileExporter *exporter)
|
||||
{
|
||||
return EV_FILE_EXPORTER_CAN_PAGE_SET |
|
||||
EV_FILE_EXPORTER_CAN_COPIES |
|
||||
EV_FILE_EXPORTER_CAN_COLLATE |
|
||||
EV_FILE_EXPORTER_CAN_REVERSE |
|
||||
EV_FILE_EXPORTER_CAN_GENERATE_PS;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_file_exporter_iface_init (EvFileExporterInterface *iface)
|
||||
{
|
||||
iface->begin = djvu_document_file_exporter_begin;
|
||||
iface->do_page = djvu_document_file_exporter_do_page;
|
||||
iface->end = djvu_document_file_exporter_end;
|
||||
iface->get_capabilities = djvu_document_file_exporter_get_capabilities;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_init (DjvuDocument *djvu_document)
|
||||
{
|
||||
guint masks[4] = { 0xff0000, 0xff00, 0xff, 0xff000000 };
|
||||
|
||||
djvu_document->d_context = ddjvu_context_create ("Atril");
|
||||
djvu_document->d_format = ddjvu_format_create (DDJVU_FORMAT_RGBMASK32, 4, masks);
|
||||
ddjvu_format_set_row_order (djvu_document->d_format, 1);
|
||||
|
||||
djvu_document->thumbs_format = ddjvu_format_create (DDJVU_FORMAT_RGB24, 0, 0);
|
||||
ddjvu_format_set_row_order (djvu_document->thumbs_format, 1);
|
||||
|
||||
djvu_document->ps_filename = NULL;
|
||||
djvu_document->opts = g_string_new ("");
|
||||
|
||||
djvu_document->d_document = NULL;
|
||||
}
|
||||
|
||||
static GList *
|
||||
djvu_document_find_find_text (EvDocumentFind *document,
|
||||
EvPage *page,
|
||||
const char *text,
|
||||
gboolean case_sensitive)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document);
|
||||
miniexp_t page_text;
|
||||
gdouble width, height;
|
||||
GList *matches = NULL, *l;
|
||||
|
||||
g_return_val_if_fail (text != NULL, NULL);
|
||||
|
||||
while ((page_text = ddjvu_document_get_pagetext (djvu_document->d_document,
|
||||
page->index,
|
||||
"char")) == miniexp_dummy)
|
||||
djvu_handle_events (djvu_document, TRUE, NULL);
|
||||
|
||||
if (page_text != miniexp_nil) {
|
||||
DjvuTextPage *tpage = djvu_text_page_new (page_text);
|
||||
|
||||
djvu_text_page_prepare_search (tpage, case_sensitive);
|
||||
if (tpage->links->len > 0) {
|
||||
djvu_text_page_search (tpage, text, case_sensitive);
|
||||
matches = tpage->results;
|
||||
}
|
||||
djvu_text_page_free (tpage);
|
||||
ddjvu_miniexp_release (djvu_document->d_document, page_text);
|
||||
}
|
||||
|
||||
if (!matches)
|
||||
return NULL;
|
||||
|
||||
document_get_page_size (djvu_document, page->index, &width, &height);
|
||||
for (l = matches; l && l->data; l = g_list_next (l)) {
|
||||
EvRectangle *r = (EvRectangle *)l->data;
|
||||
gdouble tmp = r->y1;
|
||||
|
||||
r->x1 *= SCALE_FACTOR;
|
||||
r->x2 *= SCALE_FACTOR;
|
||||
|
||||
r->y1 = height - r->y2 * SCALE_FACTOR;
|
||||
r->y2 = height - tmp * SCALE_FACTOR;
|
||||
}
|
||||
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_find_iface_init (EvDocumentFindInterface *iface)
|
||||
{
|
||||
iface->find_text = djvu_document_find_find_text;
|
||||
}
|
||||
|
||||
static EvMappingList *
|
||||
djvu_document_links_get_links (EvDocumentLinks *document_links,
|
||||
EvPage *page)
|
||||
{
|
||||
return djvu_links_get_links (document_links, page->index, SCALE_FACTOR);
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_document_document_links_iface_init (EvDocumentLinksInterface *iface)
|
||||
{
|
||||
iface->has_document_links = djvu_links_has_document_links;
|
||||
iface->get_links_model = djvu_links_get_links_model;
|
||||
iface->get_links = djvu_document_links_get_links;
|
||||
iface->find_link_dest = djvu_links_find_link_dest;
|
||||
iface->find_link_page = djvu_links_find_link_page;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* djvu-document.h: Implementation of EvDocument for djvu documents
|
||||
* Copyright (C) 2005, Nickolay V. Shmyrev <nshmyrev@yandex.ru>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DJVU_DOCUMENT_H__
|
||||
#define __DJVU_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define DJVU_TYPE_DOCUMENT (djvu_document_get_type ())
|
||||
#define DJVU_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DJVU_TYPE_DOCUMENT, DjvuDocument))
|
||||
#define DJVU_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DJVU_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _DjvuDocument DjvuDocument;
|
||||
|
||||
GType djvu_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DJVU_DOCUMENT_H__ */
|
|
@ -0,0 +1,456 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
|
||||
/*
|
||||
* Implements hyperlink functionality for Djvu files.
|
||||
* Copyright (C) 2006 Pauli Virtanen <pav@iki.fi>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <libdjvu/miniexp.h>
|
||||
#include "djvu-document.h"
|
||||
#include "djvu-links.h"
|
||||
#include "djvu-document-private.h"
|
||||
#include "ev-document-links.h"
|
||||
#include "ev-mapping-list.h"
|
||||
|
||||
static gboolean number_from_miniexp(miniexp_t sexp, int *number)
|
||||
{
|
||||
if (miniexp_numberp (sexp)) {
|
||||
*number = miniexp_to_int (sexp);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean string_from_miniexp(miniexp_t sexp, const char **str)
|
||||
{
|
||||
if (miniexp_stringp (sexp)) {
|
||||
*str = miniexp_to_str (sexp);
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean number_from_string_10(const gchar *str, guint64 *number)
|
||||
{
|
||||
gchar *end_ptr;
|
||||
|
||||
*number = g_ascii_strtoull(str, &end_ptr, 10);
|
||||
if (*end_ptr == '\0') {
|
||||
return TRUE;
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static guint64
|
||||
get_djvu_link_page (const DjvuDocument *djvu_document, const gchar *link_name, int base_page)
|
||||
{
|
||||
guint64 page_num = 0;
|
||||
|
||||
/* #pagenum, #+pageoffset, #-pageoffset */
|
||||
if (g_str_has_prefix (link_name, "#")) {
|
||||
if (base_page > 0 && g_str_has_prefix (link_name+1, "+")) {
|
||||
if (number_from_string_10 (link_name + 2, &page_num)) {
|
||||
return base_page + page_num;
|
||||
}
|
||||
} else if (base_page > 0 && g_str_has_prefix (link_name+1, "-")) {
|
||||
if (number_from_string_10 (link_name + 2, &page_num)) {
|
||||
return base_page - page_num;
|
||||
}
|
||||
} else {
|
||||
if (number_from_string_10 (link_name + 1, &page_num)) {
|
||||
return page_num - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* FIXME: component file identifiers */
|
||||
}
|
||||
|
||||
return page_num;
|
||||
}
|
||||
|
||||
static EvLinkDest *
|
||||
get_djvu_link_dest (const DjvuDocument *djvu_document, const gchar *link_name, int base_page)
|
||||
{
|
||||
return ev_link_dest_new_page (get_djvu_link_page (djvu_document, link_name, base_page));
|
||||
}
|
||||
|
||||
static EvLinkAction *
|
||||
get_djvu_link_action (const DjvuDocument *djvu_document, const gchar *link_name, int base_page)
|
||||
{
|
||||
EvLinkDest *ev_dest = NULL;
|
||||
EvLinkAction *ev_action = NULL;
|
||||
|
||||
ev_dest = get_djvu_link_dest (djvu_document, link_name, base_page);
|
||||
|
||||
if (ev_dest) {
|
||||
ev_action = ev_link_action_new_dest (ev_dest);
|
||||
} else if (strstr(link_name, "://") != NULL) {
|
||||
/* It's probably an URI */
|
||||
ev_action = ev_link_action_new_external_uri (link_name);
|
||||
} else {
|
||||
/* FIXME: component file identifiers */
|
||||
}
|
||||
|
||||
return ev_action;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
str_to_utf8 (const gchar *text)
|
||||
{
|
||||
static const gchar *encodings_to_try[2];
|
||||
static gint n_encodings_to_try = 0;
|
||||
gchar *utf8_text = NULL;
|
||||
gint i;
|
||||
|
||||
if (n_encodings_to_try == 0) {
|
||||
const gchar *charset;
|
||||
gboolean charset_is_utf8;
|
||||
|
||||
charset_is_utf8 = g_get_charset (&charset);
|
||||
if (!charset_is_utf8) {
|
||||
encodings_to_try[n_encodings_to_try++] = charset;
|
||||
}
|
||||
|
||||
if (g_ascii_strcasecmp (charset, "ISO-8859-1") != 0) {
|
||||
encodings_to_try[n_encodings_to_try++] = "ISO-8859-1";
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < n_encodings_to_try; i++) {
|
||||
utf8_text = g_convert (text, -1, "UTF-8",
|
||||
encodings_to_try[i],
|
||||
NULL, NULL, NULL);
|
||||
if (utf8_text)
|
||||
break;
|
||||
}
|
||||
|
||||
return utf8_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the index GtkTreeModel from DjVu s-expr
|
||||
*
|
||||
* (bookmarks
|
||||
* ("title1" "dest1"
|
||||
* ("title12" "dest12"
|
||||
* ... )
|
||||
* ... )
|
||||
* ("title2" "dest2"
|
||||
* ... )
|
||||
* ... )
|
||||
*/
|
||||
static void
|
||||
build_tree (const DjvuDocument *djvu_document,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *parent,
|
||||
miniexp_t iter)
|
||||
{
|
||||
const char *title, *link_dest;
|
||||
char *title_markup;
|
||||
|
||||
EvLinkAction *ev_action = NULL;
|
||||
EvLink *ev_link = NULL;
|
||||
GtkTreeIter tree_iter;
|
||||
|
||||
if (miniexp_car (iter) == miniexp_symbol ("bookmarks")) {
|
||||
/* The (bookmarks) cons */
|
||||
iter = miniexp_cdr (iter);
|
||||
} else if ( miniexp_length (iter) >= 2 ) {
|
||||
gchar *utf8_title = NULL;
|
||||
|
||||
/* An entry */
|
||||
if (!string_from_miniexp (miniexp_car (iter), &title)) goto unknown_entry;
|
||||
if (!string_from_miniexp (miniexp_cadr (iter), &link_dest)) goto unknown_entry;
|
||||
|
||||
|
||||
if (!g_utf8_validate (title, -1, NULL)) {
|
||||
utf8_title = str_to_utf8 (title);
|
||||
title_markup = g_markup_escape_text (utf8_title, -1);
|
||||
} else {
|
||||
title_markup = g_markup_escape_text (title, -1);
|
||||
}
|
||||
|
||||
ev_action = get_djvu_link_action (djvu_document, link_dest, -1);
|
||||
|
||||
if (g_str_has_suffix (link_dest, ".djvu")) {
|
||||
/* FIXME: component file identifiers */
|
||||
} else if (ev_action) {
|
||||
ev_link = ev_link_new (utf8_title ? utf8_title : title, ev_action);
|
||||
gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
|
||||
gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
|
||||
EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
|
||||
EV_DOCUMENT_LINKS_COLUMN_LINK, ev_link,
|
||||
EV_DOCUMENT_LINKS_COLUMN_EXPAND, FALSE,
|
||||
-1);
|
||||
g_object_unref (ev_link);
|
||||
} else {
|
||||
gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent);
|
||||
gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter,
|
||||
EV_DOCUMENT_LINKS_COLUMN_MARKUP, title_markup,
|
||||
EV_DOCUMENT_LINKS_COLUMN_EXPAND, FALSE,
|
||||
-1);
|
||||
}
|
||||
|
||||
g_free (title_markup);
|
||||
g_free (utf8_title);
|
||||
iter = miniexp_cddr (iter);
|
||||
parent = &tree_iter;
|
||||
} else {
|
||||
goto unknown_entry;
|
||||
}
|
||||
|
||||
for (; iter != miniexp_nil; iter = miniexp_cdr (iter)) {
|
||||
build_tree (djvu_document, model, parent, miniexp_car (iter));
|
||||
}
|
||||
return;
|
||||
|
||||
unknown_entry:
|
||||
g_warning ("DjvuLibre error: Unknown entry in bookmarks");
|
||||
return;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_djvu_hyperlink_area (ddjvu_pageinfo_t *page_info,
|
||||
miniexp_t sexp,
|
||||
EvMapping *ev_link_mapping)
|
||||
{
|
||||
miniexp_t iter;
|
||||
|
||||
iter = sexp;
|
||||
|
||||
if ((miniexp_car (iter) == miniexp_symbol ("rect") || miniexp_car (iter) == miniexp_symbol ("oval"))
|
||||
&& miniexp_length (iter) == 5) {
|
||||
/* FIXME: get bounding box for (oval) since Atril doesn't support shaped links */
|
||||
int minx, miny, width, height;
|
||||
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!number_from_miniexp (miniexp_car (iter), &minx)) goto unknown_link;
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!number_from_miniexp (miniexp_car (iter), &miny)) goto unknown_link;
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!number_from_miniexp (miniexp_car (iter), &width)) goto unknown_link;
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!number_from_miniexp (miniexp_car (iter), &height)) goto unknown_link;
|
||||
|
||||
ev_link_mapping->area.x1 = minx;
|
||||
ev_link_mapping->area.x2 = (minx + width);
|
||||
ev_link_mapping->area.y1 = (page_info->height - (miny + height));
|
||||
ev_link_mapping->area.y2 = (page_info->height - miny);
|
||||
} else if (miniexp_car (iter) == miniexp_symbol ("poly")
|
||||
&& miniexp_length (iter) >= 5 && miniexp_length (iter) % 2 == 1) {
|
||||
|
||||
/* FIXME: get bounding box since Atril doesn't support shaped links */
|
||||
int minx = G_MAXINT, miny = G_MAXINT;
|
||||
int maxx = G_MININT, maxy = G_MININT;
|
||||
|
||||
iter = miniexp_cdr(iter);
|
||||
while (iter != miniexp_nil) {
|
||||
int x, y;
|
||||
|
||||
if (!number_from_miniexp (miniexp_car(iter), &x)) goto unknown_link;
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!number_from_miniexp (miniexp_car(iter), &y)) goto unknown_link;
|
||||
iter = miniexp_cdr (iter);
|
||||
|
||||
minx = MIN (minx, x);
|
||||
miny = MIN (miny, y);
|
||||
maxx = MAX (maxx, x);
|
||||
maxy = MAX (maxy, y);
|
||||
}
|
||||
|
||||
ev_link_mapping->area.x1 = minx;
|
||||
ev_link_mapping->area.x2 = maxx;
|
||||
ev_link_mapping->area.y1 = (page_info->height - maxy);
|
||||
ev_link_mapping->area.y2 = (page_info->height - miny);
|
||||
} else {
|
||||
/* unknown */
|
||||
goto unknown_link;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
unknown_link:
|
||||
g_warning("DjvuLibre error: Unknown hyperlink area %s", miniexp_to_name(miniexp_car(sexp)));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static EvMapping *
|
||||
get_djvu_hyperlink_mapping (DjvuDocument *djvu_document,
|
||||
int page,
|
||||
ddjvu_pageinfo_t *page_info,
|
||||
miniexp_t sexp)
|
||||
{
|
||||
EvMapping *ev_link_mapping = NULL;
|
||||
EvLinkAction *ev_action = NULL;
|
||||
miniexp_t iter;
|
||||
const char *url, *url_target, *comment;
|
||||
|
||||
ev_link_mapping = g_new (EvMapping, 1);
|
||||
|
||||
iter = sexp;
|
||||
|
||||
if (miniexp_car (iter) != miniexp_symbol ("maparea")) goto unknown_mapping;
|
||||
|
||||
iter = miniexp_cdr(iter);
|
||||
|
||||
if (miniexp_caar(iter) == miniexp_symbol("url")) {
|
||||
if (!string_from_miniexp (miniexp_cadr (miniexp_car (iter)), &url)) goto unknown_mapping;
|
||||
if (!string_from_miniexp (miniexp_caddr (miniexp_car (iter)), &url_target)) goto unknown_mapping;
|
||||
} else {
|
||||
if (!string_from_miniexp (miniexp_car(iter), &url)) goto unknown_mapping;
|
||||
url_target = NULL;
|
||||
}
|
||||
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!string_from_miniexp (miniexp_car(iter), &comment)) goto unknown_mapping;
|
||||
|
||||
iter = miniexp_cdr (iter);
|
||||
if (!get_djvu_hyperlink_area (page_info, miniexp_car(iter), ev_link_mapping)) goto unknown_mapping;
|
||||
|
||||
iter = miniexp_cdr (iter);
|
||||
/* FIXME: DjVu hyperlink attributes are ignored */
|
||||
|
||||
ev_action = get_djvu_link_action (djvu_document, url, page);
|
||||
if (!ev_action) goto unknown_mapping;
|
||||
|
||||
ev_link_mapping->data = ev_link_new (comment, ev_action);
|
||||
|
||||
return ev_link_mapping;
|
||||
|
||||
unknown_mapping:
|
||||
if (ev_link_mapping) g_free(ev_link_mapping);
|
||||
g_warning("DjvuLibre error: Unknown hyperlink %s", miniexp_to_name(miniexp_car(sexp)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
djvu_links_has_document_links (EvDocumentLinks *document_links)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document_links);
|
||||
miniexp_t outline;
|
||||
|
||||
while ((outline = ddjvu_document_get_outline (djvu_document->d_document)) == miniexp_dummy)
|
||||
djvu_handle_events (djvu_document, TRUE, NULL);
|
||||
|
||||
if (outline) {
|
||||
ddjvu_miniexp_release (djvu_document->d_document, outline);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
EvMappingList *
|
||||
djvu_links_get_links (EvDocumentLinks *document_links,
|
||||
gint page,
|
||||
double scale_factor)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document_links);
|
||||
GList *retval = NULL;
|
||||
miniexp_t page_annotations = miniexp_nil;
|
||||
miniexp_t *hyperlinks = NULL, *iter = NULL;
|
||||
EvMapping *ev_link_mapping;
|
||||
ddjvu_pageinfo_t page_info;
|
||||
|
||||
while ((page_annotations = ddjvu_document_get_pageanno (djvu_document->d_document, page)) == miniexp_dummy)
|
||||
djvu_handle_events (djvu_document, TRUE, NULL);
|
||||
|
||||
while (ddjvu_document_get_pageinfo (djvu_document->d_document, page, &page_info) < DDJVU_JOB_OK)
|
||||
djvu_handle_events(djvu_document, TRUE, NULL);
|
||||
|
||||
if (page_annotations) {
|
||||
hyperlinks = ddjvu_anno_get_hyperlinks (page_annotations);
|
||||
if (hyperlinks) {
|
||||
for (iter = hyperlinks; *iter; ++iter) {
|
||||
ev_link_mapping = get_djvu_hyperlink_mapping (djvu_document, page, &page_info, *iter);
|
||||
if (ev_link_mapping) {
|
||||
ev_link_mapping->area.x1 *= scale_factor;
|
||||
ev_link_mapping->area.x2 *= scale_factor;
|
||||
ev_link_mapping->area.y1 *= scale_factor;
|
||||
ev_link_mapping->area.y2 *= scale_factor;
|
||||
retval = g_list_prepend (retval, ev_link_mapping);
|
||||
}
|
||||
}
|
||||
free (hyperlinks);
|
||||
}
|
||||
ddjvu_miniexp_release (djvu_document->d_document, page_annotations);
|
||||
}
|
||||
|
||||
return ev_mapping_list_new (page, retval, (GDestroyNotify)g_object_unref);
|
||||
}
|
||||
|
||||
EvLinkDest *
|
||||
djvu_links_find_link_dest (EvDocumentLinks *document_links,
|
||||
const gchar *link_name)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document_links);
|
||||
EvLinkDest *ev_dest = NULL;
|
||||
|
||||
ev_dest = get_djvu_link_dest (djvu_document, link_name, -1);
|
||||
|
||||
if (!ev_dest) {
|
||||
g_warning ("DjvuLibre error: unknown link destination %s", link_name);
|
||||
}
|
||||
|
||||
return ev_dest;
|
||||
}
|
||||
|
||||
gint
|
||||
djvu_links_find_link_page (EvDocumentLinks *document_links,
|
||||
const gchar *link_name)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document_links);
|
||||
gint page;
|
||||
|
||||
page = get_djvu_link_page (djvu_document, link_name, -1);
|
||||
|
||||
if (page == -1) {
|
||||
g_warning ("DjvuLibre error: unknown link destination %s", link_name);
|
||||
}
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
GtkTreeModel *
|
||||
djvu_links_get_links_model (EvDocumentLinks *document_links)
|
||||
{
|
||||
DjvuDocument *djvu_document = DJVU_DOCUMENT (document_links);
|
||||
GtkTreeModel *model = NULL;
|
||||
miniexp_t outline = miniexp_nil;
|
||||
|
||||
while ((outline = ddjvu_document_get_outline (djvu_document->d_document)) == miniexp_dummy)
|
||||
djvu_handle_events (djvu_document, TRUE, NULL);
|
||||
|
||||
if (outline) {
|
||||
model = (GtkTreeModel *) gtk_tree_store_new (EV_DOCUMENT_LINKS_COLUMN_NUM_COLUMNS,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_OBJECT,
|
||||
G_TYPE_BOOLEAN,
|
||||
G_TYPE_STRING);
|
||||
build_tree (djvu_document, model, NULL, outline);
|
||||
|
||||
ddjvu_miniexp_release (djvu_document->d_document, outline);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Pauli Virtanen <pav@iki.fi>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DJVU_LINK_H__
|
||||
#define __DJVU_LINK_H__
|
||||
|
||||
#include "ev-document-links.h"
|
||||
#include "djvu-document.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
GtkTreeModel *djvu_links_get_links_model (EvDocumentLinks *document_links);
|
||||
EvMappingList *djvu_links_get_links (EvDocumentLinks *document_links,
|
||||
gint page,
|
||||
double scale_factor);
|
||||
EvLinkDest *djvu_links_find_link_dest (EvDocumentLinks *document_links,
|
||||
const gchar *link_name);
|
||||
gint djvu_links_find_link_page (EvDocumentLinks *document_links,
|
||||
const gchar *link_name);
|
||||
gboolean djvu_links_has_document_links (EvDocumentLinks *document_links);
|
||||
|
||||
#endif /* __DJVU_LINK_H__ */
|
|
@ -0,0 +1,456 @@
|
|||
/*
|
||||
* Implements search and copy functionality for Djvu files.
|
||||
* Copyright (C) 2006 Michael Hofmann <mh21@piware.de>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <libdjvu/miniexp.h>
|
||||
#include "djvu-text-page.h"
|
||||
|
||||
|
||||
/**
|
||||
* djvu_text_page_selection_process:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @p: s-expression to append
|
||||
* @delimit: character/word/... delimiter
|
||||
*
|
||||
* Appends the string in @p to the page text.
|
||||
*
|
||||
* Returns: whether the end was not reached in this s-expression
|
||||
*/
|
||||
static gboolean
|
||||
djvu_text_page_selection_process (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
int delimit)
|
||||
{
|
||||
if (page->text || p == page->start) {
|
||||
char *token_text = (char *) miniexp_to_str (miniexp_nth (5, p));
|
||||
if (page->text) {
|
||||
char *new_text =
|
||||
g_strjoin (delimit & 2 ? "\n" :
|
||||
delimit & 1 ? " " : NULL,
|
||||
page->text, token_text,
|
||||
NULL);
|
||||
g_free (page->text);
|
||||
page->text = new_text;
|
||||
} else
|
||||
page->text = g_strdup (token_text);
|
||||
if (p == page->end)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_selection:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @p: tree to append
|
||||
* @delimit: character/word/... delimiter
|
||||
*
|
||||
* Walks the tree in @p and appends the text with
|
||||
* djvu_text_page_selection_process() for all s-expressions
|
||||
* between the start and end fields.
|
||||
*
|
||||
* Returns: whether the end was not reached in this subtree
|
||||
*/
|
||||
static gboolean
|
||||
djvu_text_page_selection (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
int delimit)
|
||||
{
|
||||
g_return_val_if_fail (miniexp_consp (p) && miniexp_symbolp
|
||||
(miniexp_car (p)), FALSE);
|
||||
|
||||
if (miniexp_car (p) != page->char_symbol)
|
||||
delimit |= miniexp_car (p) == page->word_symbol ? 1 : 2;
|
||||
|
||||
miniexp_t deeper = miniexp_cddr (miniexp_cdddr (p));
|
||||
while (deeper != miniexp_nil) {
|
||||
miniexp_t str = miniexp_car (deeper);
|
||||
if (miniexp_stringp (str)) {
|
||||
if (!djvu_text_page_selection_process
|
||||
(page, p, delimit))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!djvu_text_page_selection
|
||||
(page, str, delimit))
|
||||
return FALSE;
|
||||
}
|
||||
delimit = 0;
|
||||
deeper = miniexp_cdr (deeper);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
djvu_text_page_limits_process (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
EvRectangle *rect)
|
||||
{
|
||||
EvRectangle current;
|
||||
|
||||
current.x1 = miniexp_to_int (miniexp_nth (1, p));
|
||||
current.y1 = miniexp_to_int (miniexp_nth (2, p));
|
||||
current.x2 = miniexp_to_int (miniexp_nth (3, p));
|
||||
current.y2 = miniexp_to_int (miniexp_nth (4, p));
|
||||
if (current.x2 >= rect->x1 && current.y1 <= rect->y2 &&
|
||||
current.x1 <= rect->x2 && current.y2 >= rect->y1) {
|
||||
if (page->start == miniexp_nil)
|
||||
page->start = p;
|
||||
page->end = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
djvu_text_page_limits (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
EvRectangle *rect)
|
||||
{
|
||||
g_return_if_fail (miniexp_consp (p) &&
|
||||
miniexp_symbolp (miniexp_car (p)));
|
||||
|
||||
miniexp_t deeper = miniexp_cddr (miniexp_cdddr (p));
|
||||
while (deeper != miniexp_nil) {
|
||||
miniexp_t str = miniexp_car (deeper);
|
||||
if (miniexp_stringp (str))
|
||||
djvu_text_page_limits_process (page, p, rect);
|
||||
else
|
||||
djvu_text_page_limits (page, str, rect);
|
||||
|
||||
deeper = miniexp_cdr (deeper);
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
djvu_text_page_copy (DjvuTextPage *page,
|
||||
EvRectangle *rectangle)
|
||||
{
|
||||
char* text;
|
||||
|
||||
page->start = miniexp_nil;
|
||||
page->end = miniexp_nil;
|
||||
djvu_text_page_limits (page, page->text_structure, rectangle);
|
||||
djvu_text_page_selection (page, page->text_structure, 0);
|
||||
|
||||
/* Do not free the string */
|
||||
text = page->text;
|
||||
page->text = NULL;
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_position:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @position: index in the page text
|
||||
*
|
||||
* Returns the closest s-expression that contains the given position in
|
||||
* the page text.
|
||||
*
|
||||
* Returns: closest s-expression
|
||||
*/
|
||||
static miniexp_t
|
||||
djvu_text_page_position (DjvuTextPage *page,
|
||||
int position)
|
||||
{
|
||||
GArray *links = page->links;
|
||||
int low = 0;
|
||||
int hi = links->len - 1;
|
||||
int mid = 0;
|
||||
|
||||
g_return_val_if_fail (hi >= 0, miniexp_nil);
|
||||
|
||||
/* Shamelessly copied from GNU classpath */
|
||||
while (low <= hi) {
|
||||
mid = (low + hi) >> 1;
|
||||
DjvuTextLink *link =
|
||||
&g_array_index (links, DjvuTextLink, mid);
|
||||
if (link->position == position)
|
||||
break;
|
||||
else if (link->position > position)
|
||||
hi = --mid;
|
||||
else
|
||||
low = mid + 1;
|
||||
}
|
||||
|
||||
return g_array_index (page->links, DjvuTextLink, mid).pair;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_union:
|
||||
* @target: first rectangle and result
|
||||
* @source: second rectangle
|
||||
*
|
||||
* Calculates the bounding box of two rectangles and stores the reuslt
|
||||
* in the first.
|
||||
*/
|
||||
static void
|
||||
djvu_text_page_union (EvRectangle *target,
|
||||
EvRectangle *source)
|
||||
{
|
||||
if (source->x1 < target->x1)
|
||||
target->x1 = source->x1;
|
||||
if (source->x2 > target->x2)
|
||||
target->x2 = source->x2;
|
||||
if (source->y1 < target->y1)
|
||||
target->y1 = source->y1;
|
||||
if (source->y2 > target->y2)
|
||||
target->y2 = source->y2;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_sexpr_process:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @p: s-expression to append
|
||||
* @start: first s-expression in the selection
|
||||
* @end: last s-expression in the selection
|
||||
*
|
||||
* Appends the rectangle defined by @p to the internal bounding box rectangle.
|
||||
*
|
||||
* Returns: whether the end was not reached in this s-expression
|
||||
*/
|
||||
static gboolean
|
||||
djvu_text_page_sexpr_process (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
miniexp_t start,
|
||||
miniexp_t end)
|
||||
{
|
||||
if (page->bounding_box || p == start) {
|
||||
EvRectangle *new_rectangle = ev_rectangle_new ();
|
||||
new_rectangle->x1 = miniexp_to_int (miniexp_nth (1, p));
|
||||
new_rectangle->y1 = miniexp_to_int (miniexp_nth (2, p));
|
||||
new_rectangle->x2 = miniexp_to_int (miniexp_nth (3, p));
|
||||
new_rectangle->y2 = miniexp_to_int (miniexp_nth (4, p));
|
||||
if (page->bounding_box) {
|
||||
djvu_text_page_union (page->bounding_box,
|
||||
new_rectangle);
|
||||
g_free (new_rectangle);
|
||||
} else
|
||||
page->bounding_box = new_rectangle;
|
||||
if (p == end)
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_sexpr:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @p: tree to append
|
||||
* @start: first s-expression in the selection
|
||||
* @end: last s-expression in the selection
|
||||
*
|
||||
* Walks the tree in @p and extends the rectangle with
|
||||
* djvu_text_page_process() for all s-expressions between @start and @end.
|
||||
*
|
||||
* Returns: whether the end was not reached in this subtree
|
||||
*/
|
||||
static gboolean
|
||||
djvu_text_page_sexpr (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
miniexp_t start,
|
||||
miniexp_t end)
|
||||
{
|
||||
g_return_val_if_fail (miniexp_consp (p) && miniexp_symbolp
|
||||
(miniexp_car (p)), FALSE);
|
||||
|
||||
miniexp_t deeper = miniexp_cddr (miniexp_cdddr (p));
|
||||
while (deeper != miniexp_nil) {
|
||||
miniexp_t str = miniexp_car (deeper);
|
||||
if (miniexp_stringp (str)) {
|
||||
if (!djvu_text_page_sexpr_process
|
||||
(page, p, start, end))
|
||||
return FALSE;
|
||||
} else {
|
||||
if (!djvu_text_page_sexpr
|
||||
(page, str, start, end))
|
||||
return FALSE;
|
||||
}
|
||||
deeper = miniexp_cdr (deeper);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_box:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @start: first s-expression in the selection
|
||||
* @end: last s-expression in the selection
|
||||
*
|
||||
* Builds a rectangle that contains all s-expressions in the given range.
|
||||
*/
|
||||
static EvRectangle *
|
||||
djvu_text_page_box (DjvuTextPage *page,
|
||||
miniexp_t start,
|
||||
miniexp_t end)
|
||||
{
|
||||
page->bounding_box = NULL;
|
||||
djvu_text_page_sexpr (page, page->text_structure, start, end);
|
||||
return page->bounding_box;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_append_search:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @p: tree to append
|
||||
* @case_sensitive: do not ignore case
|
||||
* @delimit: insert spaces because of higher (sentence/paragraph/...) break
|
||||
*
|
||||
* Appends the tree in @p to the internal text string.
|
||||
*/
|
||||
static void
|
||||
djvu_text_page_append_text (DjvuTextPage *page,
|
||||
miniexp_t p,
|
||||
gboolean case_sensitive,
|
||||
gboolean delimit)
|
||||
{
|
||||
char *token_text;
|
||||
|
||||
g_return_if_fail (miniexp_consp (p) &&
|
||||
miniexp_symbolp (miniexp_car (p)));
|
||||
|
||||
delimit |= page->char_symbol != miniexp_car (p);
|
||||
|
||||
miniexp_t deeper = miniexp_cddr (miniexp_cdddr (p));
|
||||
while (deeper != miniexp_nil) {
|
||||
miniexp_t data = miniexp_car (deeper);
|
||||
if (miniexp_stringp (data)) {
|
||||
DjvuTextLink link;
|
||||
link.position = page->text == NULL ? 0 :
|
||||
strlen (page->text);
|
||||
link.pair = p;
|
||||
g_array_append_val (page->links, link);
|
||||
|
||||
token_text = (char *) miniexp_to_str (data);
|
||||
if (!case_sensitive)
|
||||
token_text = g_utf8_casefold (token_text, -1);
|
||||
if (page->text == NULL)
|
||||
page->text = g_strdup (token_text);
|
||||
else {
|
||||
char *new_text =
|
||||
g_strjoin (delimit ? " " : NULL,
|
||||
page->text, token_text,
|
||||
NULL);
|
||||
g_free (page->text);
|
||||
page->text = new_text;
|
||||
}
|
||||
if (!case_sensitive)
|
||||
g_free (token_text);
|
||||
} else
|
||||
djvu_text_page_append_text (page, data,
|
||||
case_sensitive, delimit);
|
||||
delimit = FALSE;
|
||||
deeper = miniexp_cdr (deeper);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_search:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @text: text to search
|
||||
* @case_sensitive: do not ignore case
|
||||
*
|
||||
* Searches the page for the given text. The results list has to be
|
||||
* externally freed afterwards.
|
||||
*/
|
||||
void
|
||||
djvu_text_page_search (DjvuTextPage *page,
|
||||
const char *text,
|
||||
gboolean case_sensitive)
|
||||
{
|
||||
char *haystack = page->text;
|
||||
char *search_text;
|
||||
int search_len;
|
||||
EvRectangle *result;
|
||||
if (page->links->len == 0)
|
||||
return;
|
||||
|
||||
search_len = strlen (text);
|
||||
|
||||
if (case_sensitive)
|
||||
search_text = g_strdup (text);
|
||||
else
|
||||
search_text = g_utf8_casefold (text, search_len);
|
||||
|
||||
while ((haystack = strstr (haystack, search_text)) != NULL) {
|
||||
int start_p = haystack - page->text;
|
||||
miniexp_t start = djvu_text_page_position (page, start_p);
|
||||
int end_p = start_p + search_len - 1;
|
||||
miniexp_t end = djvu_text_page_position (page, end_p);
|
||||
result = djvu_text_page_box (page, start, end);
|
||||
g_assert (result);
|
||||
page->results = g_list_prepend (page->results, result);
|
||||
haystack = haystack + search_len;
|
||||
}
|
||||
page->results = g_list_reverse (page->results);
|
||||
|
||||
g_free (search_text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* djvu_text_page_prepare_search:
|
||||
* @page: #DjvuTextPage instance
|
||||
* @case_sensitive: do not ignore case
|
||||
*
|
||||
* Indexes the page text and prepares the page for subsequent searches.
|
||||
*/
|
||||
void
|
||||
djvu_text_page_prepare_search (DjvuTextPage *page,
|
||||
gboolean case_sensitive)
|
||||
{
|
||||
djvu_text_page_append_text (page, page->text_structure,
|
||||
case_sensitive, FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_new:
|
||||
* @text: S-expression of the page text
|
||||
*
|
||||
* Creates a new page to search.
|
||||
*
|
||||
* Returns: new #DjvuTextPage instance
|
||||
*/
|
||||
DjvuTextPage *
|
||||
djvu_text_page_new (miniexp_t text)
|
||||
{
|
||||
DjvuTextPage *page;
|
||||
|
||||
page = g_new0 (DjvuTextPage, 1);
|
||||
page->links = g_array_new (FALSE, FALSE, sizeof (DjvuTextLink));
|
||||
page->char_symbol = miniexp_symbol ("char");
|
||||
page->word_symbol = miniexp_symbol ("word");
|
||||
page->text_structure = text;
|
||||
return page;
|
||||
}
|
||||
|
||||
/**
|
||||
* djvu_text_page_free:
|
||||
* @page: #DjvuTextPage instance
|
||||
*
|
||||
* Frees the given #DjvuTextPage instance.
|
||||
*/
|
||||
void
|
||||
djvu_text_page_free (DjvuTextPage *page)
|
||||
{
|
||||
g_free (page->text);
|
||||
g_array_free (page->links, TRUE);
|
||||
g_free (page);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2006 Michael Hofmann <mh21@piware.de>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DJVU_TEXT_PAGE_H__
|
||||
#define __DJVU_TEXT_PAGE_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <glib.h>
|
||||
#include <libdjvu/miniexp.h>
|
||||
|
||||
|
||||
typedef struct _DjvuTextPage DjvuTextPage;
|
||||
typedef struct _DjvuTextLink DjvuTextLink;
|
||||
|
||||
struct _DjvuTextPage {
|
||||
char *text;
|
||||
GArray *links;
|
||||
GList *results;
|
||||
miniexp_t char_symbol;
|
||||
miniexp_t word_symbol;
|
||||
EvRectangle *bounding_box;
|
||||
miniexp_t text_structure;
|
||||
miniexp_t start;
|
||||
miniexp_t end;
|
||||
};
|
||||
|
||||
struct _DjvuTextLink {
|
||||
int position;
|
||||
miniexp_t pair;
|
||||
};
|
||||
|
||||
char * djvu_text_page_copy (DjvuTextPage *page,
|
||||
EvRectangle *rectangle);
|
||||
void djvu_text_page_prepare_search (DjvuTextPage *page,
|
||||
gboolean case_sensitive);
|
||||
void djvu_text_page_search (DjvuTextPage *page,
|
||||
const char *text,
|
||||
gboolean case_sensitive);
|
||||
DjvuTextPage* djvu_text_page_new (miniexp_t text);
|
||||
void djvu_text_page_free (DjvuTextPage *page);
|
||||
|
||||
#endif /* __DJVU_TEXT_PAGE_H__ */
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[Atril Backend]
|
||||
Module=djvudocument
|
||||
TypeDescription=DjVu Documents
|
||||
MimeType=image/vnd.djvu;image/vnd.djvu+multipage
|
|
@ -0,0 +1,45 @@
|
|||
SUBDIRS = mdvi-lib
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-I$(srcdir)/mdvi-lib \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(WARN_CFLAGS) \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(SPECTRE_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libdvidocument.la
|
||||
|
||||
libdvidocument_la_SOURCES = \
|
||||
dvi-document.c \
|
||||
dvi-document.h \
|
||||
cairo-device.c \
|
||||
cairo-device.h \
|
||||
fonts.c \
|
||||
fonts.h
|
||||
|
||||
libdvidocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libdvidocument_la_LIBADD = \
|
||||
mdvi-lib/libmdvi.la \
|
||||
-lkpathsea \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS) \
|
||||
$(SPECTRE_LIBS)
|
||||
|
||||
if WITH_TYPE1_FONTS
|
||||
libdvidocument_la_LIBADD += -lt1
|
||||
endif
|
||||
|
||||
backend_in_files = dvidocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,372 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <gdk/gdk.h>
|
||||
#ifdef HAVE_SPECTRE
|
||||
#include <libspectre/spectre.h>
|
||||
#endif
|
||||
|
||||
#include "cairo-device.h"
|
||||
|
||||
typedef struct {
|
||||
cairo_t *cr;
|
||||
|
||||
gint xmargin;
|
||||
gint ymargin;
|
||||
|
||||
gdouble scale;
|
||||
|
||||
Ulong fg;
|
||||
Ulong bg;
|
||||
|
||||
} DviCairoDevice;
|
||||
|
||||
static void
|
||||
dvi_cairo_draw_glyph (DviContext *dvi,
|
||||
DviFontChar *ch,
|
||||
int x0,
|
||||
int y0)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
int x, y, w, h;
|
||||
gboolean isbox;
|
||||
DviGlyph *glyph;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
cairo_device = (DviCairoDevice *) dvi->device.device_data;
|
||||
|
||||
glyph = &ch->grey;
|
||||
|
||||
isbox = (glyph->data == NULL ||
|
||||
(dvi->params.flags & MDVI_PARAM_CHARBOXES) ||
|
||||
MDVI_GLYPH_ISEMPTY (glyph->data));
|
||||
|
||||
x = - glyph->x + x0 + cairo_device->xmargin;
|
||||
y = - glyph->y + y0 + cairo_device->ymargin;
|
||||
w = glyph->w;
|
||||
h = glyph->h;
|
||||
|
||||
surface = cairo_get_target (cairo_device->cr);
|
||||
if (x < 0 || y < 0
|
||||
|| x + w > cairo_image_surface_get_width (surface)
|
||||
|| y + h > cairo_image_surface_get_height (surface))
|
||||
return;
|
||||
|
||||
cairo_save (cairo_device->cr);
|
||||
if (isbox) {
|
||||
cairo_rectangle (cairo_device->cr,
|
||||
x - cairo_device->xmargin,
|
||||
y - cairo_device->ymargin,
|
||||
w, h);
|
||||
cairo_stroke (cairo_device->cr);
|
||||
} else {
|
||||
cairo_translate (cairo_device->cr, x, y);
|
||||
cairo_set_source_surface (cairo_device->cr,
|
||||
(cairo_surface_t *) glyph->data,
|
||||
0, 0);
|
||||
cairo_paint (cairo_device->cr);
|
||||
}
|
||||
|
||||
cairo_restore (cairo_device->cr);
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_cairo_draw_rule (DviContext *dvi,
|
||||
int x,
|
||||
int y,
|
||||
Uint width,
|
||||
Uint height,
|
||||
int fill)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
Ulong color;
|
||||
|
||||
cairo_device = (DviCairoDevice *) dvi->device.device_data;
|
||||
|
||||
color = cairo_device->fg;
|
||||
|
||||
cairo_save (cairo_device->cr);
|
||||
|
||||
cairo_set_line_width (cairo_device->cr,
|
||||
cairo_get_line_width (cairo_device->cr) * cairo_device->scale);
|
||||
cairo_set_source_rgb (cairo_device->cr,
|
||||
((color >> 16) & 0xff) / 255.,
|
||||
((color >> 8) & 0xff) / 255.,
|
||||
((color >> 0) & 0xff) / 255.);
|
||||
|
||||
cairo_rectangle (cairo_device->cr,
|
||||
x + cairo_device->xmargin,
|
||||
y + cairo_device->ymargin,
|
||||
width, height);
|
||||
if (fill == 0) {
|
||||
cairo_stroke (cairo_device->cr);
|
||||
} else {
|
||||
cairo_fill (cairo_device->cr);
|
||||
}
|
||||
|
||||
cairo_restore (cairo_device->cr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SPECTRE
|
||||
static void
|
||||
dvi_cairo_draw_ps (DviContext *dvi,
|
||||
const char *filename,
|
||||
int x,
|
||||
int y,
|
||||
Uint width,
|
||||
Uint height)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
unsigned char *data = NULL;
|
||||
int row_length;
|
||||
SpectreDocument *psdoc;
|
||||
SpectreRenderContext *rc;
|
||||
int w, h;
|
||||
SpectreStatus status;
|
||||
cairo_surface_t *image;
|
||||
|
||||
cairo_device = (DviCairoDevice *) dvi->device.device_data;
|
||||
|
||||
psdoc = spectre_document_new ();
|
||||
spectre_document_load (psdoc, filename);
|
||||
if (spectre_document_status (psdoc)) {
|
||||
spectre_document_free (psdoc);
|
||||
return;
|
||||
}
|
||||
|
||||
spectre_document_get_page_size (psdoc, &w, &h);
|
||||
|
||||
rc = spectre_render_context_new ();
|
||||
spectre_render_context_set_scale (rc,
|
||||
(double)width / w,
|
||||
(double)height / h);
|
||||
spectre_document_render_full (psdoc, rc, &data, &row_length);
|
||||
status = spectre_document_status (psdoc);
|
||||
|
||||
spectre_render_context_free (rc);
|
||||
spectre_document_free (psdoc);
|
||||
|
||||
if (status) {
|
||||
g_warning ("Error rendering PS document %s: %s\n",
|
||||
filename, spectre_status_to_string (status));
|
||||
free (data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
image = cairo_image_surface_create_for_data ((unsigned char *)data,
|
||||
CAIRO_FORMAT_RGB24,
|
||||
width, height,
|
||||
row_length);
|
||||
|
||||
cairo_save (cairo_device->cr);
|
||||
|
||||
cairo_translate (cairo_device->cr,
|
||||
x + cairo_device->xmargin,
|
||||
y + cairo_device->ymargin);
|
||||
cairo_set_source_surface (cairo_device->cr, image, 0, 0);
|
||||
cairo_paint (cairo_device->cr);
|
||||
|
||||
cairo_restore (cairo_device->cr);
|
||||
|
||||
cairo_surface_destroy (image);
|
||||
free (data);
|
||||
}
|
||||
#endif /* HAVE_SPECTRE */
|
||||
|
||||
static int
|
||||
dvi_cairo_alloc_colors (void *device_data,
|
||||
Ulong *pixels,
|
||||
int npixels,
|
||||
Ulong fg,
|
||||
Ulong bg,
|
||||
double gamma,
|
||||
int density)
|
||||
{
|
||||
double frac;
|
||||
GdkColor color, color_fg;
|
||||
int i, n;
|
||||
unsigned int alpha;
|
||||
|
||||
color_fg.red = (fg >> 16) & 0xff;
|
||||
color_fg.green = (fg >> 8) & 0xff;
|
||||
color_fg.blue = (fg >> 0) & 0xff;
|
||||
|
||||
n = npixels - 1;
|
||||
for (i = 0; i < npixels; i++) {
|
||||
frac = (gamma > 0) ?
|
||||
pow ((double)i / n, 1 / gamma) :
|
||||
1 - pow ((double)(n - i) / n, -gamma);
|
||||
|
||||
color.red = frac * color_fg.red;
|
||||
color.green = frac * color_fg.green;
|
||||
color.blue = frac * color_fg.blue;
|
||||
alpha = frac * 0xFF;
|
||||
|
||||
pixels[i] = (alpha << 24) + (color.red << 16) + (color.green << 8) + color.blue;
|
||||
}
|
||||
|
||||
return npixels;
|
||||
}
|
||||
|
||||
static void *
|
||||
dvi_cairo_create_image (void *device_data,
|
||||
Uint width,
|
||||
Uint height,
|
||||
Uint bpp)
|
||||
{
|
||||
return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_cairo_free_image (void *ptr)
|
||||
{
|
||||
cairo_surface_destroy ((cairo_surface_t *)ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_cairo_put_pixel (void *image, int x, int y, Ulong color)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
gint rowstride;
|
||||
guint32 *p;
|
||||
|
||||
surface = (cairo_surface_t *) image;
|
||||
|
||||
rowstride = cairo_image_surface_get_stride (surface);
|
||||
p = (guint32*) (cairo_image_surface_get_data (surface) + y * rowstride + x * 4);
|
||||
|
||||
/* per cairo docs, must flush before modifying outside of cairo */
|
||||
cairo_surface_flush(surface);
|
||||
*p = color;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_cairo_image_done (void *ptr)
|
||||
{
|
||||
cairo_surface_mark_dirty((cairo_surface_t *)ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_cairo_set_color (void *device_data, Ulong fg, Ulong bg)
|
||||
{
|
||||
DviCairoDevice *cairo_device = (DviCairoDevice *) device_data;
|
||||
|
||||
cairo_device->fg = fg;
|
||||
cairo_device->bg = bg;
|
||||
}
|
||||
|
||||
/* Public methods */
|
||||
void
|
||||
mdvi_cairo_device_init (DviDevice *device)
|
||||
{
|
||||
device->device_data = g_new0 (DviCairoDevice, 1);
|
||||
|
||||
device->draw_glyph = dvi_cairo_draw_glyph;
|
||||
device->draw_rule = dvi_cairo_draw_rule;
|
||||
device->alloc_colors = dvi_cairo_alloc_colors;
|
||||
device->create_image = dvi_cairo_create_image;
|
||||
device->free_image = dvi_cairo_free_image;
|
||||
device->put_pixel = dvi_cairo_put_pixel;
|
||||
device->image_done = dvi_cairo_image_done;
|
||||
device->set_color = dvi_cairo_set_color;
|
||||
#ifdef HAVE_SPECTRE
|
||||
device->draw_ps = dvi_cairo_draw_ps;
|
||||
#else
|
||||
device->draw_ps = NULL;
|
||||
#endif
|
||||
device->refresh = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mdvi_cairo_device_free (DviDevice *device)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
|
||||
cairo_device = (DviCairoDevice *) device->device_data;
|
||||
|
||||
if (cairo_device->cr)
|
||||
cairo_destroy (cairo_device->cr);
|
||||
|
||||
g_free (cairo_device);
|
||||
}
|
||||
|
||||
cairo_surface_t *
|
||||
mdvi_cairo_device_get_surface (DviDevice *device)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
|
||||
cairo_device = (DviCairoDevice *) device->device_data;
|
||||
|
||||
return cairo_surface_reference (cairo_get_target (cairo_device->cr));
|
||||
}
|
||||
|
||||
void
|
||||
mdvi_cairo_device_render (DviContext* dvi)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
gint page_width;
|
||||
gint page_height;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
cairo_device = (DviCairoDevice *) dvi->device.device_data;
|
||||
|
||||
if (cairo_device->cr)
|
||||
cairo_destroy (cairo_device->cr);
|
||||
|
||||
page_width = dvi->dvi_page_w * dvi->params.conv + 2 * cairo_device->xmargin;
|
||||
page_height = dvi->dvi_page_h * dvi->params.vconv + 2 * cairo_device->ymargin;
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
|
||||
page_width, page_height);
|
||||
|
||||
cairo_device->cr = cairo_create (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
cairo_set_source_rgb (cairo_device->cr, 1., 1., 1.);
|
||||
cairo_paint (cairo_device->cr);
|
||||
|
||||
mdvi_dopage (dvi, dvi->currpage);
|
||||
}
|
||||
|
||||
void
|
||||
mdvi_cairo_device_set_margins (DviDevice *device,
|
||||
gint xmargin,
|
||||
gint ymargin)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
|
||||
cairo_device = (DviCairoDevice *) device->device_data;
|
||||
|
||||
cairo_device->xmargin = xmargin;
|
||||
cairo_device->ymargin = ymargin;
|
||||
}
|
||||
|
||||
void
|
||||
mdvi_cairo_device_set_scale (DviDevice *device,
|
||||
gdouble scale)
|
||||
{
|
||||
DviCairoDevice *cairo_device;
|
||||
|
||||
cairo_device = (DviCairoDevice *) device->device_data;
|
||||
|
||||
cairo_device->scale = scale;
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef MDVI_CAIRO_DEVICE
|
||||
#define MDVI_CAIRO_DEVICE
|
||||
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void mdvi_cairo_device_init (DviDevice *device);
|
||||
void mdvi_cairo_device_free (DviDevice *device);
|
||||
cairo_surface_t *mdvi_cairo_device_get_surface (DviDevice *device);
|
||||
void mdvi_cairo_device_render (DviContext* dvi);
|
||||
void mdvi_cairo_device_set_margins (DviDevice *device,
|
||||
gint xmargin,
|
||||
gint ymargin);
|
||||
void mdvi_cairo_device_set_scale (DviDevice *device,
|
||||
gdouble scale);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* MDVI_CAIRO_DEVICE */
|
|
@ -0,0 +1,601 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
|
||||
/*
|
||||
* Copyright (C) 2005, Nickolay V. Shmyrev <nshmyrev@yandex.ru>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "dvi-document.h"
|
||||
#include "ev-document-thumbnails.h"
|
||||
#include "ev-document-misc.h"
|
||||
#include "ev-file-exporter.h"
|
||||
#include "ev-file-helpers.h"
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "fonts.h"
|
||||
#include "color.h"
|
||||
#include "cairo-device.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
GMutex dvi_context_mutex;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TITLE
|
||||
};
|
||||
|
||||
struct _DviDocumentClass
|
||||
{
|
||||
EvDocumentClass parent_class;
|
||||
};
|
||||
|
||||
struct _DviDocument
|
||||
{
|
||||
EvDocument parent_instance;
|
||||
|
||||
DviContext *context;
|
||||
DviPageSpec *spec;
|
||||
DviParams *params;
|
||||
|
||||
/* To let document scale we should remember width and height */
|
||||
double base_width;
|
||||
double base_height;
|
||||
|
||||
gchar *uri;
|
||||
|
||||
/* PDF exporter */
|
||||
gchar *exporter_filename;
|
||||
GString *exporter_opts;
|
||||
};
|
||||
|
||||
typedef struct _DviDocumentClass DviDocumentClass;
|
||||
|
||||
static void dvi_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
|
||||
static void dvi_document_file_exporter_iface_init (EvFileExporterInterface *iface);
|
||||
static void dvi_document_do_color_special (DviContext *dvi,
|
||||
const char *prefix,
|
||||
const char *arg);
|
||||
|
||||
EV_BACKEND_REGISTER_WITH_CODE (DviDocument, dvi_document,
|
||||
{
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, dvi_document_document_thumbnails_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER, dvi_document_file_exporter_iface_init);
|
||||
});
|
||||
|
||||
static gboolean
|
||||
dvi_document_load (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
gchar *filename;
|
||||
DviDocument *dvi_document = DVI_DOCUMENT(document);
|
||||
|
||||
filename = g_filename_from_uri (uri, NULL, error);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
g_mutex_lock (&dvi_context_mutex);
|
||||
if (dvi_document->context)
|
||||
mdvi_destroy_context (dvi_document->context);
|
||||
|
||||
dvi_document->context = mdvi_init_context(dvi_document->params, dvi_document->spec, filename);
|
||||
g_mutex_unlock (&dvi_context_mutex);
|
||||
g_free (filename);
|
||||
|
||||
if (!dvi_document->context) {
|
||||
g_set_error_literal (error,
|
||||
EV_DOCUMENT_ERROR,
|
||||
EV_DOCUMENT_ERROR_INVALID,
|
||||
_("DVI document has incorrect format"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mdvi_cairo_device_init (&dvi_document->context->device);
|
||||
|
||||
|
||||
dvi_document->base_width = dvi_document->context->dvi_page_w * dvi_document->context->params.conv
|
||||
+ 2 * unit2pix(dvi_document->params->dpi, MDVI_HMARGIN) / dvi_document->params->hshrink;
|
||||
|
||||
dvi_document->base_height = dvi_document->context->dvi_page_h * dvi_document->context->params.vconv
|
||||
+ 2 * unit2pix(dvi_document->params->vdpi, MDVI_VMARGIN) / dvi_document->params->vshrink;
|
||||
|
||||
g_free (dvi_document->uri);
|
||||
dvi_document->uri = g_strdup (uri);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
dvi_document_save (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT (document);
|
||||
|
||||
return ev_xfer_uri_simple (dvi_document->uri, uri, error);
|
||||
}
|
||||
|
||||
static int
|
||||
dvi_document_get_n_pages (EvDocument *document)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT (document);
|
||||
|
||||
return dvi_document->context->npages;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_get_page_size (EvDocument *document,
|
||||
EvPage *page,
|
||||
double *width,
|
||||
double *height)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT (document);
|
||||
|
||||
*width = dvi_document->base_width;
|
||||
*height = dvi_document->base_height;;
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
dvi_document_render (EvDocument *document,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_surface_t *rotated_surface;
|
||||
DviDocument *dvi_document = DVI_DOCUMENT(document);
|
||||
gint required_width, required_height;
|
||||
gint proposed_width, proposed_height;
|
||||
gint xmargin = 0, ymargin = 0;
|
||||
|
||||
/* We should protect our context since it's not
|
||||
* thread safe. The work to the future -
|
||||
* let context render page independently
|
||||
*/
|
||||
g_mutex_lock (&dvi_context_mutex);
|
||||
|
||||
mdvi_setpage (dvi_document->context, rc->page->index);
|
||||
|
||||
mdvi_set_shrink (dvi_document->context,
|
||||
(int)((dvi_document->params->hshrink - 1) / rc->scale) + 1,
|
||||
(int)((dvi_document->params->vshrink - 1) / rc->scale) + 1);
|
||||
|
||||
required_width = dvi_document->base_width * rc->scale + 0.5;
|
||||
required_height = dvi_document->base_height * rc->scale + 0.5;
|
||||
proposed_width = dvi_document->context->dvi_page_w * dvi_document->context->params.conv;
|
||||
proposed_height = dvi_document->context->dvi_page_h * dvi_document->context->params.vconv;
|
||||
|
||||
if (required_width >= proposed_width)
|
||||
xmargin = (required_width - proposed_width) / 2;
|
||||
if (required_height >= proposed_height)
|
||||
ymargin = (required_height - proposed_height) / 2;
|
||||
|
||||
mdvi_cairo_device_set_margins (&dvi_document->context->device, xmargin, ymargin);
|
||||
mdvi_cairo_device_set_scale (&dvi_document->context->device, rc->scale);
|
||||
mdvi_cairo_device_render (dvi_document->context);
|
||||
surface = mdvi_cairo_device_get_surface (&dvi_document->context->device);
|
||||
|
||||
g_mutex_unlock (&dvi_context_mutex);
|
||||
|
||||
rotated_surface = ev_document_misc_surface_rotate_and_scale (surface,
|
||||
required_width,
|
||||
required_height,
|
||||
rc->rotation);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return rotated_surface;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_finalize (GObject *object)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT(object);
|
||||
|
||||
g_mutex_lock (&dvi_context_mutex);
|
||||
if (dvi_document->context) {
|
||||
mdvi_cairo_device_free (&dvi_document->context->device);
|
||||
mdvi_destroy_context (dvi_document->context);
|
||||
}
|
||||
g_mutex_unlock (&dvi_context_mutex);
|
||||
|
||||
if (dvi_document->params)
|
||||
g_free (dvi_document->params);
|
||||
|
||||
if (dvi_document->exporter_filename)
|
||||
g_free (dvi_document->exporter_filename);
|
||||
|
||||
if (dvi_document->exporter_opts)
|
||||
g_string_free (dvi_document->exporter_opts, TRUE);
|
||||
|
||||
g_free (dvi_document->uri);
|
||||
|
||||
G_OBJECT_CLASS (dvi_document_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dvi_document_support_synctex (EvDocument *document)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_class_init (DviDocumentClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = dvi_document_finalize;
|
||||
|
||||
mdvi_init_kpathsea ("atril", MDVI_MFMODE, MDVI_FALLBACK_FONT, MDVI_DPI, getenv("TEXMFCNF"));
|
||||
|
||||
mdvi_register_special ("Color", "color", NULL, dvi_document_do_color_special, 1);
|
||||
mdvi_register_fonts ();
|
||||
|
||||
ev_document_class->load = dvi_document_load;
|
||||
ev_document_class->save = dvi_document_save;
|
||||
ev_document_class->get_n_pages = dvi_document_get_n_pages;
|
||||
ev_document_class->get_page_size = dvi_document_get_page_size;
|
||||
ev_document_class->render = dvi_document_render;
|
||||
ev_document_class->support_synctex = dvi_document_support_synctex;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT (document);
|
||||
gdouble page_width = dvi_document->base_width;
|
||||
gdouble page_height = dvi_document->base_height;
|
||||
|
||||
if (rc->rotation == 90 || rc->rotation == 270) {
|
||||
*width = (gint) (page_height * rc->scale);
|
||||
*height = (gint) (page_width * rc->scale);
|
||||
} else {
|
||||
*width = (gint) (page_width * rc->scale);
|
||||
*height = (gint) (page_height * rc->scale);
|
||||
}
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
dvi_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gboolean border)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT (document);
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbuf *rotated_pixbuf;
|
||||
cairo_surface_t *surface;
|
||||
gint thumb_width, thumb_height;
|
||||
gint proposed_width, proposed_height;
|
||||
|
||||
thumb_width = (gint) (dvi_document->base_width * rc->scale);
|
||||
thumb_height = (gint) (dvi_document->base_height * rc->scale);
|
||||
|
||||
g_mutex_lock (&dvi_context_mutex);
|
||||
|
||||
mdvi_setpage (dvi_document->context, rc->page->index);
|
||||
|
||||
mdvi_set_shrink (dvi_document->context,
|
||||
(int)dvi_document->base_width * dvi_document->params->hshrink / thumb_width,
|
||||
(int)dvi_document->base_height * dvi_document->params->vshrink / thumb_height);
|
||||
|
||||
proposed_width = dvi_document->context->dvi_page_w * dvi_document->context->params.conv;
|
||||
proposed_height = dvi_document->context->dvi_page_h * dvi_document->context->params.vconv;
|
||||
|
||||
if (border) {
|
||||
mdvi_cairo_device_set_margins (&dvi_document->context->device,
|
||||
MAX (thumb_width - proposed_width, 0) / 2,
|
||||
MAX (thumb_height - proposed_height, 0) / 2);
|
||||
} else {
|
||||
mdvi_cairo_device_set_margins (&dvi_document->context->device,
|
||||
MAX (thumb_width - proposed_width - 2, 0) / 2,
|
||||
MAX (thumb_height - proposed_height - 2, 0) / 2);
|
||||
}
|
||||
|
||||
mdvi_cairo_device_set_scale (&dvi_document->context->device, rc->scale);
|
||||
mdvi_cairo_device_render (dvi_document->context);
|
||||
surface = mdvi_cairo_device_get_surface (&dvi_document->context->device);
|
||||
g_mutex_unlock (&dvi_context_mutex);
|
||||
|
||||
pixbuf = ev_document_misc_pixbuf_from_surface (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
if (border) {
|
||||
GdkPixbuf *tmp_pixbuf = rotated_pixbuf;
|
||||
|
||||
rotated_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
|
||||
g_object_unref (tmp_pixbuf);
|
||||
}
|
||||
|
||||
return rotated_pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
|
||||
{
|
||||
iface->get_thumbnail = dvi_document_thumbnails_get_thumbnail;
|
||||
iface->get_dimensions = dvi_document_thumbnails_get_dimensions;
|
||||
}
|
||||
|
||||
/* EvFileExporterIface */
|
||||
static void
|
||||
dvi_document_file_exporter_begin (EvFileExporter *exporter,
|
||||
EvFileExporterContext *fc)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT(exporter);
|
||||
|
||||
if (dvi_document->exporter_filename)
|
||||
g_free (dvi_document->exporter_filename);
|
||||
dvi_document->exporter_filename = g_strdup (fc->filename);
|
||||
|
||||
if (dvi_document->exporter_opts) {
|
||||
g_string_free (dvi_document->exporter_opts, TRUE);
|
||||
}
|
||||
dvi_document->exporter_opts = g_string_new ("-s ");
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_file_exporter_do_page (EvFileExporter *exporter,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
DviDocument *dvi_document = DVI_DOCUMENT(exporter);
|
||||
|
||||
g_string_append_printf (dvi_document->exporter_opts, "%d,", (rc->page->index) + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_file_exporter_end (EvFileExporter *exporter)
|
||||
{
|
||||
gchar *command_line;
|
||||
gint exit_stat;
|
||||
GError *err = NULL;
|
||||
gboolean success;
|
||||
|
||||
DviDocument *dvi_document = DVI_DOCUMENT(exporter);
|
||||
gchar* quoted_filename = g_shell_quote (dvi_document->context->filename);
|
||||
|
||||
command_line = g_strdup_printf ("dvipdfm %s -o %s %s", /* dvipdfm -s 1,2,.., -o exporter_filename dvi_filename */
|
||||
dvi_document->exporter_opts->str,
|
||||
dvi_document->exporter_filename,
|
||||
quoted_filename);
|
||||
g_free (quoted_filename);
|
||||
|
||||
success = g_spawn_command_line_sync (command_line,
|
||||
NULL,
|
||||
NULL,
|
||||
&exit_stat,
|
||||
&err);
|
||||
|
||||
g_free (command_line);
|
||||
|
||||
if (success == FALSE) {
|
||||
g_warning ("Error: %s", err->message);
|
||||
} else if (!WIFEXITED(exit_stat) || WEXITSTATUS(exit_stat) != EXIT_SUCCESS){
|
||||
g_warning ("Error: dvipdfm does not end normally or exit with a failure status.");
|
||||
}
|
||||
|
||||
if (err)
|
||||
g_error_free (err);
|
||||
}
|
||||
|
||||
static EvFileExporterCapabilities
|
||||
dvi_document_file_exporter_get_capabilities (EvFileExporter *exporter)
|
||||
{
|
||||
return EV_FILE_EXPORTER_CAN_PAGE_SET |
|
||||
EV_FILE_EXPORTER_CAN_COPIES |
|
||||
EV_FILE_EXPORTER_CAN_COLLATE |
|
||||
EV_FILE_EXPORTER_CAN_REVERSE |
|
||||
EV_FILE_EXPORTER_CAN_GENERATE_PDF;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_file_exporter_iface_init (EvFileExporterInterface *iface)
|
||||
{
|
||||
iface->begin = dvi_document_file_exporter_begin;
|
||||
iface->do_page = dvi_document_file_exporter_do_page;
|
||||
iface->end = dvi_document_file_exporter_end;
|
||||
iface->get_capabilities = dvi_document_file_exporter_get_capabilities;
|
||||
}
|
||||
|
||||
#define RGB2ULONG(r,g,b) ((0xFF<<24)|(r<<16)|(g<<8)|(b))
|
||||
|
||||
static gboolean
|
||||
hsb2rgb (float h, float s, float v, guchar *red, guchar *green, guchar *blue)
|
||||
{
|
||||
float f, p, q, t, r, g, b;
|
||||
int i;
|
||||
|
||||
s /= 100;
|
||||
v /= 100;
|
||||
h /= 60;
|
||||
i = floor (h);
|
||||
if (i == 6)
|
||||
i = 0;
|
||||
else if ((i > 6) || (i < 0))
|
||||
return FALSE;
|
||||
f = h - i;
|
||||
p = v * (1 - s);
|
||||
q = v * (1 - (s * f));
|
||||
t = v * (1 - (s * (1 - f)));
|
||||
|
||||
if (i == 0) {
|
||||
r = v;
|
||||
g = t;
|
||||
b = p;
|
||||
} else if (i == 1) {
|
||||
r = q;
|
||||
g = v;
|
||||
b = p;
|
||||
} else if (i == 2) {
|
||||
r = p;
|
||||
g = v;
|
||||
b = t;
|
||||
} else if (i == 3) {
|
||||
r = p;
|
||||
g = q;
|
||||
b = v;
|
||||
} else if (i == 4) {
|
||||
r = t;
|
||||
g = p;
|
||||
b = v;
|
||||
} else if (i == 5) {
|
||||
r = v;
|
||||
g = p;
|
||||
b = q;
|
||||
}
|
||||
|
||||
*red = (guchar)floor(r * 255.0);
|
||||
*green = (guchar)floor(g * 255.0);
|
||||
*blue = (guchar)floor(b * 255.0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_color (const gchar *ptr,
|
||||
gdouble *color,
|
||||
gint n_color)
|
||||
{
|
||||
gchar *p = (gchar *)ptr;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_color; i++) {
|
||||
while (isspace (*p)) p++;
|
||||
color[i] = g_ascii_strtod (p, NULL);
|
||||
while (!isspace (*p) && *p != '\0') p++;
|
||||
if (*p == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_do_color_special (DviContext *dvi, const char *prefix, const char *arg)
|
||||
{
|
||||
if (strncmp (arg, "pop", 3) == 0) {
|
||||
mdvi_pop_color (dvi);
|
||||
} else if (strncmp (arg, "push", 4) == 0) {
|
||||
/* Find color source: Named, CMYK or RGB */
|
||||
const char *tmp = arg + 4;
|
||||
|
||||
while (isspace (*tmp)) tmp++;
|
||||
|
||||
if (!strncmp ("rgb", tmp, 3)) {
|
||||
gdouble rgb[3];
|
||||
guchar red, green, blue;
|
||||
|
||||
parse_color (tmp + 4, rgb, 3);
|
||||
|
||||
red = 255 * rgb[0];
|
||||
green = 255 * rgb[1];
|
||||
blue = 255 * rgb[2];
|
||||
|
||||
mdvi_push_color (dvi, RGB2ULONG (red, green, blue), 0xFFFFFFFF);
|
||||
} else if (!strncmp ("hsb", tmp, 4)) {
|
||||
gdouble hsb[3];
|
||||
guchar red, green, blue;
|
||||
|
||||
parse_color (tmp + 4, hsb, 3);
|
||||
|
||||
if (hsb2rgb (hsb[0], hsb[1], hsb[2], &red, &green, &blue))
|
||||
mdvi_push_color (dvi, RGB2ULONG (red, green, blue), 0xFFFFFFFF);
|
||||
} else if (!strncmp ("cmyk", tmp, 4)) {
|
||||
gdouble cmyk[4];
|
||||
double r, g, b;
|
||||
guchar red, green, blue;
|
||||
|
||||
parse_color (tmp + 5, cmyk, 4);
|
||||
|
||||
r = 1.0 - cmyk[0] - cmyk[3];
|
||||
if (r < 0.0)
|
||||
r = 0.0;
|
||||
g = 1.0 - cmyk[1] - cmyk[3];
|
||||
if (g < 0.0)
|
||||
g = 0.0;
|
||||
b = 1.0 - cmyk[2] - cmyk[3];
|
||||
if (b < 0.0)
|
||||
b = 0.0;
|
||||
|
||||
red = r * 255 + 0.5;
|
||||
green = g * 255 + 0.5;
|
||||
blue = b * 255 + 0.5;
|
||||
|
||||
mdvi_push_color (dvi, RGB2ULONG (red, green, blue), 0xFFFFFFFF);
|
||||
} else if (!strncmp ("gray ", tmp, 5)) {
|
||||
gdouble gray;
|
||||
guchar rgb;
|
||||
|
||||
parse_color (tmp + 5, &gray, 1);
|
||||
|
||||
rgb = gray * 255 + 0.5;
|
||||
|
||||
mdvi_push_color (dvi, RGB2ULONG (rgb, rgb, rgb), 0xFFFFFFFF);
|
||||
} else {
|
||||
GdkColor color;
|
||||
|
||||
if (gdk_color_parse (tmp, &color)) {
|
||||
guchar red, green, blue;
|
||||
|
||||
red = color.red * 255 / 65535.;
|
||||
green = color.green * 255 / 65535.;
|
||||
blue = color.blue * 255 / 65535.;
|
||||
|
||||
mdvi_push_color (dvi, RGB2ULONG (red, green, blue), 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_init_params (DviDocument *dvi_document)
|
||||
{
|
||||
dvi_document->params = g_new0 (DviParams, 1);
|
||||
|
||||
dvi_document->params->dpi = MDVI_DPI;
|
||||
dvi_document->params->vdpi = MDVI_VDPI;
|
||||
dvi_document->params->mag = MDVI_MAGNIFICATION;
|
||||
dvi_document->params->density = MDVI_DEFAULT_DENSITY;
|
||||
dvi_document->params->gamma = MDVI_DEFAULT_GAMMA;
|
||||
dvi_document->params->flags = MDVI_PARAM_ANTIALIASED;
|
||||
dvi_document->params->hdrift = 0;
|
||||
dvi_document->params->vdrift = 0;
|
||||
dvi_document->params->hshrink = MDVI_SHRINK_FROM_DPI(dvi_document->params->dpi);
|
||||
dvi_document->params->vshrink = MDVI_SHRINK_FROM_DPI(dvi_document->params->vdpi);
|
||||
dvi_document->params->orientation = MDVI_ORIENT_TBLR;
|
||||
|
||||
dvi_document->spec = NULL;
|
||||
|
||||
dvi_document->params->bg = 0xffffffff;
|
||||
dvi_document->params->fg = 0xff000000;
|
||||
}
|
||||
|
||||
static void
|
||||
dvi_document_init (DviDocument *dvi_document)
|
||||
{
|
||||
dvi_document->context = NULL;
|
||||
dvi_document_init_params (dvi_document);
|
||||
|
||||
dvi_document->exporter_filename = NULL;
|
||||
dvi_document->exporter_opts = NULL;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* dvi-document.h: Implementation of EvDocument for dvi documents
|
||||
* Copyright (C) 2005, Nickolay V. Shmyrev <nshmyrev@yandex.ru>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __DVI_DOCUMENT_H__
|
||||
#define __DVI_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define DVI_TYPE_DOCUMENT (dvi_document_get_type ())
|
||||
#define DVI_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DVI_TYPE_DOCUMENT, DviDocument))
|
||||
#define DVI_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DVI_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _DviDocument DviDocument;
|
||||
|
||||
GType dvi_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __DVI_DOCUMENT_H__ */
|
|
@ -0,0 +1,4 @@
|
|||
[Atril Backend]
|
||||
Module=dvidocument
|
||||
TypeDescription=DVI Documents
|
||||
MimeType=application/x-dvi;application/x-bzdvi;application/x-gzdvi
|
|
@ -0,0 +1,57 @@
|
|||
#include "config.h"
|
||||
#include "fonts.h"
|
||||
#include "mdvi.h"
|
||||
|
||||
static int registered = 0;
|
||||
|
||||
extern DviFontInfo pk_font_info;
|
||||
extern DviFontInfo pkn_font_info;
|
||||
extern DviFontInfo gf_font_info;
|
||||
extern DviFontInfo vf_font_info;
|
||||
extern DviFontInfo ovf_font_info;
|
||||
#if 0
|
||||
extern DviFontInfo tt_font_info;
|
||||
#endif
|
||||
#ifdef WITH_TYPE1_FONTS
|
||||
extern DviFontInfo t1_font_info;
|
||||
#endif
|
||||
extern DviFontInfo afm_font_info;
|
||||
extern DviFontInfo tfm_font_info;
|
||||
extern DviFontInfo ofm_font_info;
|
||||
|
||||
static struct fontinfo {
|
||||
DviFontInfo *info;
|
||||
char *desc;
|
||||
int klass;
|
||||
} known_fonts[] = {
|
||||
{&vf_font_info, "Virtual fonts", 0},
|
||||
{&ovf_font_info, "Omega's virtual fonts", 0},
|
||||
#if 0
|
||||
{&tt_font_info, "TrueType fonts", 0},
|
||||
#endif
|
||||
#ifdef WITH_TYPE1_FONTS
|
||||
{&t1_font_info, "Type1 PostScript fonts", 0},
|
||||
#endif
|
||||
{&pk_font_info, "Packed bitmap (auto-generated)", 1},
|
||||
{&pkn_font_info, "Packed bitmap", -2},
|
||||
{&gf_font_info, "Metafont's generic font format", 1},
|
||||
{&ofm_font_info, "Omega font metrics", -1},
|
||||
{&tfm_font_info, "TeX font metrics", -1},
|
||||
{&afm_font_info, "Adobe font metrics", -1},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
void mdvi_register_fonts (void)
|
||||
{
|
||||
struct fontinfo *type;
|
||||
|
||||
if (!registered) {
|
||||
for(type = known_fonts; type->info; type++) {
|
||||
mdvi_register_font_type(type->info, type->klass);
|
||||
}
|
||||
registered = 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef MDVI_FONTS_REGISTRATION_H
|
||||
#define MDVI_FONTS_REGISTRATION_H
|
||||
|
||||
void mdvi_register_fonts (void);
|
||||
|
||||
#endif /* MDVI_FONTS_REGISTRATION_H */
|
|
@ -0,0 +1,43 @@
|
|||
AM_CPPFLAGS = $(WARN_CFLAGS)
|
||||
noinst_LTLIBRARIES = libmdvi.la
|
||||
|
||||
libmdvi_la_SOURCES = \
|
||||
afmparse.c \
|
||||
afmparse.h \
|
||||
bitmap.c \
|
||||
bitmap.h \
|
||||
color.c \
|
||||
color.h \
|
||||
common.c \
|
||||
common.h \
|
||||
defaults.h \
|
||||
dviopcodes.h \
|
||||
dviread.c \
|
||||
files.c \
|
||||
font.c \
|
||||
fontmap.c \
|
||||
fontmap.h \
|
||||
fontsrch.c \
|
||||
gf.c \
|
||||
hash.c \
|
||||
hash.h \
|
||||
list.c \
|
||||
mdvi.h \
|
||||
pagesel.c \
|
||||
paper.c \
|
||||
paper.h \
|
||||
pk.c \
|
||||
private.h \
|
||||
setup.c \
|
||||
special.c \
|
||||
sp-epsf.c \
|
||||
sysdeps.h \
|
||||
t1.c \
|
||||
tfm.c \
|
||||
tfmfile.c \
|
||||
tt.c \
|
||||
util.c \
|
||||
vf.c
|
||||
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,307 @@
|
|||
/* modified for MDVI -- some names changed to avoid conflicts with T1lib */
|
||||
/*
|
||||
* (C) 1988, 1989 by Adobe Systems Incorporated. All rights reserved.
|
||||
*
|
||||
* This file may be freely copied and redistributed as long as:
|
||||
* 1) This entire notice continues to be included in the file,
|
||||
* 2) If the file has been modified in any way, a notice of such
|
||||
* modification is conspicuously indicated.
|
||||
*
|
||||
* PostScript, Display PostScript, and Adobe are registered trademarks of
|
||||
* Adobe Systems Incorporated.
|
||||
*
|
||||
* ************************************************************************
|
||||
* THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO CHANGE WITHOUT
|
||||
* NOTICE, AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY ADOBE SYSTEMS
|
||||
* INCORPORATED. ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY OR
|
||||
* LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO WARRANTY OF ANY
|
||||
* KIND (EXPRESS, IMPLIED OR STATUTORY) WITH RESPECT TO THIS INFORMATION,
|
||||
* AND EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* ************************************************************************
|
||||
*/
|
||||
|
||||
/* ParseAFM.h
|
||||
*
|
||||
* This header file is used in conjuction with the parseAFM.c file.
|
||||
* Together these files provide the functionality to parse Adobe Font
|
||||
* Metrics files and store the information in predefined data structures.
|
||||
* It is intended to work with an application program that needs font metric
|
||||
* information. The program can be used as is by making a procedure call to
|
||||
* parse an AFM file and have the data stored, or an application developer
|
||||
* may wish to customize the code.
|
||||
*
|
||||
* This header file defines the data structures used as well as the key
|
||||
* strings that are currently recognized by this version of the AFM parser.
|
||||
* This program is based on the document "Adobe Font Metrics Files,
|
||||
* Specification Version 2.0".
|
||||
*
|
||||
* AFM files are separated into distinct sections of different data. Because
|
||||
* of this, the parseAFM program can parse a specified file to only save
|
||||
* certain sections of information based on the application's needs. A record
|
||||
* containing the requested information will be returned to the application.
|
||||
*
|
||||
* AFM files are divided into five sections of data:
|
||||
* 1) The Global Font Information
|
||||
* 2) The Character Metrics Information
|
||||
* 3) The Track Kerning Data
|
||||
* 4) The Pair-Wise Kerning Data
|
||||
* 5) The Composite Character Data
|
||||
*
|
||||
* Basically, the application can request any of these sections independent
|
||||
* of what other sections are requested. In addition, in recognizing that
|
||||
* many applications will want ONLY the x-width of characters and not all
|
||||
* of the other character metrics information, there is a way to receive
|
||||
* only the width information so as not to pay the storage cost for the
|
||||
* unwanted data. An application should never request both the
|
||||
* "quick and dirty" char metrics (widths only) and the Character Metrics
|
||||
* Information since the Character Metrics Information will contain all
|
||||
* of the character widths as well.
|
||||
*
|
||||
* There is a procedure in parseAFM.c, called parseFile, that can be
|
||||
* called from any application wishing to get information from the AFM File.
|
||||
* This procedure expects 3 parameters: a vaild file descriptor, a pointer
|
||||
* to a (FontInfo *) variable (for which space will be allocated and then
|
||||
* will be filled in with the data requested), and a mask specifying
|
||||
* which data from the AFM File should be saved in the FontInfo structure.
|
||||
*
|
||||
* The flags that can be used to set the appropriate mask are defined below.
|
||||
* In addition, several commonly used masks have already been defined.
|
||||
*
|
||||
* History:
|
||||
* original: DSM Thu Oct 20 17:39:59 PDT 1988
|
||||
* modified: DSM Mon Jul 3 14:17:50 PDT 1989
|
||||
* - added 'storageProblem' return code
|
||||
* - fixed typos
|
||||
*/
|
||||
#ifndef _MDVI_PARSEAFM_H
|
||||
#define _MDVI_PARSEAFM_H 1
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* your basic constants */
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#define EOL '\n' /* end-of-line indicator */
|
||||
#define MAX_NAME 4096 /* max length for identifiers */
|
||||
#define BOOL int
|
||||
#define FLAGS int
|
||||
|
||||
/* Flags that can be AND'ed together to specify exactly what
|
||||
* information from the AFM file should be saved. */
|
||||
#define P_G 0x01 /* 0000 0001 */ /* Global Font Info */
|
||||
#define P_W 0x02 /* 0000 0010 */ /* Character Widths ONLY */
|
||||
#define P_M 0x06 /* 0000 0110 */ /* All Char Metric Info */
|
||||
#define P_P 0x08 /* 0000 1000 */ /* Pair Kerning Info */
|
||||
#define P_T 0x10 /* 0001 0000 */ /* Track Kerning Info */
|
||||
#define P_C 0x20 /* 0010 0000 */ /* Composite Char Info */
|
||||
|
||||
/* Commonly used flags */
|
||||
#define P_GW (P_G | P_W)
|
||||
#define P_GM (P_G | P_M)
|
||||
#define P_GMP (P_G | P_M | P_P)
|
||||
#define P_GMK (P_G | P_M | P_P | P_T)
|
||||
#define P_ALL (P_G | P_M | P_P | P_T | P_C)
|
||||
|
||||
/* Possible return codes from the parseFile procedure.
|
||||
*
|
||||
* ok means there were no problems parsing the file.
|
||||
*
|
||||
* parseError means that there was some kind of parsing error, but the
|
||||
* parser went on. This could include problems like the count for any given
|
||||
* section does not add up to how many entries there actually were, or
|
||||
* there was a key that was not recognized. The return record may contain
|
||||
* vaild data or it may not.
|
||||
*
|
||||
* earlyEOF means that an End of File was encountered before expected. This
|
||||
* may mean that the AFM file had been truncated, or improperly formed.
|
||||
*
|
||||
* storageProblem means that there were problems allocating storage for
|
||||
* the data structures that would have contained the AFM data.
|
||||
*/
|
||||
#define ok 0
|
||||
#define parseError -1
|
||||
#define earlyEOF -2
|
||||
#define storageProblem -3
|
||||
|
||||
/************************* TYPES *********************************/
|
||||
/* Below are all of the data structure definitions. These structures
|
||||
* try to map as closely as possible to grouping and naming of data
|
||||
* in the AFM Files.
|
||||
*/
|
||||
|
||||
/* Bounding box definition. Used for the Font BBox as well as the
|
||||
* Character BBox.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int llx; /* lower left x-position */
|
||||
int lly; /* lower left y-position */
|
||||
int urx; /* upper right x-position */
|
||||
int ury; /* upper right y-position */
|
||||
} BBox;
|
||||
|
||||
/* Global Font information.
|
||||
* The key that each field is associated with is in comments. For an
|
||||
* explanation about each key and its value please refer to the AFM
|
||||
* documentation (full title & version given above).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *afmVersion; /* key: StartFontMetrics */
|
||||
char *fontName; /* key: FontName */
|
||||
char *fullName; /* key: FullName */
|
||||
char *familyName; /* key: FamilyName */
|
||||
char *weight; /* key: Weight */
|
||||
float italicAngle; /* key: ItalicAngle */
|
||||
BOOL isFixedPitch; /* key: IsFixedPitch */
|
||||
BBox fontBBox; /* key: FontBBox */
|
||||
int underlinePosition; /* key: UnderlinePosition */
|
||||
int underlineThickness; /* key: UnderlineThickness */
|
||||
char *version; /* key: Version */
|
||||
char *notice; /* key: Notice */
|
||||
char *encodingScheme; /* key: EncodingScheme */
|
||||
int capHeight; /* key: CapHeight */
|
||||
int xHeight; /* key: XHeight */
|
||||
int ascender; /* key: Ascender */
|
||||
int descender; /* key: Descender */
|
||||
} GlobalFontInfo;
|
||||
|
||||
/* Ligature definition is a linked list since any character can have
|
||||
* any number of ligatures.
|
||||
*/
|
||||
typedef struct _t_ligature
|
||||
{
|
||||
char *succ, *lig;
|
||||
struct _t_ligature *next;
|
||||
} Ligature;
|
||||
|
||||
/* Character Metric Information. This structure is used only if ALL
|
||||
* character metric information is requested. If only the character
|
||||
* widths is requested, then only an array of the character x-widths
|
||||
* is returned.
|
||||
*
|
||||
* The key that each field is associated with is in comments. For an
|
||||
* explanation about each key and its value please refer to the
|
||||
* Character Metrics section of the AFM documentation (full title
|
||||
* & version given above).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int code, /* key: C */
|
||||
wx, /* key: WX */
|
||||
wy; /* together wx and wy are associated with key: W */
|
||||
char *name; /* key: N */
|
||||
BBox charBBox; /* key: B */
|
||||
Ligature *ligs; /* key: L (linked list; not a fixed number of Ls */
|
||||
} CharMetricInfo;
|
||||
|
||||
/* Track kerning data structure.
|
||||
* The fields of this record are the five values associated with every
|
||||
* TrackKern entry.
|
||||
*
|
||||
* For an explanation about each value please refer to the
|
||||
* Track Kerning section of the AFM documentation (full title
|
||||
* & version given above).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int degree;
|
||||
float minPtSize,
|
||||
minKernAmt,
|
||||
maxPtSize,
|
||||
maxKernAmt;
|
||||
} TrackKernData;
|
||||
|
||||
/* Pair Kerning data structure.
|
||||
* The fields of this record are the four values associated with every
|
||||
* KP entry. For KPX entries, the yamt will be zero.
|
||||
*
|
||||
* For an explanation about each value please refer to the
|
||||
* Pair Kerning section of the AFM documentation (full title
|
||||
* & version given above).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *name1;
|
||||
char *name2;
|
||||
int xamt,
|
||||
yamt;
|
||||
} PairKernData;
|
||||
|
||||
/* PCC is a piece of a composite character. This is a sub structure of a
|
||||
* compCharData described below.
|
||||
* These fields will be filled in with the values from the key PCC.
|
||||
*
|
||||
* For an explanation about each key and its value please refer to the
|
||||
* Composite Character section of the AFM documentation (full title
|
||||
* & version given above).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *pccName;
|
||||
int deltax,
|
||||
deltay;
|
||||
} Pcc;
|
||||
|
||||
/* Composite Character Information data structure.
|
||||
* The fields ccName and numOfPieces are filled with the values associated
|
||||
* with the key CC. The field pieces points to an array (size = numOfPieces)
|
||||
* of information about each of the parts of the composite character. That
|
||||
* array is filled in with the values from the key PCC.
|
||||
*
|
||||
* For an explanation about each key and its value please refer to the
|
||||
* Composite Character section of the AFM documentation (full title
|
||||
* & version given above).
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *ccName;
|
||||
int numOfPieces;
|
||||
Pcc *pieces;
|
||||
} CompCharData;
|
||||
|
||||
/* FontInfo
|
||||
* Record type containing pointers to all of the other data
|
||||
* structures containing information about a font.
|
||||
* A a record of this type is filled with data by the
|
||||
* parseFile function.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GlobalFontInfo *gfi; /* ptr to a GlobalFontInfo record */
|
||||
int *cwi; /* ptr to 256 element array of just char widths */
|
||||
int numOfChars; /* number of entries in char metrics array */
|
||||
CharMetricInfo *cmi; /* ptr to char metrics array */
|
||||
int numOfTracks; /* number to entries in track kerning array */
|
||||
TrackKernData *tkd; /* ptr to track kerning array */
|
||||
int numOfPairs; /* number to entries in pair kerning array */
|
||||
PairKernData *pkd; /* ptr to pair kerning array */
|
||||
int numOfComps; /* number to entries in comp char array */
|
||||
CompCharData *ccd; /* ptr to comp char array */
|
||||
} FontInfo;
|
||||
|
||||
/************************* PROCEDURES ****************************/
|
||||
|
||||
/* Call this procedure to do the grunt work of parsing an AFM file.
|
||||
*
|
||||
* "fp" should be a valid file pointer to an AFM file.
|
||||
*
|
||||
* "fi" is a pointer to a pointer to a FontInfo record sturcture
|
||||
* (defined above). Storage for the FontInfo structure will be
|
||||
* allocated in parseFile and the structure will be filled in
|
||||
* with the requested data from the AFM File.
|
||||
*
|
||||
* "flags" is a mask with bits set representing what data should
|
||||
* be saved. Defined above are valid flags that can be used to set
|
||||
* the mask, as well as a few commonly used masks.
|
||||
*
|
||||
* The possible return codes from parseFile are defined above.
|
||||
*/
|
||||
|
||||
extern int afm_parse_file __PROTO((FILE *, FontInfo **, FLAGS));
|
||||
extern void afm_free_fontinfo __PROTO((FontInfo *));
|
||||
|
||||
#endif /* _MDVI_PARSEAFM_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _BITMAP_H
|
||||
#define _BITMAP_H 1
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
/* Structures and functions to manipulate bitmaps */
|
||||
|
||||
/* bitmap unit (as in X's docs) */
|
||||
typedef Uint32 BmUnit;
|
||||
|
||||
/* size (in bytes) of a bitmap atom */
|
||||
#define BITMAP_BYTES 4
|
||||
|
||||
/* size (in bits) of a bitmap atom */
|
||||
#define BITMAP_BITS (BITMAP_BYTES << 3)
|
||||
|
||||
typedef struct {
|
||||
int width;
|
||||
int height;
|
||||
int stride;
|
||||
BmUnit *data;
|
||||
} BITMAP;
|
||||
|
||||
#define BM_BYTES_PER_LINE(b) \
|
||||
(ROUND((b)->width, BITMAP_BITS) * BITMAP_BYTES)
|
||||
#define BM_WIDTH(b) (((BITMAP *)(b))->width)
|
||||
#define BM_HEIGHT(b) (((BITMAP *)(b))->height)
|
||||
|
||||
#define BMBIT(n) ((BmUnit)1 << (n))
|
||||
|
||||
/* Macros to manipulate individual pixels in a bitmap
|
||||
* (they are slow, don't use them)
|
||||
*/
|
||||
|
||||
#define bm_offset(b,o) (BmUnit *)((Uchar *)(b) + (o))
|
||||
|
||||
#define __bm_unit_ptr(b,x,y) \
|
||||
bm_offset((b)->data, (y) * (b)->stride + \
|
||||
((x) / BITMAP_BITS) * BITMAP_BYTES)
|
||||
|
||||
#define __bm_unit(b,x,y) __bm_unit_ptr((b), (x), (y))[0]
|
||||
|
||||
#define BM_GETPIXEL(b,x,y) __bm_unit((b), (x), (y))
|
||||
#define BM_SETPIXEL(b,x,y) (__bm_unit((b), (x), (y)) |= FIRSTMASKAT(x))
|
||||
#define BM_CLRPIXEL(b,x,y) (__bm_unit((b), (x), (y)) &= ~FIRSTMASKAT(x))
|
||||
|
||||
/*
|
||||
* These macros are used to access pixels in a bitmap. They are supposed
|
||||
* to be used like this:
|
||||
*/
|
||||
#if 0
|
||||
BmUnit *row, mask;
|
||||
|
||||
mask = FIRSTMASK;
|
||||
|
||||
/* position `unit' at coordinates (column_number, row_number) */
|
||||
unit = (BmUnit *)((char *)bitmap->data + row_number * bitmap->stride
|
||||
+ (column_number / BITMAP_BITS);
|
||||
/* loop over all pixels IN THE SAME ROW */
|
||||
for(i = 0; i < number_of_pixels; i++) {
|
||||
/* to test if a pixel is set */
|
||||
if(*unit & mask) {
|
||||
/* yes, it is, do something with it */
|
||||
}
|
||||
/* to set/clear a pixel */
|
||||
if(painting)
|
||||
*unit |= mask; /* now you see it */
|
||||
else
|
||||
*unit &= ~mask; /* now you don't */
|
||||
/* move to next pixel */
|
||||
if(mask == LASTMASK) {
|
||||
unit++;
|
||||
UPDATEMASK(mask);
|
||||
}
|
||||
}
|
||||
/* end of sample code */
|
||||
#endif
|
||||
|
||||
/* bitmaps are stored in native byte order */
|
||||
#ifdef WORD_BIG_ENDIAN
|
||||
#define FIRSTSHIFT (BITMAP_BITS - 1)
|
||||
#define LASTSHIFT 0
|
||||
#define NEXTMASK(m) ((m) >>= 1)
|
||||
#define PREVMASK(m) ((m) <<= 1)
|
||||
#define FIRSTSHIFTAT(c) (BITMAP_BITS - ((c) % BITMAP_BITS) - 1)
|
||||
#else
|
||||
#define FIRSTSHIFT 0
|
||||
#define LASTSHIFT (BITMAP_BITS - 1)
|
||||
#define NEXTMASK(m) ((m) <<= 1)
|
||||
#define PREVMASK(m) ((m) >>= 1)
|
||||
#define FIRSTSHIFTAT(c) ((c) % BITMAP_BITS)
|
||||
#endif
|
||||
|
||||
#define FIRSTMASK BMBIT(FIRSTSHIFT)
|
||||
#define FIRSTMASKAT(c) BMBIT(FIRSTSHIFTAT(c))
|
||||
#define LASTMASK BMBIT(LASTSHIFT)
|
||||
|
||||
extern BITMAP *bitmap_alloc __PROTO((int, int));
|
||||
extern BITMAP *bitmap_alloc_raw __PROTO((int, int));
|
||||
extern void bitmap_destroy __PROTO((BITMAP *));
|
||||
|
||||
/*
|
||||
* set_row(bm, row, col, count, state):
|
||||
* sets `count' pixels to state `onoff', starting from pixel
|
||||
* at position (col, row). All pixels must lie in the same
|
||||
* row.
|
||||
*/
|
||||
extern void bitmap_set_col __PROTO((BITMAP *, int, int, int, int));
|
||||
extern void bitmap_set_row __PROTO((BITMAP *, int, int, int, int));
|
||||
|
||||
extern void bitmap_paint_bits __PROTO((BmUnit *, int, int));
|
||||
extern void bitmap_clear_bits __PROTO((BmUnit *, int, int));
|
||||
|
||||
extern BITMAP *bitmap_copy __PROTO((BITMAP *));
|
||||
extern void bitmap_flip_horizontally __PROTO((BITMAP *));
|
||||
extern void bitmap_flip_vertically __PROTO((BITMAP *));
|
||||
extern void bitmap_flip_diagonally __PROTO((BITMAP *));
|
||||
extern void bitmap_rotate_clockwise __PROTO((BITMAP *));
|
||||
extern void bitmap_rotate_counter_clockwise __PROTO((BITMAP *));
|
||||
extern void bitmap_flip_rotate_clockwise __PROTO((BITMAP *));
|
||||
extern void bitmap_flip_rotate_counter_clockwise __PROTO((BITMAP *));
|
||||
extern BITMAP *bitmap_convert_lsb8 __PROTO((Uchar *, int, int, int));
|
||||
extern BITMAP *bitmap_convert_msb8 __PROTO((Uchar *, int, int, int));
|
||||
|
||||
#include <stdio.h>
|
||||
extern void bitmap_print __PROTO((FILE *, BITMAP *));
|
||||
|
||||
#endif /* _BITMAP_H */
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "mdvi.h"
|
||||
#include "color.h"
|
||||
|
||||
void mdvi_set_color(DviContext *dvi, Ulong fg, Ulong bg)
|
||||
{
|
||||
if(dvi->curr_fg != fg || dvi->curr_bg != bg) {
|
||||
DEBUG((DBG_DEVICE, "setting color to (%lu,%lu)\n", fg, bg));
|
||||
if(dvi->device.set_color)
|
||||
dvi->device.set_color(dvi->device.device_data, fg, bg);
|
||||
dvi->curr_fg = fg;
|
||||
dvi->curr_bg = bg;
|
||||
}
|
||||
}
|
||||
|
||||
void mdvi_push_color(DviContext *dvi, Ulong fg, Ulong bg)
|
||||
{
|
||||
if(dvi->color_top == dvi->color_size) {
|
||||
dvi->color_size += 32;
|
||||
dvi->color_stack = mdvi_realloc(dvi->color_stack,
|
||||
dvi->color_size * sizeof(DviColorPair));
|
||||
}
|
||||
dvi->color_stack[dvi->color_top].fg = dvi->curr_fg;
|
||||
dvi->color_stack[dvi->color_top].bg = dvi->curr_bg;
|
||||
dvi->color_top++;
|
||||
mdvi_set_color(dvi, fg, bg);
|
||||
}
|
||||
|
||||
void mdvi_pop_color(DviContext *dvi)
|
||||
{
|
||||
Ulong fg, bg;
|
||||
|
||||
if(dvi->color_top == 0)
|
||||
return;
|
||||
dvi->color_top--;
|
||||
fg = dvi->color_stack[dvi->color_top].fg;
|
||||
bg = dvi->color_stack[dvi->color_top].bg;
|
||||
mdvi_set_color(dvi, fg, bg);
|
||||
}
|
||||
|
||||
void mdvi_reset_color(DviContext *dvi)
|
||||
{
|
||||
dvi->color_top = 0;
|
||||
mdvi_set_color(dvi, dvi->params.fg, dvi->params.bg);
|
||||
}
|
||||
|
||||
/* cache for color tables, to avoid creating them for every glyph */
|
||||
typedef struct {
|
||||
Ulong fg;
|
||||
Ulong bg;
|
||||
Uint nlevels;
|
||||
Ulong *pixels;
|
||||
int density;
|
||||
double gamma;
|
||||
Uint hits;
|
||||
} ColorCache;
|
||||
|
||||
#define CCSIZE 256
|
||||
static ColorCache color_cache[CCSIZE];
|
||||
static int cc_entries;
|
||||
|
||||
#define GAMMA_DIFF 0.005
|
||||
|
||||
|
||||
/* create a color table */
|
||||
Ulong *get_color_table(DviDevice *dev,
|
||||
int nlevels, Ulong fg, Ulong bg, double gamma, int density)
|
||||
{
|
||||
ColorCache *cc, *tofree;
|
||||
int lohits;
|
||||
Ulong *pixels;
|
||||
int status;
|
||||
|
||||
lohits = color_cache[0].hits;
|
||||
tofree = &color_cache[0];
|
||||
/* look in the cache and see if we have one that matches this request */
|
||||
for(cc = &color_cache[0]; cc < &color_cache[cc_entries]; cc++) {
|
||||
if(cc->hits < lohits) {
|
||||
lohits = cc->hits;
|
||||
tofree = cc;
|
||||
}
|
||||
if(cc->fg == fg && cc->bg == bg && cc->density == density &&
|
||||
cc->nlevels == nlevels && fabs(cc->gamma - gamma) <= GAMMA_DIFF)
|
||||
break;
|
||||
}
|
||||
|
||||
if(cc < &color_cache[cc_entries]) {
|
||||
cc->hits++;
|
||||
return cc->pixels;
|
||||
}
|
||||
|
||||
DEBUG((DBG_DEVICE, "Adding color table to cache (fg=%lu, bg=%lu, n=%d)\n",
|
||||
fg, bg, nlevels));
|
||||
|
||||
/* no entry was found in the cache, create a new one */
|
||||
if(cc_entries < CCSIZE) {
|
||||
cc = &color_cache[cc_entries++];
|
||||
cc->pixels = NULL;
|
||||
} else {
|
||||
cc = tofree;
|
||||
mdvi_free(cc->pixels);
|
||||
}
|
||||
pixels = xnalloc(Ulong, nlevels);
|
||||
status = dev->alloc_colors(dev->device_data,
|
||||
pixels, nlevels, fg, bg, gamma, density);
|
||||
if(status < 0) {
|
||||
mdvi_free(pixels);
|
||||
return NULL;
|
||||
}
|
||||
cc->fg = fg;
|
||||
cc->bg = bg;
|
||||
cc->gamma = gamma;
|
||||
cc->density = density;
|
||||
cc->nlevels = nlevels;
|
||||
cc->pixels = pixels;
|
||||
cc->hits = 1;
|
||||
return pixels;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _COLOR_H_
|
||||
#define _COLOR_H_
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern Ulong *get_color_table(DviDevice *dev,
|
||||
int nlevels, Ulong fg, Ulong bg, double gamma, int density);
|
||||
|
||||
extern void mdvi_set_color __PROTO((DviContext *, Ulong, Ulong));
|
||||
extern void mdvi_push_color __PROTO((DviContext *, Ulong, Ulong));
|
||||
extern void mdvi_pop_color __PROTO((DviContext *));
|
||||
extern void mdvi_reset_color __PROTO((DviContext *));
|
||||
|
||||
#endif /* _COLOR_H_ */
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
long fsgetn(FILE *p, size_t n)
|
||||
{
|
||||
long v;
|
||||
|
||||
v = fgetbyte(p);
|
||||
if(v & 0x80)
|
||||
v -= 0x100;
|
||||
while(--n > 0)
|
||||
v = (v << 8) | fgetbyte(p);
|
||||
return v;
|
||||
}
|
||||
|
||||
Ulong fugetn(FILE *p, size_t n)
|
||||
{
|
||||
Ulong v;
|
||||
|
||||
v = fgetbyte(p);
|
||||
while(--n > 0)
|
||||
v = (v << 8) | fgetbyte(p);
|
||||
return v;
|
||||
}
|
||||
|
||||
long msgetn(const Uchar *p, size_t n)
|
||||
{
|
||||
long v = (long)*p++;
|
||||
|
||||
if(v & 0x80)
|
||||
v -= 0x100;
|
||||
while(--n > 0)
|
||||
v = (v << 8) | *p++;
|
||||
return v;
|
||||
}
|
||||
|
||||
Ulong mugetn(const Uchar *p, size_t n)
|
||||
{
|
||||
Ulong v = (Ulong)*p++;
|
||||
|
||||
while(--n > 0)
|
||||
v = (v << 8) | *p++;
|
||||
return v;
|
||||
}
|
||||
|
||||
char *read_string(FILE *in, int s, char *buffer, size_t len)
|
||||
{
|
||||
int n;
|
||||
char *str;
|
||||
|
||||
n = fugetn(in, s ? s : 1);
|
||||
if((str = buffer) == NULL || n + 1 > len)
|
||||
str = mdvi_malloc(n + 1);
|
||||
if(fread(str, 1, n, in) != n) {
|
||||
if(str != buffer) mdvi_free(str);
|
||||
return NULL;
|
||||
}
|
||||
str[n] = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
size_t read_bcpl(FILE *in, char *buffer, size_t maxlen, size_t wanted)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
i = (int)fuget1(in);
|
||||
if(maxlen && i > maxlen)
|
||||
i = maxlen;
|
||||
if(fread(buffer, i, 1, in) != 1)
|
||||
return -1;
|
||||
buffer[i] = '\0';
|
||||
while(wanted-- > i)
|
||||
(void)fgetc(in);
|
||||
return i;
|
||||
}
|
||||
|
||||
char *read_alloc_bcpl(FILE *in, size_t maxlen, size_t *size)
|
||||
{
|
||||
size_t i;
|
||||
char *buffer;
|
||||
|
||||
i = (size_t)fuget1(in);
|
||||
if(maxlen && i > maxlen)
|
||||
i = maxlen;
|
||||
buffer = (char *)malloc(i + 1);
|
||||
if(buffer == NULL)
|
||||
return NULL;
|
||||
if(fread(buffer, i, 1, in) != 1) {
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
buffer[i] = '\0';
|
||||
if(size) *size = i;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/* buffers */
|
||||
|
||||
void buff_free(Buffer *buf)
|
||||
{
|
||||
if(buf->data)
|
||||
mdvi_free(buf->data);
|
||||
buff_init(buf);
|
||||
}
|
||||
|
||||
void buff_init(Buffer *buf)
|
||||
{
|
||||
buf->data = NULL;
|
||||
buf->size = 0;
|
||||
buf->length = 0;
|
||||
}
|
||||
|
||||
size_t buff_add(Buffer *buf, const char *data, size_t len)
|
||||
{
|
||||
if(!len && data)
|
||||
len = strlen(data);
|
||||
if(buf->length + len + 1 > buf->size) {
|
||||
buf->size = buf->length + len + 256;
|
||||
buf->data = mdvi_realloc(buf->data, buf->size);
|
||||
}
|
||||
memcpy(buf->data + buf->length, data, len);
|
||||
buf->length += len;
|
||||
return buf->length;
|
||||
}
|
||||
|
||||
char *buff_gets(Buffer *buf, size_t *length)
|
||||
{
|
||||
char *ptr;
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
ptr = strchr(buf->data, '\n');
|
||||
if(ptr == NULL)
|
||||
return NULL;
|
||||
ptr++; /* include newline */
|
||||
len = ptr - buf->data;
|
||||
ret = mdvi_malloc(len + 1);
|
||||
if(len > 0) {
|
||||
memcpy(ret, buf->data, len);
|
||||
memmove(buf->data, buf->data + len, buf->length - len);
|
||||
buf->length -= len;
|
||||
}
|
||||
ret[len] = 0;
|
||||
if(length) *length = len;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _MDVI_COMMON_H
|
||||
#define _MDVI_COMMON_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#if STDC_HEADERS
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#if !defined(STDC_HEADERS) || defined(__STRICT_ANSI__)
|
||||
# ifndef HAVE_STRCHR
|
||||
# define strchr index
|
||||
# define strrchr rindex
|
||||
# endif
|
||||
# ifndef HAVE_MEMCPY
|
||||
# define memcpy(a,b,n) bcopy((b), (a), (n))
|
||||
# define memmove(a,b,n) bcopy((b), (a), (n))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(STDC_HEADERS) || defined(HAVE_MEMCPY)
|
||||
#define memzero(a,n) memset((a), 0, (n))
|
||||
#else
|
||||
#define memzero(a,n) bzero((a), (n))
|
||||
#endif
|
||||
|
||||
typedef struct _List {
|
||||
struct _List *next;
|
||||
struct _List *prev;
|
||||
} List;
|
||||
#define LIST(x) ((List *)(x))
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
size_t size;
|
||||
size_t length;
|
||||
} Buffer;
|
||||
|
||||
typedef struct {
|
||||
List *head;
|
||||
List *tail;
|
||||
int count;
|
||||
} ListHead;
|
||||
#define MDVI_EMPTY_LIST_HEAD {NULL, NULL, 0}
|
||||
|
||||
typedef struct {
|
||||
char *data;
|
||||
size_t size;
|
||||
size_t length;
|
||||
} Dstring;
|
||||
|
||||
/* Functions to read numbers from streams and memory */
|
||||
|
||||
#define fgetbyte(p) ((unsigned)getc(p))
|
||||
|
||||
extern char *program_name;
|
||||
|
||||
extern Ulong fugetn __PROTO((FILE *, size_t));
|
||||
extern long fsgetn __PROTO((FILE *, size_t));
|
||||
extern Ulong mugetn __PROTO((const Uchar *, size_t));
|
||||
extern long msgetn __PROTO((const Uchar *, size_t));
|
||||
|
||||
/* To read from a stream (fu: unsigned, fs: signed) */
|
||||
#define fuget4(p) fugetn((p), 4)
|
||||
#define fuget3(p) fugetn((p), 3)
|
||||
#define fuget2(p) fugetn((p), 2)
|
||||
#define fuget1(p) fgetbyte(p)
|
||||
#define fsget4(p) fsgetn((p), 4)
|
||||
#define fsget3(p) fsgetn((p), 3)
|
||||
#define fsget2(p) fsgetn((p), 2)
|
||||
#define fsget1(p) fsgetn((p), 1)
|
||||
|
||||
/* To read from memory (mu: unsigned, ms: signed) */
|
||||
#define MUGETN(p,n) ((p) += (n), mugetn((p)-(n), (n)))
|
||||
#define MSGETN(p,n) ((p) += (n), msgetn((p)-(n), (n)))
|
||||
#define muget4(p) MUGETN((p), 4)
|
||||
#define muget3(p) MUGETN((p), 3)
|
||||
#define muget2(p) MUGETN((p), 2)
|
||||
#define muget1(p) MUGETN((p), 1)
|
||||
#define msget4(p) MSGETN((p), 4)
|
||||
#define msget3(p) MSGETN((p), 3)
|
||||
#define msget2(p) MSGETN((p), 2)
|
||||
#define msget1(p) MSGETN((p), 1)
|
||||
|
||||
#define ROUND(x,y) (((x) + (y) - 1) / (y))
|
||||
#define FROUND(x) (int)((x) + 0.5)
|
||||
#define SFROUND(x) (int)((x) >= 0 ? floor((x) + 0.5) : ceil((x) + 0.5))
|
||||
|
||||
#define Max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define Min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
/* make 2byte number from 2 8bit quantities */
|
||||
#define HALFWORD(a,b) ((((a) << 8) & 0xf) | (b))
|
||||
#define FULLWORD(a,b,c,d) \
|
||||
((((Int8)(a) << 24) & 0xff000000) | \
|
||||
(((Uint8)(b) << 16) & 0x00ff0000) | \
|
||||
(((Uint8)(c) << 8) & 0x0000ff00) | \
|
||||
((Uint8)(d) & 0xff))
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define SWAPINT(a,b) \
|
||||
({ int _s = a; a = b; b = _s; })
|
||||
#else
|
||||
#define SWAPINT(a,b) do { int _s = a; a = b; b = _s; } while(0)
|
||||
#endif
|
||||
|
||||
#define STREQ(a,b) (strcmp((a), (b)) == 0)
|
||||
#define STRNEQ(a,b,n) (strncmp((a), (b), (n)) == 0)
|
||||
#define STRCEQ(a,b) (strcasecmp((a), (b)) == 0)
|
||||
#define STRNCEQ(a,b,n) (strncasecmp((a), (b), (n)) == 0)
|
||||
|
||||
extern char *read_string __PROTO((FILE *, int, char *, size_t));
|
||||
extern size_t read_bcpl __PROTO((FILE *, char *, size_t, size_t));
|
||||
extern char *read_alloc_bcpl __PROTO((FILE *, size_t, size_t *));
|
||||
|
||||
/* miscellaneous */
|
||||
|
||||
extern void mdvi_message __PROTO((const char *, ...));
|
||||
extern void mdvi_crash __PROTO((const char *, ...));
|
||||
extern void mdvi_fatal __PROTO((const char *, ...));
|
||||
extern void mdvi_error __PROTO((const char *, ...));
|
||||
extern void mdvi_warning __PROTO((const char *, ...));
|
||||
extern int unit2pix __PROTO((int, const char *));
|
||||
extern double unit2pix_factor __PROTO((const char *));
|
||||
|
||||
#define LOG_NONE -1
|
||||
#define LOG_INFO 0
|
||||
#define LOG_WARN 1
|
||||
#define LOG_ERROR 2
|
||||
#define LOG_DEBUG 3
|
||||
|
||||
#define DBG_OPCODE (1 << 0)
|
||||
#define DBG_FONTS (1 << 1)
|
||||
#define DBG_FILES (1 << 2)
|
||||
#define DBG_DVI (1 << 3)
|
||||
#define DBG_PARAMS (1 << 4)
|
||||
#define DBG_SPECIAL (1 << 5)
|
||||
#define DBG_DEVICE (1 << 6)
|
||||
#define DBG_GLYPHS (1 << 7)
|
||||
#define DBG_BITMAPS (1 << 8)
|
||||
#define DBG_PATHS (1 << 9)
|
||||
#define DBG_SEARCH (1 << 10)
|
||||
#define DBG_VARS (1 << 11)
|
||||
#define DBG_BITMAP_OPS (1 << 12)
|
||||
#define DBG_BITMAP_DATA (1 << 13)
|
||||
#define DBG_TYPE1 (1 << 14)
|
||||
#define DBG_TT (1 << 15)
|
||||
#define DBG_FT2 (1 << 16)
|
||||
#define DBG_FMAP (1 << 17)
|
||||
|
||||
#define DBG_SILENT (1 << 31)
|
||||
|
||||
#ifdef NODEBUG
|
||||
#define DEBUGGING(x) 0
|
||||
#else
|
||||
#define DEBUGGING(x) (_mdvi_debug_mask & DBG_##x)
|
||||
#endif
|
||||
|
||||
#ifndef NODEBUG
|
||||
extern Uint32 _mdvi_debug_mask;
|
||||
extern void __debug __PROTO((int, const char *, ...));
|
||||
#define DEBUG(x) __debug x
|
||||
#define ASSERT(x) do { \
|
||||
if(!(x)) mdvi_crash("%s:%d: Assertion %s failed\n", \
|
||||
__FILE__, __LINE__, #x); \
|
||||
} while(0)
|
||||
#define ASSERT_VALUE(x,y) do { \
|
||||
if((x) != (y)) \
|
||||
mdvi_crash("%s:%d: Assertion failed (%d = %s != %s)\n", \
|
||||
__FILE__, __LINE__, (x), #x, #x); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DEBUG(x) do { } while(0)
|
||||
#define ASSERT(x) do { } while(0)
|
||||
#define ASSERT_VALUE(x,y) do { } while(0)
|
||||
#endif
|
||||
|
||||
#define set_debug_mask(m) (_mdvi_debug_mask = (Uint32)(m))
|
||||
#define add_debug_mask(m) (_mdvi_debug_mask |= (Uint32)(m))
|
||||
#define get_debug_mask() _mdvi_debug_mask
|
||||
|
||||
/* memory allocation */
|
||||
|
||||
extern void mdvi_free __PROTO((void *));
|
||||
extern void *mdvi_malloc __PROTO((size_t));
|
||||
extern void *mdvi_realloc __PROTO((void *, size_t));
|
||||
extern void *mdvi_calloc __PROTO((size_t, size_t));
|
||||
extern char *mdvi_strncpy __PROTO((char *, const char *, size_t));
|
||||
extern char *mdvi_strdup __PROTO((const char *));
|
||||
extern char *mdvi_strndup __PROTO((const char *, size_t));
|
||||
extern void *mdvi_memdup __PROTO((const void *, size_t));
|
||||
extern char *mdvi_build_path_from_cwd __PROTO((const char *));
|
||||
extern char *mdvi_strrstr __PROTO((const char *, const char *));
|
||||
|
||||
/* macros to make memory allocation nicer */
|
||||
#define xalloc(t) (t *)mdvi_malloc(sizeof(t))
|
||||
#define xnalloc(t,n) (t *)mdvi_calloc((n), sizeof(t))
|
||||
#define xresize(p,t,n) (t *)mdvi_realloc((p), (n) * sizeof(t))
|
||||
|
||||
extern char *xstradd __PROTO((char *, size_t *, size_t, const char *, size_t));
|
||||
|
||||
extern Ulong get_mtime __PROTO((int));
|
||||
|
||||
/* lists */
|
||||
extern void listh_init __PROTO((ListHead *));
|
||||
extern void listh_prepend __PROTO((ListHead *, List *));
|
||||
extern void listh_append __PROTO((ListHead *, List *));
|
||||
extern void listh_add_before __PROTO((ListHead *, List *, List *));
|
||||
extern void listh_add_after __PROTO((ListHead *, List *, List *));
|
||||
extern void listh_remove __PROTO((ListHead *, List *));
|
||||
extern void listh_concat __PROTO((ListHead *, ListHead *));
|
||||
extern void listh_catcon __PROTO((ListHead *, ListHead *));
|
||||
|
||||
extern void buff_init __PROTO((Buffer *));
|
||||
extern size_t buff_add __PROTO((Buffer *, const char *, size_t));
|
||||
extern char *buff_gets __PROTO((Buffer *, size_t *));
|
||||
extern void buff_free __PROTO((Buffer *));
|
||||
|
||||
extern char *getword __PROTO((char *, const char *, char **));
|
||||
extern char *getstring __PROTO((char *, const char *, char **));
|
||||
|
||||
extern void dstring_init __PROTO((Dstring *));
|
||||
extern int dstring_new __PROTO((Dstring *, const char *, int));
|
||||
extern int dstring_append __PROTO((Dstring *, const char *, int));
|
||||
extern int dstring_copy __PROTO((Dstring *, int, const char *, int));
|
||||
extern int dstring_insert __PROTO((Dstring *, int, const char *, int));
|
||||
extern void dstring_reset __PROTO((Dstring *));
|
||||
|
||||
#define dstring_length(d) ((d)->length)
|
||||
#define dstring_strcat(d,s) dstring_append((d), (s), -1)
|
||||
|
||||
extern char *dgets __PROTO((Dstring *, FILE *));
|
||||
extern int file_readable __PROTO((const char *));
|
||||
extern int file_exists __PROTO((const char *));
|
||||
extern const char *file_basename __PROTO((const char *));
|
||||
extern const char *file_extension __PROTO((const char *));
|
||||
|
||||
/*
|
||||
* Miscellaneous macros
|
||||
*/
|
||||
|
||||
#define LIST_FOREACH(ptr, type, list) \
|
||||
for(ptr = (type *)(list)->head; ptr; ptr = (ptr)->next)
|
||||
|
||||
#define Size(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
/* multiply a fix_word by a 32bit number */
|
||||
#define B0(x) ((x) & 0xff)
|
||||
#define B1(x) B0((x) >> 8)
|
||||
#define B2(x) B0((x) >> 16)
|
||||
#define B3(x) B0((x) >> 24)
|
||||
#define __tfm_mul(z,t) \
|
||||
(((((B0(t) * (z)) >> 8) + (B1(t) * (z))) >> 8) + B2(t) * (z))
|
||||
#define TFMSCALE(z,t,a,b) \
|
||||
((B3(t) == 255) ? \
|
||||
__tfm_mul((z), (t)) / (b) - (a) : \
|
||||
__tfm_mul((z), (t)) / (b))
|
||||
#define TFMPREPARE(x,z,a,b) do { \
|
||||
a = 16; z = (x); \
|
||||
while(z > 040000000L) { z >>= 1; a <<= 1; } \
|
||||
b = 256 / a; a *= z; \
|
||||
} while(0)
|
||||
|
||||
#endif /* _MDVI_COMMON_H */
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _MDVI_DEFAULTS_H
|
||||
#define _MDVI_DEFAULTS_H 1
|
||||
|
||||
/* resolution */
|
||||
#define MDVI_DPI 600
|
||||
#define MDVI_VDPI MDVI_DPI
|
||||
|
||||
/* horizontal margins */
|
||||
#define MDVI_HMARGIN "1in"
|
||||
|
||||
/* vertical margins */
|
||||
#define MDVI_VMARGIN "1in"
|
||||
|
||||
/* rulers */
|
||||
#define MDVI_HRUNITS "1in"
|
||||
#define MDVI_VRUNITS "1in"
|
||||
|
||||
/* paper */
|
||||
#define MDVI_PAPERNAME "letter"
|
||||
|
||||
/* magnification */
|
||||
#define MDVI_MAGNIFICATION 1.0
|
||||
|
||||
/* fallback font */
|
||||
#define MDVI_FALLBACK_FONT "cmr10"
|
||||
|
||||
/* metafont mode */
|
||||
#define MDVI_MFMODE NULL
|
||||
|
||||
/* default shrinking factor */
|
||||
#define MDVI_DEFAULT_SHRINKING -1 /* based on resolution */
|
||||
|
||||
/* default pixel density */
|
||||
#define MDVI_DEFAULT_DENSITY 50
|
||||
|
||||
/* default gamma correction */
|
||||
#define MDVI_DEFAULT_GAMMA 1.0
|
||||
|
||||
/* default window geometry */
|
||||
#define MDVI_GEOMETRY NULL
|
||||
|
||||
/* default orientation */
|
||||
#define MDVI_ORIENTATION "tblr"
|
||||
|
||||
/* colors */
|
||||
#define MDVI_FOREGROUND "black"
|
||||
#define MDVI_BACKGROUND "white"
|
||||
|
||||
/* flags */
|
||||
#define MDVI_DEFAULT_FLAGS MDVI_ANTIALIASED
|
||||
|
||||
#define MDVI_DEFAULT_CONFIG "mdvi.conf"
|
||||
|
||||
#endif /* _MDVI_DEAFAULTS_H */
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef _MDVI_DVIOPCODES_H
|
||||
#define _MDVI_DVIOPCODES_H 1
|
||||
|
||||
#define DVI_SET_CHAR0 0
|
||||
#define DVI_SET_CHAR1 1
|
||||
#define DVI_SET_CHAR_MAX 127
|
||||
#define DVI_SET1 128
|
||||
#define DVI_SET2 129
|
||||
#define DVI_SET3 130
|
||||
#define DVI_SET4 131
|
||||
#define DVI_SET_RULE 132
|
||||
#define DVI_PUT1 133
|
||||
#define DVI_PUT2 134
|
||||
#define DVI_PUT3 135
|
||||
#define DVI_PUT4 136
|
||||
#define DVI_PUT_RULE 137
|
||||
#define DVI_NOOP 138
|
||||
#define DVI_BOP 139
|
||||
#define DVI_EOP 140
|
||||
#define DVI_PUSH 141
|
||||
#define DVI_POP 142
|
||||
#define DVI_RIGHT1 143
|
||||
#define DVI_RIGHT2 144
|
||||
#define DVI_RIGHT3 145
|
||||
#define DVI_RIGHT4 146
|
||||
#define DVI_W0 147
|
||||
#define DVI_W1 148
|
||||
#define DVI_W2 149
|
||||
#define DVI_W3 150
|
||||
#define DVI_W4 151
|
||||
#define DVI_X0 152
|
||||
#define DVI_X1 153
|
||||
#define DVI_X2 154
|
||||
#define DVI_X3 155
|
||||
#define DVI_X4 156
|
||||
#define DVI_DOWN1 157
|
||||
#define DVI_DOWN2 158
|
||||
#define DVI_DOWN3 159
|
||||
#define DVI_DOWN4 160
|
||||
#define DVI_Y0 161
|
||||
#define DVI_Y1 162
|
||||
#define DVI_Y2 163
|
||||
#define DVI_Y3 164
|
||||
#define DVI_Y4 165
|
||||
#define DVI_Z0 166
|
||||
#define DVI_Z1 167
|
||||
#define DVI_Z2 168
|
||||
#define DVI_Z3 169
|
||||
#define DVI_Z4 170
|
||||
#define DVI_FNT_NUM0 171
|
||||
#define DVI_FNT_NUM1 172
|
||||
#define DVI_FNT_NUM_MAX 234
|
||||
#define DVI_FNT1 235
|
||||
#define DVI_FNT2 236
|
||||
#define DVI_FNT3 237
|
||||
#define DVI_FNT4 238
|
||||
#define DVI_XXX1 239
|
||||
#define DVI_XXX2 240
|
||||
#define DVI_XXX3 241
|
||||
#define DVI_XXX4 242
|
||||
#define DVI_FNT_DEF1 243
|
||||
#define DVI_FNT_DEF2 244
|
||||
#define DVI_FNT_DEF3 245
|
||||
#define DVI_FNT_DEF4 246
|
||||
#define DVI_PRE 247
|
||||
#define DVI_POST 248
|
||||
#define DVI_POST_POST 249
|
||||
|
||||
#define DVI_ID 2
|
||||
#define DVI_TRAILER 223
|
||||
|
||||
#endif /* _MDVI_DVIOPCODES_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
char *dgets(Dstring *dstr, FILE *in)
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
dstr->length = 0;
|
||||
if(feof(in))
|
||||
return NULL;
|
||||
while(fgets(buffer, 256, in) != NULL) {
|
||||
int len = strlen(buffer);
|
||||
|
||||
if(buffer[len-1] == '\n') {
|
||||
dstring_append(dstr, buffer, len - 1);
|
||||
break;
|
||||
}
|
||||
dstring_append(dstr, buffer, len);
|
||||
}
|
||||
if(dstr->data)
|
||||
dstr->data[dstr->length] = 0;
|
||||
return dstr->data;
|
||||
}
|
||||
|
||||
/* some simple helper functions to manipulate file names */
|
||||
|
||||
const char *file_basename(const char *filename)
|
||||
{
|
||||
const char *ptr = strrchr(filename, '/');
|
||||
|
||||
return (ptr ? ptr + 1 : filename);
|
||||
}
|
||||
|
||||
const char *file_extension(const char *filename)
|
||||
{
|
||||
const char *ptr = strchr(file_basename(filename), '.');
|
||||
|
||||
return (ptr ? ptr + 1 : NULL);
|
||||
}
|
||||
|
||||
int file_readable(const char *filename)
|
||||
{
|
||||
int status = (access(filename, R_OK) == 0);
|
||||
|
||||
DEBUG((DBG_FILES, "file_redable(%s) -> %s\n",
|
||||
filename, status ? "Yes" : "No"));
|
||||
return status;
|
||||
}
|
||||
|
||||
int file_exists(const char *filename)
|
||||
{
|
||||
int status = (access(filename, F_OK) == 0);
|
||||
|
||||
DEBUG((DBG_FILES, "file_exists(%s) -> %s\n",
|
||||
filename, status ? "Yes" : "No"));
|
||||
return status;
|
||||
}
|
||||
|
|
@ -0,0 +1,519 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
static ListHead fontlist;
|
||||
|
||||
extern char *_mdvi_fallback_font;
|
||||
|
||||
extern void vf_free_macros(DviFont *);
|
||||
|
||||
#define finfo search.info
|
||||
#define TYPENAME(font) \
|
||||
((font)->finfo ? (font)->finfo->name : "none")
|
||||
|
||||
int font_reopen(DviFont *font)
|
||||
{
|
||||
if(font->in)
|
||||
fseek(font->in, (long)0, SEEK_SET);
|
||||
else if((font->in = fopen(font->filename, "rb")) == NULL) {
|
||||
DEBUG((DBG_FILES, "reopen(%s) -> Error\n", font->filename));
|
||||
return -1;
|
||||
}
|
||||
DEBUG((DBG_FILES, "reopen(%s) -> Ok.\n", font->filename));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* used from context: params and device */
|
||||
static int load_font_file(DviParams *params, DviFont *font)
|
||||
{
|
||||
int status;
|
||||
|
||||
if(SEARCH_DONE(font->search))
|
||||
return -1;
|
||||
if(font->in == NULL && font_reopen(font) < 0)
|
||||
return -1;
|
||||
DEBUG((DBG_FONTS, "%s: loading %s font from `%s'\n",
|
||||
font->fontname,
|
||||
font->finfo->name, font->filename));
|
||||
do {
|
||||
status = font->finfo->load(params, font);
|
||||
} while(status < 0 && mdvi_font_retry(params, font) == 0);
|
||||
if(status < 0)
|
||||
return -1;
|
||||
if(font->in) {
|
||||
fclose(font->in);
|
||||
font->in = NULL;
|
||||
}
|
||||
DEBUG((DBG_FONTS, "reload_font(%s) -> %s\n",
|
||||
font->fontname, status < 0 ? "Error" : "Ok"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void font_drop_one(DviFontRef *ref)
|
||||
{
|
||||
DviFont *font;
|
||||
|
||||
font = ref->ref;
|
||||
mdvi_free(ref);
|
||||
/* drop all children */
|
||||
for(ref = font->subfonts; ref; ref = ref->next) {
|
||||
/* just adjust the reference counts */
|
||||
ref->ref->links--;
|
||||
}
|
||||
if(--font->links == 0) {
|
||||
/*
|
||||
* this font doesn't have any more references, but
|
||||
* we still keep it around in case a virtual font
|
||||
* requests it.
|
||||
*/
|
||||
if(font->in) {
|
||||
fclose(font->in);
|
||||
font->in = NULL;
|
||||
}
|
||||
if(LIST(font) != fontlist.tail) {
|
||||
/* move it to the end of the list */
|
||||
listh_remove(&fontlist, LIST(font));
|
||||
listh_append(&fontlist, LIST(font));
|
||||
}
|
||||
}
|
||||
DEBUG((DBG_FONTS, "%s: reference dropped, %d more left\n",
|
||||
font->fontname, font->links));
|
||||
}
|
||||
|
||||
void font_drop_chain(DviFontRef *head)
|
||||
{
|
||||
DviFontRef *ptr;
|
||||
|
||||
for(; (ptr = head); ) {
|
||||
head = ptr->next;
|
||||
font_drop_one(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
int font_free_unused(DviDevice *dev)
|
||||
{
|
||||
DviFont *font, *next;
|
||||
int count = 0;
|
||||
|
||||
DEBUG((DBG_FONTS, "destroying unused fonts\n"));
|
||||
for(font = (DviFont *)fontlist.head; font; font = next) {
|
||||
DviFontRef *ref;
|
||||
|
||||
next = font->next;
|
||||
if(font->links)
|
||||
continue;
|
||||
count++;
|
||||
DEBUG((DBG_FONTS, "removing unused %s font `%s'\n",
|
||||
TYPENAME(font), font->fontname));
|
||||
listh_remove(&fontlist, LIST(font));
|
||||
if(font->in)
|
||||
fclose(font->in);
|
||||
/* get rid of subfonts (but can't use `drop_chain' here) */
|
||||
for(; (ref = font->subfonts); ) {
|
||||
font->subfonts = ref->next;
|
||||
mdvi_free(ref);
|
||||
}
|
||||
/* remove this font */
|
||||
font_reset_font_glyphs(dev, font, MDVI_FONTSEL_GLYPH);
|
||||
/* let the font destroy its private data */
|
||||
if(font->finfo->freedata)
|
||||
font->finfo->freedata(font);
|
||||
/* destroy characters */
|
||||
if(font->chars)
|
||||
mdvi_free(font->chars);
|
||||
mdvi_free(font->fontname);
|
||||
mdvi_free(font->filename);
|
||||
mdvi_free(font);
|
||||
}
|
||||
DEBUG((DBG_FONTS, "%d unused fonts removed\n", count));
|
||||
return count;
|
||||
}
|
||||
|
||||
/* used from context: params and device */
|
||||
DviFontRef *
|
||||
font_reference(
|
||||
DviParams *params, /* rendering parameters */
|
||||
Int32 id, /* external id number */
|
||||
const char *name, /* font name */
|
||||
Int32 sum, /* checksum (from DVI of VF) */
|
||||
int hdpi, /* resolution */
|
||||
int vdpi,
|
||||
Int32 scale) /* scaling factor (from DVI or VF) */
|
||||
{
|
||||
DviFont *font;
|
||||
DviFontRef *ref;
|
||||
DviFontRef *subfont_ref;
|
||||
|
||||
/* see if there is a font with the same characteristics */
|
||||
for(font = (DviFont *)fontlist.head; font; font = font->next) {
|
||||
if(strcmp(name, font->fontname) == 0
|
||||
&& (!sum || !font->checksum || font->checksum == sum)
|
||||
&& font->hdpi == hdpi
|
||||
&& font->vdpi == vdpi
|
||||
&& font->scale == scale)
|
||||
break;
|
||||
}
|
||||
/* try to load the font */
|
||||
if(font == NULL) {
|
||||
font = mdvi_add_font(name, sum, hdpi, vdpi, scale);
|
||||
if(font == NULL)
|
||||
return NULL;
|
||||
listh_append(&fontlist, LIST(font));
|
||||
}
|
||||
if(!font->links && !font->chars && load_font_file(params, font) < 0) {
|
||||
DEBUG((DBG_FONTS, "font_reference(%s) -> Error\n", name));
|
||||
return NULL;
|
||||
}
|
||||
ref = xalloc(DviFontRef);
|
||||
ref->ref = font;
|
||||
|
||||
font->links++;
|
||||
for(subfont_ref = font->subfonts; subfont_ref; subfont_ref = subfont_ref->next) {
|
||||
/* just adjust the reference counts */
|
||||
subfont_ref->ref->links++;
|
||||
}
|
||||
|
||||
ref->fontid = id;
|
||||
|
||||
if(LIST(font) != fontlist.head) {
|
||||
listh_remove(&fontlist, LIST(font));
|
||||
listh_prepend(&fontlist, LIST(font));
|
||||
}
|
||||
|
||||
DEBUG((DBG_FONTS, "font_reference(%s) -> %d links\n",
|
||||
font->fontname, font->links));
|
||||
return ref;
|
||||
}
|
||||
|
||||
void font_transform_glyph(DviOrientation orient, DviGlyph *g)
|
||||
{
|
||||
BITMAP *map;
|
||||
int x, y;
|
||||
|
||||
map = (BITMAP *)g->data;
|
||||
if(MDVI_GLYPH_ISEMPTY(map))
|
||||
map = NULL;
|
||||
|
||||
/* put the glyph in the right orientation */
|
||||
switch(orient) {
|
||||
case MDVI_ORIENT_TBLR:
|
||||
break;
|
||||
case MDVI_ORIENT_TBRL:
|
||||
g->x = g->w - g->x;
|
||||
if(map) bitmap_flip_horizontally(map);
|
||||
break;
|
||||
case MDVI_ORIENT_BTLR:
|
||||
g->y = g->h - g->y;
|
||||
if(map) bitmap_flip_vertically(map);
|
||||
break;
|
||||
case MDVI_ORIENT_BTRL:
|
||||
g->x = g->w - g->x;
|
||||
g->y = g->h - g->y;
|
||||
if(map) bitmap_flip_diagonally(map);
|
||||
break;
|
||||
case MDVI_ORIENT_RP90:
|
||||
if(map) bitmap_rotate_counter_clockwise(map);
|
||||
y = g->y;
|
||||
x = g->w - g->x;
|
||||
g->x = y;
|
||||
g->y = x;
|
||||
SWAPINT(g->w, g->h);
|
||||
break;
|
||||
case MDVI_ORIENT_RM90:
|
||||
if(map) bitmap_rotate_clockwise(map);
|
||||
y = g->h - g->y;
|
||||
x = g->x;
|
||||
g->x = y;
|
||||
g->y = x;
|
||||
SWAPINT(g->w, g->h);
|
||||
break;
|
||||
case MDVI_ORIENT_IRP90:
|
||||
if(map) bitmap_flip_rotate_counter_clockwise(map);
|
||||
y = g->y;
|
||||
x = g->x;
|
||||
g->x = y;
|
||||
g->y = x;
|
||||
SWAPINT(g->w, g->h);
|
||||
break;
|
||||
case MDVI_ORIENT_IRM90:
|
||||
if(map) bitmap_flip_rotate_clockwise(map);
|
||||
y = g->h - g->y;
|
||||
x = g->w - g->x;
|
||||
g->x = y;
|
||||
g->y = x;
|
||||
SWAPINT(g->w, g->h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int load_one_glyph(DviContext *dvi, DviFont *font, int code)
|
||||
{
|
||||
BITMAP *map;
|
||||
DviFontChar *ch;
|
||||
int status;
|
||||
|
||||
#ifndef NODEBUG
|
||||
ch = FONTCHAR(font, code);
|
||||
DEBUG((DBG_GLYPHS, "loading glyph code %d in %s (at %u)\n",
|
||||
code, font->fontname, ch->offset));
|
||||
#endif
|
||||
if(font->finfo->getglyph == NULL) {
|
||||
/* font type does not need to load glyphs (e.g. vf) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
status = font->finfo->getglyph(&dvi->params, font, code);
|
||||
if(status < 0)
|
||||
return -1;
|
||||
/* get the glyph again (font->chars may have changed) */
|
||||
ch = FONTCHAR(font, code);
|
||||
#ifndef NODEBUG
|
||||
map = (BITMAP *)ch->glyph.data;
|
||||
if(DEBUGGING(BITMAP_DATA)) {
|
||||
DEBUG((DBG_BITMAP_DATA,
|
||||
"%s: new %s bitmap for character %d:\n",
|
||||
font->fontname, TYPENAME(font), code));
|
||||
if(MDVI_GLYPH_ISEMPTY(map))
|
||||
DEBUG((DBG_BITMAP_DATA, "blank bitmap\n"));
|
||||
else
|
||||
bitmap_print(stderr, map);
|
||||
}
|
||||
#endif
|
||||
/* check if we have to scale it */
|
||||
if(!font->finfo->scalable && font->hdpi != font->vdpi) {
|
||||
int hs, vs, d;
|
||||
|
||||
/* we scale it ourselves */
|
||||
d = Max(font->hdpi, font->vdpi);
|
||||
hs = d / font->hdpi;
|
||||
vs = d / font->vdpi;
|
||||
if(ch->width && ch->height && (hs > 1 || vs > 1)) {
|
||||
int h, v;
|
||||
DviGlyph glyph;
|
||||
|
||||
DEBUG((DBG_FONTS,
|
||||
"%s: scaling glyph %d to resolution %dx%d\n",
|
||||
font->fontname, code, font->hdpi, font->vdpi));
|
||||
h = dvi->params.hshrink;
|
||||
v = dvi->params.vshrink;
|
||||
d = dvi->params.density;
|
||||
dvi->params.hshrink = hs;
|
||||
dvi->params.vshrink = vs;
|
||||
dvi->params.density = 50;
|
||||
/* shrink it */
|
||||
font->finfo->shrink0(dvi, font, ch, &glyph);
|
||||
/* restore parameters */
|
||||
dvi->params.hshrink = h;
|
||||
dvi->params.vshrink = v;
|
||||
dvi->params.density = d;
|
||||
/* update glyph data */
|
||||
if(!MDVI_GLYPH_ISEMPTY(ch->glyph.data))
|
||||
bitmap_destroy((BITMAP *)ch->glyph.data);
|
||||
ch->glyph.data = glyph.data;
|
||||
ch->glyph.x = glyph.x;
|
||||
ch->glyph.y = glyph.y;
|
||||
ch->glyph.w = glyph.w;
|
||||
ch->glyph.h = glyph.h;
|
||||
}
|
||||
|
||||
}
|
||||
font_transform_glyph(dvi->params.orientation, &ch->glyph);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DviFontChar *font_get_glyph(DviContext *dvi, DviFont *font, int code)
|
||||
{
|
||||
DviFontChar *ch;
|
||||
|
||||
again:
|
||||
/* if we have not loaded the font yet, do so now */
|
||||
if(!font->chars && load_font_file(&dvi->params, font) < 0)
|
||||
return NULL;
|
||||
|
||||
/* get the unscaled glyph, maybe loading it from disk */
|
||||
ch = FONTCHAR(font, code);
|
||||
if(!ch || !glyph_present(ch))
|
||||
return NULL;
|
||||
if(!ch->loaded && load_one_glyph(dvi, font, code) == -1) {
|
||||
if(font->chars == NULL) {
|
||||
/* we need to try another font class */
|
||||
goto again;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* yes, we have to do this again */
|
||||
ch = FONTCHAR(font, code);
|
||||
|
||||
/* Got the glyph. If we also have the right scaled glyph, do no more */
|
||||
if(!ch->width || !ch->height ||
|
||||
font->finfo->getglyph == NULL ||
|
||||
(dvi->params.hshrink == 1 && dvi->params.vshrink == 1))
|
||||
return ch;
|
||||
|
||||
/* If the glyph is empty, we just need to shrink the box */
|
||||
if(ch->missing || MDVI_GLYPH_ISEMPTY(ch->glyph.data)) {
|
||||
if(MDVI_GLYPH_UNSET(ch->shrunk.data))
|
||||
mdvi_shrink_box(dvi, font, ch, &ch->shrunk);
|
||||
return ch;
|
||||
} else if(MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) {
|
||||
if(ch->grey.data &&
|
||||
!MDVI_GLYPH_ISEMPTY(ch->grey.data) &&
|
||||
ch->fg == dvi->curr_fg &&
|
||||
ch->bg == dvi->curr_bg)
|
||||
return ch;
|
||||
if(ch->grey.data &&
|
||||
!MDVI_GLYPH_ISEMPTY(ch->grey.data)) {
|
||||
if(dvi->device.free_image)
|
||||
dvi->device.free_image(ch->grey.data);
|
||||
ch->grey.data = NULL;
|
||||
}
|
||||
font->finfo->shrink1(dvi, font, ch, &ch->grey);
|
||||
} else if(!ch->shrunk.data)
|
||||
font->finfo->shrink0(dvi, font, ch, &ch->shrunk);
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
void font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what)
|
||||
{
|
||||
if(!glyph_present(ch))
|
||||
return;
|
||||
if(what & MDVI_FONTSEL_BITMAP) {
|
||||
if(MDVI_GLYPH_NONEMPTY(ch->shrunk.data))
|
||||
bitmap_destroy((BITMAP *)ch->shrunk.data);
|
||||
ch->shrunk.data = NULL;
|
||||
}
|
||||
if(what & MDVI_FONTSEL_GREY) {
|
||||
if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) {
|
||||
if(dev->free_image)
|
||||
dev->free_image(ch->grey.data);
|
||||
}
|
||||
ch->grey.data = NULL;
|
||||
}
|
||||
if(what & MDVI_FONTSEL_GLYPH) {
|
||||
if(MDVI_GLYPH_NONEMPTY(ch->glyph.data))
|
||||
bitmap_destroy((BITMAP *)ch->glyph.data);
|
||||
ch->glyph.data = NULL;
|
||||
ch->loaded = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what)
|
||||
{
|
||||
int i;
|
||||
DviFontChar *ch;
|
||||
|
||||
if(what & MDVI_FONTSEL_GLYPH)
|
||||
what |= MDVI_FONTSEL_BITMAP|MDVI_FONTSEL_GREY;
|
||||
if(font->subfonts) {
|
||||
DviFontRef *ref;
|
||||
|
||||
for(ref = font->subfonts; ref; ref = ref->next)
|
||||
font_reset_font_glyphs(dev, ref->ref, what);
|
||||
}
|
||||
if(font->in) {
|
||||
DEBUG((DBG_FILES, "close(%s)\n", font->filename));
|
||||
fclose(font->in);
|
||||
font->in = NULL;
|
||||
}
|
||||
if(font->finfo->getglyph == NULL)
|
||||
return;
|
||||
DEBUG((DBG_FONTS, "resetting glyphs in font `%s'\n", font->fontname));
|
||||
for(ch = font->chars, i = font->loc; i <= font->hic; ch++, i++) {
|
||||
if(glyph_present(ch))
|
||||
font_reset_one_glyph(dev, ch, what);
|
||||
}
|
||||
if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset)
|
||||
font->finfo->reset(font);
|
||||
}
|
||||
|
||||
void font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what)
|
||||
{
|
||||
DviFontRef *ref;
|
||||
|
||||
for(ref = head; ref; ref = ref->next)
|
||||
font_reset_font_glyphs(dev, ref->ref, what);
|
||||
}
|
||||
|
||||
static int compare_refs(const void *p1, const void *p2)
|
||||
{
|
||||
return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid);
|
||||
}
|
||||
|
||||
void font_finish_definitions(DviContext *dvi)
|
||||
{
|
||||
int count;
|
||||
DviFontRef **map, *ref;
|
||||
|
||||
/* first get rid of unused fonts */
|
||||
font_free_unused(&dvi->device);
|
||||
|
||||
if(dvi->fonts == NULL) {
|
||||
mdvi_warning(_("%s: no fonts defined\n"), dvi->filename);
|
||||
return;
|
||||
}
|
||||
map = xnalloc(DviFontRef *, dvi->nfonts);
|
||||
for(count = 0, ref = dvi->fonts; ref; ref = ref->next)
|
||||
map[count++] = ref;
|
||||
/* sort the array by font id */
|
||||
qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs);
|
||||
dvi->fontmap = map;
|
||||
}
|
||||
|
||||
DviFontRef *font_find_flat(DviContext *dvi, Int32 id)
|
||||
{
|
||||
DviFontRef *ref;
|
||||
|
||||
for(ref = dvi->fonts; ref; ref = ref->next)
|
||||
if(ref->fontid == id)
|
||||
break;
|
||||
return ref;
|
||||
}
|
||||
|
||||
DviFontRef *font_find_mapped(DviContext *dvi, Int32 id)
|
||||
{
|
||||
int lo, hi, n;
|
||||
DviFontRef **map;
|
||||
|
||||
/* do a binary search */
|
||||
lo = 0; hi = dvi->nfonts;
|
||||
map = dvi->fontmap;
|
||||
while(lo < hi) {
|
||||
int sign;
|
||||
|
||||
n = (hi + lo) >> 1;
|
||||
sign = (map[n]->fontid - id);
|
||||
if(sign == 0)
|
||||
break;
|
||||
else if(sign < 0)
|
||||
lo = n;
|
||||
else
|
||||
hi = n;
|
||||
}
|
||||
if(lo >= hi)
|
||||
return NULL;
|
||||
return map[n];
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _MDVI_FONTMAP_H
|
||||
#define _MDVI_FONTMAP_H 1
|
||||
|
||||
typedef struct _DviFontMapEnt DviFontMapEnt;
|
||||
typedef struct _DviEncoding DviEncoding;
|
||||
|
||||
typedef struct {
|
||||
const char *psname;
|
||||
const char *encoding;
|
||||
const char *fontfile;
|
||||
const char *fullfile;
|
||||
const char *fmfile;
|
||||
int fmtype;
|
||||
long extend;
|
||||
long slant;
|
||||
} DviFontMapInfo;
|
||||
|
||||
struct _DviEncoding {
|
||||
DviEncoding *next;
|
||||
DviEncoding *prev;
|
||||
char *private;
|
||||
char *filename;
|
||||
char *name;
|
||||
char **vector; /* table with exactly 256 strings */
|
||||
int links;
|
||||
long offset;
|
||||
DviHashTable nametab;
|
||||
};
|
||||
|
||||
struct _DviFontMapEnt {
|
||||
DviFontMapEnt *next;
|
||||
DviFontMapEnt *prev;
|
||||
char *private;
|
||||
char *fontname;
|
||||
char *psname;
|
||||
char *encoding;
|
||||
char *encfile;
|
||||
char *fontfile;
|
||||
char *fullfile;
|
||||
long extend;
|
||||
long slant;
|
||||
};
|
||||
|
||||
#define MDVI_FMAP_SLANT(x) ((double)(x)->slant / 10000.0)
|
||||
#define MDVI_FMAP_EXTEND(x) ((double)(x)->extend / 10000.0)
|
||||
|
||||
extern DviEncoding *mdvi_request_encoding __PROTO((const char *));
|
||||
extern void mdvi_release_encoding __PROTO((DviEncoding *, int));
|
||||
extern int mdvi_encode_glyph __PROTO((DviEncoding *, const char *));
|
||||
extern DviFontMapEnt *mdvi_load_fontmap __PROTO((const char *));
|
||||
extern void mdvi_install_fontmap __PROTO((DviFontMapEnt *));
|
||||
extern int mdvi_load_fontmaps __PROTO((void));
|
||||
extern int mdvi_query_fontmap __PROTO((DviFontMapInfo *, const char *));
|
||||
extern void mdvi_flush_encodings __PROTO((void));
|
||||
extern void mdvi_flush_fontmaps __PROTO((void));
|
||||
|
||||
extern int mdvi_add_fontmap_file __PROTO((const char *, const char *));
|
||||
|
||||
/* PS font maps */
|
||||
extern int mdvi_ps_read_fontmap __PROTO((const char *));
|
||||
extern char *mdvi_ps_find_font __PROTO((const char *));
|
||||
extern TFMInfo *mdvi_ps_get_metrics __PROTO((const char *));
|
||||
extern void mdvi_ps_flush_fonts __PROTO((void));
|
||||
|
||||
#endif /* _MDVI_FONTMAP_H */
|
|
@ -0,0 +1,371 @@
|
|||
/* fontsearch.c -- implements the font lookup mechanism in MDVI */
|
||||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* How this works:
|
||||
* Fonts are divided into MAX_CLASS priority classes. The first
|
||||
* MAX_CLASS-1 ones correspond to `real' fonts (pk, gf, vf, type1, truetype,
|
||||
* etc). The last one corresponds to `metric' fonts that are used as a last
|
||||
* resort (tfm, afm, ofm, ...). When a font is looked up, it is tried in a
|
||||
* `high' priority class (0 being the highest priority). The priority is
|
||||
* lowered until it reaches MAX_CLASS-1. Then the whole thing is repeated
|
||||
* for the fallback font. When the search reaches MAX_CLASS-1, we lookup the
|
||||
* original font, and then the fallback font. The search can be done
|
||||
* incrementally, with several calls to mdvi_lookup_font(). If this function
|
||||
* is called again to continue a search, the function assumes the previous
|
||||
* font it returned was not valid, and it goes on to the next step.
|
||||
*
|
||||
* Reason for this:
|
||||
* Some font types are quite expensive to load (e.g. Type1), so loading
|
||||
* them is deferred until the last possible moment. This means that a font that
|
||||
* was supposed to exist may have to be discarded. Until now, MDVI had no ability to
|
||||
* "resume" a search, so in this case it would have produced an error, regardless
|
||||
* of whether the offending font existed in other formats.
|
||||
* Also, given the large number of font types supported by MDVI, some mechanism
|
||||
* was necessary to bring some order into the chaos.
|
||||
*
|
||||
* This mechanism fixes these two problems. For the first one, a search can
|
||||
* be "resumed" and all the font formats tried for the missing font, and
|
||||
* again for the fallback font (see above). As for the second, the
|
||||
* hierarchical division in classes gives a lot of flexibility in how the
|
||||
* fonts are configured.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "mdvi.h"
|
||||
|
||||
#define HAVE_PROTOTYPES 1
|
||||
#include <kpathsea/tex-file.h>
|
||||
#include <kpathsea/tex-glyph.h>
|
||||
|
||||
struct _DviFontClass {
|
||||
DviFontClass *next;
|
||||
DviFontClass *prev;
|
||||
DviFontInfo info;
|
||||
int links;
|
||||
int id;
|
||||
};
|
||||
|
||||
char *_mdvi_fallback_font = MDVI_FALLBACK_FONT;
|
||||
|
||||
/* this leaves classes 0 and 1 for `real' fonts */
|
||||
#define MAX_CLASS 3
|
||||
static ListHead font_classes[MAX_CLASS];
|
||||
static int initialized = 0;
|
||||
|
||||
static void init_font_classes(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAX_CLASS; i++)
|
||||
listh_init(&font_classes[i]);
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
int mdvi_get_font_classes(void)
|
||||
{
|
||||
return (MAX_CLASS - 2);
|
||||
}
|
||||
|
||||
char **mdvi_list_font_class(int klass)
|
||||
{
|
||||
char **list;
|
||||
int i, n;
|
||||
DviFontClass *fc;
|
||||
|
||||
if(klass == -1)
|
||||
klass = MAX_CLASS-1;
|
||||
if(klass < 0 || klass >= MAX_CLASS)
|
||||
return NULL;
|
||||
n = font_classes[klass].count;
|
||||
list = xnalloc(char *, n + 1);
|
||||
fc = (DviFontClass *)font_classes[klass].head;
|
||||
for(i = 0; i < n; fc = fc->next, i++) {
|
||||
list[i] = mdvi_strdup(fc->info.name);
|
||||
}
|
||||
list[i] = NULL;
|
||||
return list;
|
||||
}
|
||||
|
||||
int mdvi_register_font_type(DviFontInfo *info, int klass)
|
||||
{
|
||||
DviFontClass *fc;
|
||||
|
||||
if(klass == -1)
|
||||
klass = MAX_CLASS-1;
|
||||
if(klass < 0 || klass >= MAX_CLASS)
|
||||
return -1;
|
||||
if(!initialized)
|
||||
init_font_classes();
|
||||
fc = xalloc(struct _DviFontClass);
|
||||
fc->links = 0;
|
||||
fc->id = klass;
|
||||
fc->info.name = mdvi_strdup(info->name);
|
||||
fc->info.scalable = info->scalable;
|
||||
fc->info.load = info->load;
|
||||
fc->info.getglyph = info->getglyph;
|
||||
fc->info.shrink0 = info->shrink0;
|
||||
fc->info.shrink1 = info->shrink1;
|
||||
fc->info.freedata = info->freedata;
|
||||
fc->info.reset = info->reset;
|
||||
fc->info.lookup = info->lookup;
|
||||
fc->info.kpse_type = info->kpse_type;
|
||||
listh_append(&font_classes[klass], LIST(fc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdvi_unregister_font_type(const char *name, int klass)
|
||||
{
|
||||
DviFontClass *fc;
|
||||
int k;
|
||||
|
||||
if(klass == -1)
|
||||
klass = MAX_CLASS - 1;
|
||||
|
||||
if(klass >= 0 && klass < MAX_CLASS) {
|
||||
k = klass;
|
||||
LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
|
||||
if(STREQ(fc->info.name, name))
|
||||
break;
|
||||
}
|
||||
} else if(klass < 0) {
|
||||
for(k = 0; k < MAX_CLASS; k++) {
|
||||
LIST_FOREACH(fc, DviFontClass, &font_classes[k]) {
|
||||
if(STREQ(fc->info.name, name))
|
||||
break;
|
||||
}
|
||||
if(fc) break;
|
||||
}
|
||||
} else
|
||||
return -1;
|
||||
|
||||
if(fc == NULL || fc->links)
|
||||
return -1;
|
||||
/* remove it */
|
||||
listh_remove(&font_classes[k], LIST(fc));
|
||||
|
||||
/* and destroy it */
|
||||
mdvi_free(fc->info.name);
|
||||
mdvi_free(fc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *lookup_font(DviFontClass *ptr, const char *name, Ushort *h, Ushort *v)
|
||||
{
|
||||
char *filename;
|
||||
|
||||
/*
|
||||
* If the font type registered a function to do the lookup, use that.
|
||||
* Otherwise we use kpathsea.
|
||||
*/
|
||||
if(ptr->info.lookup)
|
||||
filename = ptr->info.lookup(name, h, v);
|
||||
else if(ptr->info.kpse_type <= kpse_any_glyph_format) {
|
||||
kpse_glyph_file_type type;
|
||||
|
||||
filename = kpse_find_glyph(name, Max(*h, *v),
|
||||
ptr->info.kpse_type, &type);
|
||||
/* if kpathsea returned a fallback font, reject it */
|
||||
if(filename && type.source == kpse_glyph_source_fallback) {
|
||||
mdvi_free(filename);
|
||||
filename = NULL;
|
||||
} else if(filename)
|
||||
*h = *v = type.dpi;
|
||||
} else
|
||||
filename = kpse_find_file(name, ptr->info.kpse_type, 1);
|
||||
return filename;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class MAX_CLASS-1 is special: it consists of `metric' fonts that should
|
||||
* be tried as a last resort
|
||||
*/
|
||||
char *mdvi_lookup_font(DviFontSearch *search)
|
||||
{
|
||||
int kid;
|
||||
int k;
|
||||
DviFontClass *ptr;
|
||||
DviFontClass *last;
|
||||
char *filename = NULL;
|
||||
const char *name;
|
||||
Ushort hdpi, vdpi;
|
||||
|
||||
if(search->id < 0)
|
||||
return NULL;
|
||||
|
||||
if(search->curr == NULL) {
|
||||
/* this is the initial search */
|
||||
name = search->wanted_name;
|
||||
hdpi = search->hdpi;
|
||||
vdpi = search->vdpi;
|
||||
kid = 0;
|
||||
last = NULL;
|
||||
} else {
|
||||
name = search->actual_name;
|
||||
hdpi = search->actual_hdpi;
|
||||
vdpi = search->actual_vdpi;
|
||||
kid = search->id;
|
||||
last = search->curr;
|
||||
}
|
||||
|
||||
ptr = NULL;
|
||||
again:
|
||||
/* try all classes except MAX_CLASS-1 */
|
||||
for(k = kid; !filename && k < MAX_CLASS-1; k++) {
|
||||
if(last == NULL)
|
||||
ptr = (DviFontClass *)font_classes[k].head;
|
||||
else
|
||||
ptr = last->next;
|
||||
while(ptr) {
|
||||
DEBUG((DBG_FONTS, "%d: trying `%s' at (%d,%d)dpi as `%s'\n",
|
||||
k, name, hdpi, vdpi, ptr->info.name));
|
||||
/* lookup the font in this class */
|
||||
filename = lookup_font(ptr, name, &hdpi, &vdpi);
|
||||
if(filename)
|
||||
break;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
last = NULL;
|
||||
}
|
||||
if(filename != NULL) {
|
||||
search->id = k-1;
|
||||
search->curr = ptr;
|
||||
search->actual_name = name;
|
||||
search->actual_hdpi = hdpi;
|
||||
search->actual_vdpi = vdpi;
|
||||
search->info = &ptr->info;
|
||||
ptr->links++;
|
||||
return filename;
|
||||
}
|
||||
|
||||
if(kid < MAX_CLASS - 1 && !STREQ(name, _mdvi_fallback_font)) {
|
||||
mdvi_warning("font `%s' at %dx%d not found, trying `%s' instead\n",
|
||||
name, hdpi, vdpi, _mdvi_fallback_font);
|
||||
name = _mdvi_fallback_font;
|
||||
kid = 0;
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* we tried the fallback font, and all the `real' classes. Let's
|
||||
* try the `metric' class now */
|
||||
name = search->wanted_name;
|
||||
hdpi = search->hdpi;
|
||||
vdpi = search->vdpi;
|
||||
if(kid == MAX_CLASS-1) {
|
||||
/* we were looking into this class from the beginning */
|
||||
if(last == NULL) {
|
||||
/* no more fonts to try */
|
||||
return NULL;
|
||||
}
|
||||
ptr = last->next;
|
||||
} else {
|
||||
mdvi_warning("font `%s' not found, trying metric files instead\n",
|
||||
name);
|
||||
ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
|
||||
}
|
||||
|
||||
metrics:
|
||||
while(ptr) {
|
||||
DEBUG((DBG_FONTS, "metric: trying `%s' at (%d,%d)dpi as `%s'\n",
|
||||
name, hdpi, vdpi, ptr->info.name));
|
||||
filename = lookup_font(ptr, name, &hdpi, &vdpi);
|
||||
if(filename)
|
||||
break;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
if(filename != NULL) {
|
||||
if(STREQ(name, _mdvi_fallback_font))
|
||||
search->id = MAX_CLASS;
|
||||
else
|
||||
search->id = MAX_CLASS - 1;
|
||||
search->curr = ptr;
|
||||
search->actual_name = name;
|
||||
search->actual_hdpi = hdpi;
|
||||
search->actual_vdpi = vdpi;
|
||||
search->info = &ptr->info;
|
||||
ptr->links++;
|
||||
return filename;
|
||||
}
|
||||
if(!STREQ(name, _mdvi_fallback_font)) {
|
||||
mdvi_warning("metric file for `%s' not found, trying `%s' instead\n",
|
||||
name, _mdvi_fallback_font);
|
||||
name = _mdvi_fallback_font;
|
||||
ptr = (DviFontClass *)font_classes[MAX_CLASS-1].head;
|
||||
goto metrics;
|
||||
}
|
||||
|
||||
search->id = -1;
|
||||
search->actual_name = NULL;
|
||||
|
||||
/* tough luck, nothing found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* called by `font_reference' to do the initial lookup */
|
||||
DviFont *mdvi_add_font(const char *name, Int32 sum,
|
||||
int hdpi, int vdpi, Int32 scale)
|
||||
{
|
||||
DviFont *font;
|
||||
|
||||
font = xalloc(DviFont);
|
||||
font->fontname = mdvi_strdup(name);
|
||||
SEARCH_INIT(font->search, font->fontname, hdpi, vdpi);
|
||||
font->filename = mdvi_lookup_font(&font->search);
|
||||
if(font->filename == NULL) {
|
||||
/* this answer is final */
|
||||
mdvi_free(font->fontname);
|
||||
mdvi_free(font);
|
||||
return NULL;
|
||||
}
|
||||
font->hdpi = font->search.actual_hdpi;
|
||||
font->vdpi = font->search.actual_vdpi;
|
||||
font->scale = scale;
|
||||
font->design = 0;
|
||||
font->checksum = sum;
|
||||
font->type = 0;
|
||||
font->links = 0;
|
||||
font->loc = 0;
|
||||
font->hic = 0;
|
||||
font->in = NULL;
|
||||
font->chars = NULL;
|
||||
font->subfonts = NULL;
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
int mdvi_font_retry(DviParams *params, DviFont *font)
|
||||
{
|
||||
/* try the search again */
|
||||
char *filename;
|
||||
|
||||
ASSERT(font->search.curr != NULL);
|
||||
/* we won't be using this class anymore */
|
||||
font->search.curr->links--;
|
||||
|
||||
filename = mdvi_lookup_font(&font->search);
|
||||
if(filename == NULL)
|
||||
return -1;
|
||||
mdvi_free(font->filename);
|
||||
font->filename = filename;
|
||||
/* copy the new information */
|
||||
font->hdpi = font->search.actual_hdpi;
|
||||
font->vdpi = font->search.actual_vdpi;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,395 @@
|
|||
/* gf.c - GF font support */
|
||||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* functions to read GF fonts */
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
/* opcodes */
|
||||
|
||||
#define GF_PAINT0 0
|
||||
#define GF_PAINT1 64
|
||||
#define GF_PAINT2 65
|
||||
#define GF_PAINT3 66
|
||||
#define GF_BOC 67
|
||||
#define GF_BOC1 68
|
||||
#define GF_EOC 69
|
||||
#define GF_SKIP0 70
|
||||
#define GF_SKIP1 71
|
||||
#define GF_SKIP2 72
|
||||
#define GF_SKIP3 73
|
||||
#define GF_NEW_ROW_0 74
|
||||
#define GF_NEW_ROW_1 75
|
||||
#define GF_NEW_ROW_MAX 238
|
||||
#define GF_XXX1 239
|
||||
#define GF_XXX2 240
|
||||
#define GF_XXX3 241
|
||||
#define GF_XXX4 242
|
||||
#define GF_YYY 243
|
||||
#define GF_NOOP 244
|
||||
#define GF_LOC 245
|
||||
#define GF_LOC0 246
|
||||
#define GF_PRE 247
|
||||
#define GF_POST 248
|
||||
#define GF_POST_POST 249
|
||||
|
||||
#define GF_ID 131
|
||||
#define GF_TRAILER 223
|
||||
|
||||
#define BLACK 1
|
||||
#define WHITE 0
|
||||
|
||||
static int gf_load_font __PROTO((DviParams *, DviFont *));
|
||||
static int gf_font_get_glyph __PROTO((DviParams *, DviFont *, int));
|
||||
|
||||
/* only symbol exported by this file */
|
||||
DviFontInfo gf_font_info = {
|
||||
"GF",
|
||||
0, /* scaling not supported natively */
|
||||
gf_load_font,
|
||||
gf_font_get_glyph,
|
||||
mdvi_shrink_glyph,
|
||||
mdvi_shrink_glyph_grey,
|
||||
NULL, /* free */
|
||||
NULL, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_gf_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int gf_read_bitmap(FILE *p, DviFontChar *ch)
|
||||
{
|
||||
int op;
|
||||
int min_n, max_n;
|
||||
int min_m, max_m;
|
||||
int paint_switch;
|
||||
int x, y;
|
||||
int bpl;
|
||||
Int32 par;
|
||||
BmUnit *line;
|
||||
BITMAP *map;
|
||||
|
||||
fseek(p, (long)ch->offset, SEEK_SET);
|
||||
op = fuget1(p);
|
||||
if(op == GF_BOC) {
|
||||
/* skip character code */
|
||||
fuget4(p);
|
||||
/* skip pointer */
|
||||
fuget4(p);
|
||||
min_m = fsget4(p);
|
||||
max_m = fsget4(p);
|
||||
min_n = fsget4(p);
|
||||
max_n = fsget4(p);
|
||||
} else if(op == GF_BOC1) {
|
||||
/* skip character code */
|
||||
fuget1(p);
|
||||
min_m = fuget1(p); /* this is max_m - min_m */
|
||||
max_m = fuget1(p);
|
||||
min_n = fuget1(p); /* this is max_n - min_n */
|
||||
max_n = fuget1(p);
|
||||
min_m = max_m - min_m;
|
||||
min_n = max_n - min_n;
|
||||
} else {
|
||||
mdvi_error(_("GF: invalid opcode %d in character %d\n"),
|
||||
op, ch->code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ch->x = -min_m;
|
||||
ch->y = max_n;
|
||||
ch->width = max_m - min_m + 1;
|
||||
ch->height = max_n - min_n + 1;
|
||||
map = bitmap_alloc(ch->width, ch->height);
|
||||
|
||||
ch->glyph.data = map;
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
|
||||
#define COLOR(x) ((x) ? "BLACK" : "WHITE")
|
||||
|
||||
paint_switch = WHITE;
|
||||
x = y = 0;
|
||||
line = map->data;
|
||||
bpl = map->stride;
|
||||
DEBUG((DBG_BITMAPS, "(gf) reading character %d\n", ch->code));
|
||||
while((op = fuget1(p)) != GF_EOC) {
|
||||
Int32 n;
|
||||
|
||||
if(feof(p))
|
||||
break;
|
||||
if(op == GF_PAINT0) {
|
||||
DEBUG((DBG_BITMAPS, "(gf) Paint0 %s -> %s\n",
|
||||
COLOR(paint_switch), COLOR(!paint_switch)));
|
||||
paint_switch = !paint_switch;
|
||||
} else if(op <= GF_PAINT3) {
|
||||
if(op < GF_PAINT1)
|
||||
par = op;
|
||||
else
|
||||
par = fugetn(p, op - GF_PAINT1 + 1);
|
||||
if(y >= ch->height || x + par >= ch->width)
|
||||
goto toobig;
|
||||
/* paint everything between columns x and x + par - 1 */
|
||||
DEBUG((DBG_BITMAPS, "(gf) Paint %d %s from (%d,%d)\n",
|
||||
par, COLOR(paint_switch), x, y));
|
||||
if(paint_switch == BLACK)
|
||||
bitmap_paint_bits(line + (x / BITMAP_BITS),
|
||||
x % BITMAP_BITS, par);
|
||||
paint_switch = !paint_switch;
|
||||
x += par;
|
||||
} else if(op >= GF_NEW_ROW_0 && op <= GF_NEW_ROW_MAX) {
|
||||
y++;
|
||||
line = bm_offset(line, bpl);
|
||||
x = op - GF_NEW_ROW_0;
|
||||
paint_switch = BLACK;
|
||||
DEBUG((DBG_BITMAPS, "(gf) new_row_%d\n", x));
|
||||
} else switch(op) {
|
||||
case GF_SKIP0:
|
||||
y++;
|
||||
line = bm_offset(line, bpl);
|
||||
x = 0;
|
||||
paint_switch = WHITE;
|
||||
DEBUG((DBG_BITMAPS, "(gf) skip_0\n"));
|
||||
break;
|
||||
case GF_SKIP1:
|
||||
case GF_SKIP2:
|
||||
case GF_SKIP3:
|
||||
par = fugetn(p, op - GF_SKIP1 + 1);
|
||||
y += par + 1;
|
||||
line = bm_offset(line, (par + 1) * bpl);
|
||||
x = 0;
|
||||
paint_switch = WHITE;
|
||||
DEBUG((DBG_BITMAPS, "(gf) skip_%d\n", op - GF_SKIP1));
|
||||
break;
|
||||
case GF_XXX1:
|
||||
case GF_XXX2:
|
||||
case GF_XXX3:
|
||||
case GF_XXX4: {
|
||||
#ifndef NODEBUG
|
||||
char *s;
|
||||
|
||||
s = read_string(p, op - GF_XXX1 + 1, NULL, 0);
|
||||
DEBUG((DBG_SPECIAL, "(gf) Character %d: Special \"%s\"\n",
|
||||
ch->code, s));
|
||||
mdvi_free(s);
|
||||
#else
|
||||
n = fugetn(p, op - GF_XXX1 + 1);
|
||||
fseek(p, (long)n, SEEK_CUR);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case GF_YYY:
|
||||
n = fuget4(p);
|
||||
DEBUG((DBG_SPECIAL, "(gf) Character %d: MF special %u\n",
|
||||
ch->code, n));
|
||||
break;
|
||||
case GF_NOOP:
|
||||
DEBUG((DBG_BITMAPS, "(gf) no_op\n"));
|
||||
break;
|
||||
default:
|
||||
mdvi_error(_("(gf) Character %d: invalid opcode %d\n"),
|
||||
ch->code, op);
|
||||
goto error;
|
||||
}
|
||||
/* chech that we're still inside the bitmap */
|
||||
if(x > ch->width || y > ch->height)
|
||||
goto toobig;
|
||||
DEBUG((DBG_BITMAPS, "(gf) curr_loc @ (%d,%d)\n", x, y));
|
||||
}
|
||||
|
||||
if(op != GF_EOC)
|
||||
goto error;
|
||||
DEBUG((DBG_BITMAPS, "(gf) end of character %d\n", ch->code));
|
||||
return 0;
|
||||
|
||||
toobig:
|
||||
mdvi_error(_("(gf) character %d has an incorrect bounding box\n"),
|
||||
ch->code);
|
||||
error:
|
||||
bitmap_destroy(map);
|
||||
ch->glyph.data = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gf_load_font(DviParams *unused, DviFont *font)
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
int loc;
|
||||
int hic;
|
||||
FILE *p;
|
||||
Int32 word;
|
||||
int op;
|
||||
long alpha, beta, z;
|
||||
#ifndef NODEBUG
|
||||
char s[256];
|
||||
#endif
|
||||
|
||||
p = font->in;
|
||||
|
||||
/* check preamble */
|
||||
loc = fuget1(p); hic = fuget1(p);
|
||||
if(loc != GF_PRE || hic != GF_ID)
|
||||
goto badgf;
|
||||
loc = fuget1(p);
|
||||
#ifndef NODEBUG
|
||||
for(i = 0; i < loc; i++)
|
||||
s[i] = fuget1(p);
|
||||
s[i] = 0;
|
||||
DEBUG((DBG_FONTS, "(gf) %s: %s\n", font->fontname, s));
|
||||
#else
|
||||
fseek(p, (long)loc, SEEK_CUR);
|
||||
#endif
|
||||
/* now read character locators in postamble */
|
||||
if(fseek(p, (long)-1, SEEK_END) == -1)
|
||||
return -1;
|
||||
|
||||
n = 0;
|
||||
while((op = fuget1(p)) == GF_TRAILER) {
|
||||
if(fseek(p, (long)-2, SEEK_CUR) < 0)
|
||||
break;
|
||||
n++;
|
||||
}
|
||||
if(op != GF_ID || n < 4)
|
||||
goto badgf;
|
||||
/* get the pointer to the postamble */
|
||||
fseek(p, (long)-5, SEEK_CUR);
|
||||
op = fuget4(p);
|
||||
/* jump to it */
|
||||
fseek(p, (long)op, SEEK_SET);
|
||||
if(fuget1(p) != GF_POST)
|
||||
goto badgf;
|
||||
/* skip pointer to last EOC */
|
||||
fuget4(p);
|
||||
/* get the design size */
|
||||
font->design = fuget4(p);
|
||||
/* the checksum */
|
||||
word = fuget4(p);
|
||||
if(word && font->checksum && font->checksum != word) {
|
||||
mdvi_warning(_("%s: bad checksum (expected %u, found %u)\n"),
|
||||
font->fontname, font->checksum, word);
|
||||
} else if(!font->checksum)
|
||||
font->checksum = word;
|
||||
/* skip pixels per point ratio */
|
||||
fuget4(p);
|
||||
fuget4(p);
|
||||
font->chars = xnalloc(DviFontChar, 256);
|
||||
for(loc = 0; loc < 256; loc++)
|
||||
font->chars[loc].offset = 0;
|
||||
/* skip glyph "bounding box" */
|
||||
fseek(p, (long)16, SEEK_CUR);
|
||||
loc = 256;
|
||||
hic = -1;
|
||||
TFMPREPARE(font->scale, z, alpha, beta);
|
||||
while((op = fuget1(p)) != GF_POST_POST) {
|
||||
DviFontChar *ch;
|
||||
int cc;
|
||||
|
||||
/* get the character code */
|
||||
cc = fuget1(p);
|
||||
if(cc < loc)
|
||||
loc = cc;
|
||||
if(cc > hic)
|
||||
hic = cc;
|
||||
ch = &font->chars[cc];
|
||||
switch(op) {
|
||||
case GF_LOC:
|
||||
fsget4(p); /* skip dx */
|
||||
fsget4(p); /* skip dy */
|
||||
break;
|
||||
case GF_LOC0:
|
||||
fuget1(p); /* skip dx */
|
||||
/* dy assumed 0 */
|
||||
break;
|
||||
default:
|
||||
mdvi_error(_("%s: junk in postamble\n"), font->fontname);
|
||||
goto error;
|
||||
}
|
||||
ch->code = cc;
|
||||
ch->tfmwidth = fuget4(p);
|
||||
ch->tfmwidth = TFMSCALE(ch->tfmwidth, z, alpha, beta);
|
||||
ch->offset = fuget4(p);
|
||||
if(ch->offset == -1)
|
||||
ch->offset = 0;
|
||||
/* initialize the rest of the glyph information */
|
||||
ch->x = 0;
|
||||
ch->y = 0;
|
||||
ch->width = 0;
|
||||
ch->height = 0;
|
||||
ch->glyph.data = NULL;
|
||||
ch->shrunk.data = NULL;
|
||||
ch->grey.data = NULL;
|
||||
ch->flags = 0;
|
||||
ch->loaded = 0;
|
||||
}
|
||||
|
||||
if(op != GF_POST_POST)
|
||||
goto badgf;
|
||||
|
||||
if(loc > 0 || hic < 255) {
|
||||
/* shrink to optimal size */
|
||||
memmove(font->chars, font->chars + loc,
|
||||
(hic - loc + 1) * sizeof(DviFontChar));
|
||||
font->chars = xresize(font->chars,
|
||||
DviFontChar, hic - loc + 1);
|
||||
}
|
||||
font->loc = loc;
|
||||
font->hic = hic;
|
||||
|
||||
return 0;
|
||||
|
||||
badgf:
|
||||
mdvi_error(_("%s: File corrupted, or not a GF file\n"), font->fontname);
|
||||
error:
|
||||
if(font->chars) {
|
||||
mdvi_free(font->chars);
|
||||
font->chars = NULL;
|
||||
}
|
||||
font->loc = font->hic = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gf_font_get_glyph(DviParams *params, DviFont *font, int code)
|
||||
{
|
||||
DviFontChar *ch;
|
||||
|
||||
if(code < font->loc || code > font->hic || !font->chars)
|
||||
return -1;
|
||||
ch = &font->chars[code - font->loc];
|
||||
|
||||
if(!ch->loaded) {
|
||||
if(ch->offset == 0)
|
||||
return -1;
|
||||
DEBUG((DBG_GLYPHS, "(gf) %s: loading GF glyph for character %d\n",
|
||||
font->fontname, code));
|
||||
if(font->in == NULL && font_reopen(font) < 0)
|
||||
return -1;
|
||||
if(fseek(font->in, ch->offset, SEEK_SET) == -1)
|
||||
return -1;
|
||||
if(gf_read_bitmap(font->in, ch) < 0)
|
||||
return -1;
|
||||
ch->loaded = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "mdvi.h"
|
||||
|
||||
/* simple hash tables for MDVI */
|
||||
|
||||
|
||||
struct _DviHashBucket {
|
||||
DviHashBucket *next;
|
||||
DviHashKey key;
|
||||
Ulong hvalue;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static Ulong hash_string(DviHashKey key)
|
||||
{
|
||||
Uchar *p;
|
||||
Ulong h, g;
|
||||
|
||||
for(h = 0, p = (Uchar *)key; *p; p++) {
|
||||
h = (h << 4UL) + *p;
|
||||
if((g = h & 0xf0000000L) != 0) {
|
||||
h ^= (g >> 24UL);
|
||||
h ^= g;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static int hash_compare(DviHashKey k1, DviHashKey k2)
|
||||
{
|
||||
return strcmp((char *)k1, (char *)k2);
|
||||
}
|
||||
|
||||
void mdvi_hash_init(DviHashTable *hash)
|
||||
{
|
||||
hash->buckets = NULL;
|
||||
hash->nbucks = 0;
|
||||
hash->nkeys = 0;
|
||||
hash->hash_func = NULL;
|
||||
hash->hash_comp = NULL;
|
||||
hash->hash_free = NULL;
|
||||
}
|
||||
|
||||
void mdvi_hash_create(DviHashTable *hash, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
hash->nbucks = size;
|
||||
hash->buckets = xnalloc(DviHashBucket *, size);
|
||||
for(i = 0; i < size; i++)
|
||||
hash->buckets[i] = NULL;
|
||||
hash->hash_func = hash_string;
|
||||
hash->hash_comp = hash_compare;
|
||||
hash->hash_free = NULL;
|
||||
hash->nkeys = 0;
|
||||
}
|
||||
|
||||
static DviHashBucket *hash_find(DviHashTable *hash, DviHashKey key)
|
||||
{
|
||||
Ulong hval;
|
||||
DviHashBucket *buck;
|
||||
|
||||
hval = (hash->hash_func(key) % hash->nbucks);
|
||||
|
||||
for(buck = hash->buckets[hval]; buck; buck = buck->next)
|
||||
if(hash->hash_comp(buck->key, key) == 0)
|
||||
break;
|
||||
return buck;
|
||||
}
|
||||
|
||||
/* Neither keys nor data are duplicated */
|
||||
int mdvi_hash_add(DviHashTable *hash, DviHashKey key, void *data, int rep)
|
||||
{
|
||||
DviHashBucket *buck = NULL;
|
||||
Ulong hval;
|
||||
|
||||
if(rep != MDVI_HASH_UNCHECKED) {
|
||||
buck = hash_find(hash, key);
|
||||
if(buck != NULL) {
|
||||
if(buck->data == data)
|
||||
return 0;
|
||||
if(rep == MDVI_HASH_UNIQUE)
|
||||
return -1;
|
||||
if(hash->hash_free != NULL)
|
||||
hash->hash_free(buck->key, buck->data);
|
||||
}
|
||||
}
|
||||
if(buck == NULL) {
|
||||
buck = xalloc(DviHashBucket);
|
||||
buck->hvalue = hash->hash_func(key);
|
||||
hval = (buck->hvalue % hash->nbucks);
|
||||
buck->next = hash->buckets[hval];
|
||||
hash->buckets[hval] = buck;
|
||||
hash->nkeys++;
|
||||
}
|
||||
|
||||
/* save key and data */
|
||||
buck->key = key;
|
||||
buck->data = data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *mdvi_hash_lookup(DviHashTable *hash, DviHashKey key)
|
||||
{
|
||||
DviHashBucket *buck = hash_find(hash, key);
|
||||
|
||||
return buck ? buck->data : NULL;
|
||||
}
|
||||
|
||||
static DviHashBucket *hash_remove(DviHashTable *hash, DviHashKey key)
|
||||
{
|
||||
DviHashBucket *buck, *last;
|
||||
Ulong hval;
|
||||
|
||||
hval = hash->hash_func(key);
|
||||
hval %= hash->nbucks;
|
||||
|
||||
for(last = NULL, buck = hash->buckets[hval]; buck; buck = buck->next) {
|
||||
if(hash->hash_comp(buck->key, key) == 0)
|
||||
break;
|
||||
last = buck;
|
||||
}
|
||||
if(buck == NULL)
|
||||
return NULL;
|
||||
if(last)
|
||||
last->next = buck->next;
|
||||
else
|
||||
hash->buckets[hval] = buck->next;
|
||||
hash->nkeys--;
|
||||
return buck;
|
||||
}
|
||||
|
||||
void *mdvi_hash_remove(DviHashTable *hash, DviHashKey key)
|
||||
{
|
||||
DviHashBucket *buck = hash_remove(hash, key);
|
||||
void *data = NULL;
|
||||
|
||||
if(buck) {
|
||||
data = buck->data;
|
||||
mdvi_free(buck);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
void *mdvi_hash_remove_ptr(DviHashTable *hash, DviHashKey key)
|
||||
{
|
||||
DviHashBucket *buck, *last;
|
||||
Ulong hval;
|
||||
void *ptr;
|
||||
|
||||
hval = hash->hash_func(key);
|
||||
hval %= hash->nbucks;
|
||||
|
||||
for(last = NULL, buck = hash->buckets[hval]; buck; buck = buck->next) {
|
||||
if(buck->key == key)
|
||||
break;
|
||||
last = buck;
|
||||
}
|
||||
if(buck == NULL)
|
||||
return NULL;
|
||||
if(last)
|
||||
last->next = buck->next;
|
||||
else
|
||||
hash->buckets[hval] = buck->next;
|
||||
hash->nkeys--;
|
||||
/* destroy the bucket */
|
||||
ptr = buck->data;
|
||||
mdvi_free(buck);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int mdvi_hash_destroy_key(DviHashTable *hash, DviHashKey key)
|
||||
{
|
||||
DviHashBucket *buck = hash_remove(hash, key);
|
||||
|
||||
if(buck == NULL)
|
||||
return -1;
|
||||
if(hash->hash_free)
|
||||
hash->hash_free(buck->key, buck->data);
|
||||
mdvi_free(buck);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdvi_hash_reset(DviHashTable *hash, int reuse)
|
||||
{
|
||||
int i;
|
||||
DviHashBucket *buck;
|
||||
|
||||
/* remove all keys in the hash table */
|
||||
for(i = 0; i < hash->nbucks; i++) {
|
||||
for(; (buck = hash->buckets[i]); ) {
|
||||
hash->buckets[i] = buck->next;
|
||||
if(hash->hash_free)
|
||||
hash->hash_free(buck->key, buck->data);
|
||||
mdvi_free(buck);
|
||||
}
|
||||
}
|
||||
hash->nkeys = 0;
|
||||
if(!reuse && hash->buckets) {
|
||||
mdvi_free(hash->buckets);
|
||||
hash->buckets = NULL;
|
||||
hash->nbucks = 0;
|
||||
} /* otherwise, it is left empty, ready to be reused */
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef MDVI_HASH
|
||||
#define MDVI_HASH
|
||||
|
||||
/* Hash tables */
|
||||
|
||||
|
||||
typedef struct _DviHashBucket DviHashBucket;
|
||||
typedef struct _DviHashTable DviHashTable;
|
||||
|
||||
/*
|
||||
* Hash tables
|
||||
*/
|
||||
|
||||
typedef Uchar *DviHashKey;
|
||||
#define MDVI_KEY(x) ((DviHashKey)(x))
|
||||
|
||||
typedef Ulong (*DviHashFunc) __PROTO((DviHashKey key));
|
||||
typedef int (*DviHashComp) __PROTO((DviHashKey key1, DviHashKey key2));
|
||||
typedef void (*DviHashFree) __PROTO((DviHashKey key, void *data));
|
||||
|
||||
|
||||
struct _DviHashTable {
|
||||
DviHashBucket **buckets;
|
||||
int nbucks;
|
||||
int nkeys;
|
||||
DviHashFunc hash_func;
|
||||
DviHashComp hash_comp;
|
||||
DviHashFree hash_free;
|
||||
};
|
||||
#define MDVI_EMPTY_HASH_TABLE {NULL, 0, 0, NULL, NULL, NULL}
|
||||
|
||||
#define MDVI_HASH_REPLACE 0
|
||||
#define MDVI_HASH_UNIQUE 1
|
||||
#define MDVI_HASH_UNCHECKED 2
|
||||
|
||||
extern void mdvi_hash_init __PROTO((DviHashTable *));
|
||||
extern void mdvi_hash_create __PROTO((DviHashTable *, int));
|
||||
extern int mdvi_hash_add __PROTO((DviHashTable *, DviHashKey, void *, int));
|
||||
extern int mdvi_hash_destroy_key __PROTO((DviHashTable *, DviHashKey));
|
||||
extern void mdvi_hash_reset __PROTO((DviHashTable *, int));
|
||||
extern void *mdvi_hash_lookup __PROTO((DviHashTable *, DviHashKey));
|
||||
extern void *mdvi_hash_remove __PROTO((DviHashTable *, DviHashKey));
|
||||
extern void *mdvi_hash_remove_ptr __PROTO((DviHashTable *, DviHashKey));
|
||||
|
||||
#define mdvi_hash_flush(h) mdvi_hash_reset((h), 1)
|
||||
#define mdvi_hash_destroy(h) mdvi_hash_reset((h), 0)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "common.h"
|
||||
|
||||
void listh_init(ListHead *head)
|
||||
{
|
||||
head->head = head->tail = NULL;
|
||||
head->count = 0;
|
||||
}
|
||||
|
||||
void listh_prepend(ListHead *head, List *list)
|
||||
{
|
||||
list->prev = NULL;
|
||||
list->next = head->head;
|
||||
if(head->head)
|
||||
head->head->prev = list;
|
||||
head->head = list;
|
||||
if(!head->tail)
|
||||
head->tail = list;
|
||||
head->count++;
|
||||
}
|
||||
|
||||
void listh_append(ListHead *head, List *list)
|
||||
{
|
||||
list->next = NULL;
|
||||
list->prev = head->tail;
|
||||
if(head->tail)
|
||||
head->tail->next = list;
|
||||
else
|
||||
head->head = list;
|
||||
head->tail = list;
|
||||
head->count++;
|
||||
}
|
||||
|
||||
void listh_add_before(ListHead *head, List *at, List *list)
|
||||
{
|
||||
if(at == head->head || head->head == NULL)
|
||||
listh_prepend(head, list);
|
||||
else {
|
||||
list->next = at;
|
||||
list->prev = at->prev;
|
||||
at->prev = list;
|
||||
head->count++;
|
||||
}
|
||||
}
|
||||
|
||||
void listh_add_after(ListHead *head, List *at, List *list)
|
||||
{
|
||||
if(at == head->tail || !head->tail)
|
||||
listh_append(head, list);
|
||||
else {
|
||||
list->prev = at;
|
||||
list->next = at->next;
|
||||
at->next = list;
|
||||
head->count++;
|
||||
}
|
||||
}
|
||||
|
||||
void listh_remove(ListHead *head, List *list)
|
||||
{
|
||||
if(list == head->head) {
|
||||
head->head = list->next;
|
||||
if(head->head)
|
||||
head->head->prev = NULL;
|
||||
} else if(list == head->tail) {
|
||||
head->tail = list->prev;
|
||||
if(head->tail)
|
||||
head->tail->next = NULL;
|
||||
} else {
|
||||
list->next->prev = list->prev;
|
||||
list->prev->next = list->next;
|
||||
}
|
||||
if(--head->count == 0)
|
||||
head->head = head->tail = NULL;
|
||||
}
|
||||
|
||||
void listh_concat(ListHead *h1, ListHead *h2)
|
||||
{
|
||||
if(h2->head == NULL)
|
||||
; /* do nothing */
|
||||
else if(h1->tail == NULL)
|
||||
h1->head = h2->head;
|
||||
else {
|
||||
h1->tail->next = h2->head;
|
||||
h2->head->prev = h1->tail;
|
||||
}
|
||||
h1->tail = h2->tail;
|
||||
h1->count += h2->count;
|
||||
}
|
||||
|
||||
void listh_catcon(ListHead *h1, ListHead *h2)
|
||||
{
|
||||
if(h2->head == NULL)
|
||||
; /* do nothing */
|
||||
else if(h1->head == NULL)
|
||||
h1->tail = h2->tail;
|
||||
else {
|
||||
h1->head->prev = h2->tail;
|
||||
h2->tail->next = h1->head;
|
||||
}
|
||||
h1->head = h2->head;
|
||||
h1->count += h2->count;
|
||||
}
|
|
@ -0,0 +1,625 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _MDVI_DVI_H
|
||||
#define _MDVI_DVI_H 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
#include "bitmap.h"
|
||||
#include "common.h"
|
||||
#include "defaults.h"
|
||||
#include "dviopcodes.h"
|
||||
|
||||
typedef struct _DviGlyph DviGlyph;
|
||||
typedef struct _DviDevice DviDevice;
|
||||
typedef struct _DviFontChar DviFontChar;
|
||||
typedef struct _DviFontRef DviFontRef;
|
||||
typedef struct _DviFontInfo DviFontInfo;
|
||||
typedef struct _DviFont DviFont;
|
||||
typedef struct _DviState DviState;
|
||||
typedef struct _DviPageSpec *DviPageSpec;
|
||||
typedef struct _DviParams DviParams;
|
||||
typedef struct _DviBuffer DviBuffer;
|
||||
typedef struct _DviContext DviContext;
|
||||
typedef struct _DviRange DviRange;
|
||||
typedef struct _DviColorPair DviColorPair;
|
||||
typedef struct _DviSection DviSection;
|
||||
typedef struct _TFMChar TFMChar;
|
||||
typedef struct _TFMInfo TFMInfo;
|
||||
typedef struct _DviFontSearch DviFontSearch;
|
||||
/* this is an opaque type */
|
||||
typedef struct _DviFontClass DviFontClass;
|
||||
|
||||
typedef void (*DviFreeFunc) __PROTO((void *));
|
||||
typedef void (*DviFree2Func) __PROTO((void *, void *));
|
||||
|
||||
typedef Ulong DviColor;
|
||||
|
||||
#ifdef TRUE
|
||||
#undef TRUE
|
||||
#endif
|
||||
#ifdef FALSE
|
||||
#undef FALSE
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
FALSE = 0,
|
||||
TRUE = 1
|
||||
} DviBool;
|
||||
|
||||
#include "hash.h"
|
||||
#include "paper.h"
|
||||
|
||||
/*
|
||||
* information about a page:
|
||||
* pagenum[0] = offset to BOP
|
||||
* pagenum[1], ..., pagenum[10] = TeX \counters
|
||||
*/
|
||||
typedef long PageNum[11];
|
||||
|
||||
/* this structure contains the platform-specific information
|
||||
* required to interpret a DVI file */
|
||||
|
||||
typedef void (*DviGlyphDraw) __PROTO((DviContext *context,
|
||||
DviFontChar *glyph,
|
||||
int x, int y));
|
||||
|
||||
typedef void (*DviRuleDraw) __PROTO((DviContext *context,
|
||||
int x, int y,
|
||||
Uint width, Uint height, int fill));
|
||||
|
||||
typedef int (*DviColorScale) __PROTO((void *device_data,
|
||||
Ulong *pixels,
|
||||
int npixels,
|
||||
Ulong foreground,
|
||||
Ulong background,
|
||||
double gamma,
|
||||
int density));
|
||||
typedef void *(*DviCreateImage) __PROTO((void *device_data,
|
||||
Uint width,
|
||||
Uint height,
|
||||
Uint bpp));
|
||||
typedef void (*DviFreeImage) __PROTO((void *image));
|
||||
typedef void (*DviPutPixel) __PROTO((void *image, int x, int y, Ulong color));
|
||||
typedef void (*DviImageDone) __PROTO((void *image));
|
||||
typedef void (*DviDevDestroy) __PROTO((void *data));
|
||||
typedef void (*DviRefresh) __PROTO((DviContext *dvi, void *device_data));
|
||||
typedef void (*DviSetColor) __PROTO((void *device_data, Ulong, Ulong));
|
||||
typedef void (*DviPSDraw) __PROTO((DviContext *context,
|
||||
const char *filename,
|
||||
int x, int y,
|
||||
Uint width, Uint height));
|
||||
|
||||
struct _DviDevice {
|
||||
DviGlyphDraw draw_glyph;
|
||||
DviRuleDraw draw_rule;
|
||||
DviColorScale alloc_colors;
|
||||
DviCreateImage create_image;
|
||||
DviFreeImage free_image;
|
||||
DviPutPixel put_pixel;
|
||||
DviImageDone image_done;
|
||||
DviDevDestroy dev_destroy;
|
||||
DviRefresh refresh;
|
||||
DviSetColor set_color;
|
||||
DviPSDraw draw_ps;
|
||||
void * device_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Fonts
|
||||
*/
|
||||
|
||||
#include "fontmap.h"
|
||||
|
||||
struct _TFMChar {
|
||||
Int32 present;
|
||||
Int32 advance; /* advance */
|
||||
Int32 height; /* ascent */
|
||||
Int32 depth; /* descent */
|
||||
Int32 left; /* leftSideBearing */
|
||||
Int32 right; /* rightSideBearing */
|
||||
};
|
||||
|
||||
struct _TFMInfo {
|
||||
int type; /* DviFontAFM, DviFontTFM, DviFontOFM */
|
||||
Uint32 checksum;
|
||||
Uint32 design;
|
||||
int loc;
|
||||
int hic;
|
||||
char coding[64];
|
||||
char family[64];
|
||||
TFMChar *chars;
|
||||
};
|
||||
|
||||
struct _DviGlyph {
|
||||
short x, y; /* origin */
|
||||
Uint w, h; /* dimensions */
|
||||
void *data; /* bitmap or XImage */
|
||||
};
|
||||
|
||||
typedef void (*DviFontShrinkFunc)
|
||||
__PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
|
||||
typedef int (*DviFontLoadFunc) __PROTO((DviParams *, DviFont *));
|
||||
typedef int (*DviFontGetGlyphFunc) __PROTO((DviParams *, DviFont *, int));
|
||||
typedef void (*DviFontFreeFunc) __PROTO((DviFont *));
|
||||
typedef void (*DviFontResetFunc) __PROTO((DviFont *));
|
||||
typedef char *(*DviFontLookupFunc) __PROTO((const char *, Ushort *, Ushort *));
|
||||
typedef int (*DviFontEncodeFunc) __PROTO((DviParams *, DviFont *, DviEncoding *));
|
||||
|
||||
struct _DviFontInfo {
|
||||
char *name; /* human-readable format identifying string */
|
||||
int scalable; /* does it support scaling natively? */
|
||||
DviFontLoadFunc load;
|
||||
DviFontGetGlyphFunc getglyph;
|
||||
DviFontShrinkFunc shrink0;
|
||||
DviFontShrinkFunc shrink1;
|
||||
DviFontFreeFunc freedata;
|
||||
DviFontResetFunc reset;
|
||||
DviFontLookupFunc lookup;
|
||||
int kpse_type;
|
||||
void * private;
|
||||
};
|
||||
|
||||
struct _DviFontChar {
|
||||
Uint32 offset;
|
||||
Int16 code; /* format-dependent, not used by MDVI */
|
||||
Int16 width;
|
||||
Int16 height;
|
||||
Int16 x;
|
||||
Int16 y;
|
||||
Int32 tfmwidth;
|
||||
Ushort flags;
|
||||
#ifdef __STRICT_ANSI__
|
||||
Ushort loaded;
|
||||
Ushort missing;
|
||||
#else
|
||||
Ushort loaded : 1,
|
||||
missing : 1;
|
||||
#endif
|
||||
Ulong fg;
|
||||
Ulong bg;
|
||||
BITMAP *glyph_data;
|
||||
/* data for shrunk bitimaps */
|
||||
DviGlyph glyph;
|
||||
DviGlyph shrunk;
|
||||
DviGlyph grey;
|
||||
};
|
||||
|
||||
struct _DviFontRef {
|
||||
DviFontRef *next;
|
||||
DviFont *ref;
|
||||
Int32 fontid;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
DviFontAny = -1,
|
||||
DviFontPK = 0,
|
||||
DviFontGF = 1,
|
||||
DviFontVF = 2,
|
||||
DviFontTFM = 3,
|
||||
DviFontT1 = 4,
|
||||
DviFontTT = 5,
|
||||
DviFontAFM = 6,
|
||||
DviFontOFM = 7
|
||||
} DviFontType;
|
||||
|
||||
struct _DviFontSearch {
|
||||
int id;
|
||||
Ushort hdpi;
|
||||
Ushort vdpi;
|
||||
Ushort actual_hdpi;
|
||||
Ushort actual_vdpi;
|
||||
const char *wanted_name;
|
||||
const char *actual_name;
|
||||
DviFontClass *curr;
|
||||
DviFontInfo *info;
|
||||
};
|
||||
|
||||
/* this is a kludge, I know */
|
||||
#define ISVIRTUAL(font) ((font)->search.info->getglyph == NULL)
|
||||
#define SEARCH_DONE(s) ((s).id < 0)
|
||||
#define SEARCH_INIT(s, name, h, v) do { \
|
||||
(s).id = 0; \
|
||||
(s).curr = NULL; \
|
||||
(s).hdpi = (h); \
|
||||
(s).vdpi = (v); \
|
||||
(s).wanted_name = (name); \
|
||||
(s).actual_name = NULL; \
|
||||
} while(0)
|
||||
|
||||
struct _DviFont {
|
||||
DviFont *next;
|
||||
DviFont *prev;
|
||||
int type;
|
||||
Int32 checksum;
|
||||
int hdpi;
|
||||
int vdpi;
|
||||
Int32 scale;
|
||||
Int32 design;
|
||||
FILE *in;
|
||||
char *fontname;
|
||||
char *filename;
|
||||
int links;
|
||||
int loc;
|
||||
int hic;
|
||||
Uint flags;
|
||||
DviFontSearch search;
|
||||
DviFontChar *chars;
|
||||
DviFontRef *subfonts;
|
||||
void *private;
|
||||
};
|
||||
|
||||
/*
|
||||
* Dvi context
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
MDVI_ORIENT_TBLR = 0, /* top to bottom, left to right */
|
||||
MDVI_ORIENT_TBRL = 1, /* top to bottom, right to left */
|
||||
MDVI_ORIENT_BTLR = 2, /* bottom to top, left to right */
|
||||
MDVI_ORIENT_BTRL = 3, /* bottom to top, right to left */
|
||||
MDVI_ORIENT_RP90 = 4, /* rotated +90 degrees (counter-clockwise) */
|
||||
MDVI_ORIENT_RM90 = 5, /* rotated -90 degrees (clockwise) */
|
||||
MDVI_ORIENT_IRP90 = 6, /* flip horizontally, then rotate by +90 */
|
||||
MDVI_ORIENT_IRM90 = 7 /* rotate by -90, then flip horizontally */
|
||||
} DviOrientation;
|
||||
|
||||
typedef enum {
|
||||
MDVI_PAGE_SORT_UP, /* up, using \counter0 */
|
||||
MDVI_PAGE_SORT_DOWN, /* down, using \counter0 */
|
||||
MDVI_PAGE_SORT_RANDOM, /* randomly */
|
||||
MDVI_PAGE_SORT_DVI_UP, /* up, by location in DVI file */
|
||||
MDVI_PAGE_SORT_DVI_DOWN, /* down, by location in DVI file */
|
||||
MDVI_PAGE_SORT_NONE /* don't sort */
|
||||
} DviPageSort;
|
||||
|
||||
struct _DviParams {
|
||||
double mag; /* magnification */
|
||||
double conv; /* horizontal DVI -> pixel */
|
||||
double vconv; /* vertical DVI -> pixel */
|
||||
double tfm_conv; /* TFM -> DVI */
|
||||
double gamma; /* gamma correction factor */
|
||||
Uint dpi; /* horizontal resolution */
|
||||
Uint vdpi; /* vertical resolution */
|
||||
int hshrink; /* horizontal shrinking factor */
|
||||
int vshrink; /* vertical shrinking factor */
|
||||
Uint density; /* pixel density */
|
||||
Uint flags; /* flags (see MDVI_PARAM macros) */
|
||||
int hdrift; /* max. horizontal drift */
|
||||
int vdrift; /* max. vertical drift */
|
||||
int vsmallsp; /* small vertical space */
|
||||
int thinsp; /* small horizontal space */
|
||||
int layer; /* visible layer (for layered DVI files) */
|
||||
Ulong fg; /* foreground color */
|
||||
Ulong bg; /* background color */
|
||||
DviOrientation orientation; /* page orientation */
|
||||
int base_x;
|
||||
int base_y;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MDVI_PARAM_LAST = 0,
|
||||
MDVI_SET_DPI = 1,
|
||||
MDVI_SET_XDPI = 2,
|
||||
MDVI_SET_YDPI = 3,
|
||||
MDVI_SET_SHRINK = 4,
|
||||
MDVI_SET_XSHRINK = 5,
|
||||
MDVI_SET_YSHRINK = 6,
|
||||
MDVI_SET_GAMMA = 7,
|
||||
MDVI_SET_DENSITY = 8,
|
||||
MDVI_SET_MAGNIFICATION = 9,
|
||||
MDVI_SET_DRIFT = 10,
|
||||
MDVI_SET_HDRIFT = 11,
|
||||
MDVI_SET_VDRIFT = 12,
|
||||
MDVI_SET_ORIENTATION = 13,
|
||||
MDVI_SET_FOREGROUND = 14,
|
||||
MDVI_SET_BACKGROUND = 15
|
||||
} DviParamCode;
|
||||
|
||||
struct _DviBuffer {
|
||||
Uchar *data;
|
||||
size_t size; /* allocated size */
|
||||
size_t length; /* amount of data buffered */
|
||||
size_t pos; /* current position in buffer */
|
||||
int frozen; /* can we free this data? */
|
||||
};
|
||||
|
||||
/* DVI registers */
|
||||
struct _DviState {
|
||||
int h;
|
||||
int v;
|
||||
int hh;
|
||||
int vv;
|
||||
int w;
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
};
|
||||
|
||||
struct _DviColorPair {
|
||||
Ulong fg;
|
||||
Ulong bg;
|
||||
};
|
||||
|
||||
struct _DviContext {
|
||||
char *filename; /* name of the DVI file */
|
||||
FILE *in; /* from here we read */
|
||||
char *fileid; /* from preamble */
|
||||
int npages; /* number of pages */
|
||||
int currpage; /* currrent page (0 based) */
|
||||
int depth; /* recursion depth */
|
||||
DviBuffer buffer; /* input buffer */
|
||||
DviParams params; /* parameters */
|
||||
DviPaper paper; /* paper type */
|
||||
Int32 num; /* numerator */
|
||||
Int32 den; /* denominator */
|
||||
DviFontRef *fonts; /* fonts used in this file */
|
||||
DviFontRef **fontmap; /* for faster id lookups */
|
||||
DviFontRef *currfont; /* current font */
|
||||
int nfonts; /* # of fonts used in this job */
|
||||
Int32 dvimag; /* original magnification */
|
||||
double dviconv; /* unshrunk scaling factor */
|
||||
double dvivconv; /* unshrunk scaling factor (vertical) */
|
||||
int dvi_page_w; /* unscaled page width */
|
||||
int dvi_page_h; /* unscaled page height */
|
||||
Ulong modtime; /* file modification time */
|
||||
PageNum *pagemap; /* page table */
|
||||
DviState pos; /* registers */
|
||||
DviPageSpec *pagesel; /* page selection data */
|
||||
int curr_layer; /* current layer */
|
||||
DviState *stack; /* DVI stack */
|
||||
int stacksize; /* stack depth */
|
||||
int stacktop; /* stack pointer */
|
||||
DviDevice device; /* device-specific routines */
|
||||
Ulong curr_fg; /* rendering color */
|
||||
Ulong curr_bg;
|
||||
|
||||
DviColorPair *color_stack;
|
||||
int color_top;
|
||||
int color_size;
|
||||
|
||||
DviFontRef *(*findref) __PROTO((DviContext *, Int32));
|
||||
void *user_data; /* client data attached to this context */
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
MDVI_RANGE_BOUNDED, /* range is finite */
|
||||
MDVI_RANGE_LOWER, /* range has a lower bound */
|
||||
MDVI_RANGE_UPPER, /* range has an upper bound */
|
||||
MDVI_RANGE_UNBOUNDED /* range has no bounds at all */
|
||||
} DviRangeType;
|
||||
|
||||
struct _DviRange {
|
||||
DviRangeType type; /* one of the above */
|
||||
int from; /* lower bound */
|
||||
int to; /* upper bound */
|
||||
int step; /* step */
|
||||
};
|
||||
|
||||
|
||||
typedef void (*DviSpecialHandler)
|
||||
__PROTO((DviContext *dvi, const char *prefix, const char *arg));
|
||||
|
||||
#define RANGE_HAS_LOWER(x) \
|
||||
((x) == MDVI_RANGE_BOUNDED || (x) == MDVI_RANGE_LOWER)
|
||||
#define RANGE_HAS_UPPER(x) \
|
||||
((x) == MDVI_RANGE_BOUNDED || (x) == MDVI_RANGE_UPPER)
|
||||
|
||||
/*
|
||||
* Macros and prototypes
|
||||
*/
|
||||
|
||||
#define MDVI_PARAM_ANTIALIASED 1
|
||||
#define MDVI_PARAM_MONO 2
|
||||
#define MDVI_PARAM_CHARBOXES 4
|
||||
#define MDVI_PARAM_SHOWUNDEF 8
|
||||
#define MDVI_PARAM_DELAYFONTS 16
|
||||
|
||||
/*
|
||||
* The FALLBACK priority class is reserved for font formats that
|
||||
* contain no glyph information and are to be used as a last
|
||||
* resort (e.g. TFM, AFM)
|
||||
*/
|
||||
#define MDVI_FONTPRIO_FALLBACK -3
|
||||
#define MDVI_FONTPRIO_LOWEST -2
|
||||
#define MDVI_FONTPRIO_LOW -1
|
||||
#define MDVI_FONTPRIO_NORMAL 0
|
||||
#define MDVI_FONTPRIO_HIGH 1
|
||||
#define MDVI_FONTPRIO_HIGHEST 2
|
||||
|
||||
#define MDVI_FONT_ENCODED (1 << 0)
|
||||
|
||||
#define MDVI_GLYPH_EMPTY ((void *)1)
|
||||
/* does the glyph have a non-empty bitmap/image? */
|
||||
#define MDVI_GLYPH_NONEMPTY(x) ((x) && (x) != MDVI_GLYPH_EMPTY)
|
||||
/* has the glyph been loaded from disk? */
|
||||
#define MDVI_GLYPH_UNSET(x) ((x) == NULL)
|
||||
/* do we have only a bounding box for this glyph? */
|
||||
#define MDVI_GLYPH_ISEMPTY(x) ((x) == MDVI_GLYPH_EMPTY)
|
||||
|
||||
#define MDVI_ENABLED(d,x) ((d)->params.flags & (x))
|
||||
#define MDVI_DISABLED(d,x) !MDVI_ENABLED((d), (x))
|
||||
|
||||
#define MDVI_LASTPAGE(d) ((d)->npages - 1)
|
||||
#define MDVI_NPAGES(d) (d)->npages
|
||||
#define MDVI_VALIDPAGE(d,p) ((p) >= 0 && (p) <= MDVI_LASTPAGE(d))
|
||||
#define MDVI_FLAGS(d) (d)->params.flags
|
||||
#define MDVI_SHRINK_FROM_DPI(d) Max(1, (d) / 75)
|
||||
#define MDVI_CURRFG(d) (d)->curr_fg
|
||||
#define MDVI_CURRBG(d) (d)->curr_bg
|
||||
|
||||
#define pixel_round(d,v) (int)((d)->params.conv * (v) + 0.5)
|
||||
#define vpixel_round(d,v) (int)((d)->params.vconv * (v) + 0.5)
|
||||
#define rule_round(d,v) (int)((d)->params.conv * (v) + 0.99999) /*9999999)*/
|
||||
#define vrule_round(d,v) (int)((d)->params.vconv * (v) + 0.99999)
|
||||
|
||||
extern int mdvi_reload __PROTO((DviContext *, DviParams *));
|
||||
extern void mdvi_setpage __PROTO((DviContext *, int));
|
||||
extern int mdvi_dopage __PROTO((DviContext *, int));
|
||||
extern void mdvi_shrink_glyph __PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
|
||||
extern void mdvi_shrink_box __PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
|
||||
extern void mdvi_shrink_glyph_grey __PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
|
||||
extern int mdvi_find_tex_page __PROTO((DviContext *, int));
|
||||
extern int mdvi_configure __PROTO((DviContext *, DviParamCode, ...));
|
||||
|
||||
extern int get_tfm_chars __PROTO((DviParams *, DviFont *, TFMInfo *, int));
|
||||
extern int tfm_load_file __PROTO((const char *, TFMInfo *));
|
||||
extern int afm_load_file __PROTO((const char *, TFMInfo *));
|
||||
extern TFMInfo *get_font_metrics __PROTO((const char *, int, const char *));
|
||||
extern char *lookup_font_metrics __PROTO((const char *, int *));
|
||||
extern void free_font_metrics __PROTO((TFMInfo *));
|
||||
extern void flush_font_metrics __PROTO((void));
|
||||
|
||||
#define get_metrics(name) get_font_metrics((name), DviFontAny, NULL)
|
||||
|
||||
extern void mdvi_sort_pages __PROTO((DviContext *, DviPageSort));
|
||||
|
||||
extern void mdvi_init_kpathsea __PROTO((const char *, const char *, const char *, int, const char *));
|
||||
|
||||
extern DviContext* mdvi_init_context __PROTO((DviParams *, DviPageSpec *, const char *));
|
||||
extern void mdvi_destroy_context __PROTO((DviContext *));
|
||||
|
||||
/* helper macros that call mdvi_configure() */
|
||||
#define mdvi_config_one(d,x,y) mdvi_configure((d), (x), (y), MDVI_PARAM_LAST)
|
||||
#define mdvi_set_dpi(d,x) mdvi_config_one((d), MDVI_SET_DPI, (x))
|
||||
#define mdvi_set_xdpi(d,x) mdvi_config_one((d), MDVI_SET_XDPI, (x))
|
||||
#define mdvi_set_ydpi(d,x) mdvi_config_one((d), MDVI_SET_YDPI, (x))
|
||||
#define mdvi_set_hshrink(d,h) mdvi_config_one((d), MDVI_SET_XSHRINK, (h))
|
||||
#define mdvi_set_vshrink(d,h) mdvi_config_one((d), MDVI_SET_YSHRINK, (h))
|
||||
#define mdvi_set_gamma(d,g) mdvi_config_one((d), MDVI_SET_GAMMA, (g))
|
||||
#define mdvi_set_density(d,x) mdvi_config_one((d), MDVI_SET_DENSITY, (x))
|
||||
#define mdvi_set_drift(d,x) mdvi_config_one((d), MDVI_SET_DRIFT, (x))
|
||||
#define mdvi_set_hdrift(d,h) mdvi_config_one((d), MDVI_SET_HDRIFT, (h))
|
||||
#define mdvi_set_vdrift(d,v) mdvi_config_one((d), MDVI_SET_VDRIFT, (v))
|
||||
#define mdvi_set_mag(d,m) \
|
||||
mdvi_config_one((d), MDVI_SET_MAGNIFICATION, (m))
|
||||
#define mdvi_set_foreground(d,x) \
|
||||
mdvi_config_one((d), MDVI_SET_FOREGROUND, (x))
|
||||
#define mdvi_set_background(d,x) \
|
||||
mdvi_config_one((d), MDVI_SET_BACKGROUND, (x))
|
||||
#define mdvi_set_orientation(d,x) \
|
||||
mdvi_config_one((d), MDVI_SET_ORIENTATION, (x))
|
||||
#define mdvi_set_shrink(d,h,v) \
|
||||
mdvi_configure((d), MDVI_SET_XSHRINK, (h), \
|
||||
MDVI_SET_YSHRINK, (v), MDVI_PARAM_LAST)
|
||||
|
||||
extern DviRange* mdvi_parse_range __PROTO((const char *, DviRange *, int *, char **));
|
||||
extern DviPageSpec* mdvi_parse_page_spec __PROTO((const char *));
|
||||
extern void mdvi_free_page_spec __PROTO((DviPageSpec *));
|
||||
extern int mdvi_in_range __PROTO((DviRange *, int, int));
|
||||
extern int mdvi_range_length __PROTO((DviRange *, int));
|
||||
extern int mdvi_page_selected __PROTO((DviPageSpec *, PageNum, int));
|
||||
|
||||
/* Specials */
|
||||
extern int mdvi_register_special __PROTO((
|
||||
const char *label,
|
||||
const char *prefix,
|
||||
const char *regex,
|
||||
DviSpecialHandler handler,
|
||||
int replace));
|
||||
extern int mdvi_unregister_special __PROTO((const char *prefix));
|
||||
extern int mdvi_do_special __PROTO((DviContext *dvi, char *dvi_special));
|
||||
extern void mdvi_flush_specials __PROTO((void));
|
||||
|
||||
/* Fonts */
|
||||
|
||||
#define MDVI_FONTSEL_BITMAP (1 << 0)
|
||||
#define MDVI_FONTSEL_GREY (1 << 1)
|
||||
#define MDVI_FONTSEL_GLYPH (1 << 2)
|
||||
|
||||
#define FONTCHAR(font, code) \
|
||||
(((code) < font->loc || (code) > font->hic || !(font)->chars) ? \
|
||||
NULL : &font->chars[(code) - (font)->loc])
|
||||
#define FONT_GLYPH_COUNT(font) ((font)->hic - (font)->loc + 1)
|
||||
|
||||
#define glyph_present(x) ((x) && (x)->offset)
|
||||
|
||||
/* create a reference to a font */
|
||||
extern DviFontRef *font_reference __PROTO((DviParams *params,
|
||||
Int32 dvi_id,
|
||||
const char *font_name,
|
||||
Int32 checksum,
|
||||
int xdpi,
|
||||
int ydpi,
|
||||
Int32 scale_factor));
|
||||
|
||||
/* drop a reference to a font */
|
||||
extern void font_drop_one __PROTO((DviFontRef *));
|
||||
|
||||
/* drop a chain of references */
|
||||
extern void font_drop_chain __PROTO((DviFontRef *));
|
||||
|
||||
/* destroy selected information for a glyph */
|
||||
extern void font_reset_one_glyph __PROTO((DviDevice *, DviFontChar *, int));
|
||||
|
||||
/* destroy selected information for all glyphs in a font */
|
||||
extern void font_reset_font_glyphs __PROTO((DviDevice *, DviFont *, int));
|
||||
|
||||
/* same for a chain of font references */
|
||||
extern void font_reset_chain_glyphs __PROTO((DviDevice *, DviFontRef *, int));
|
||||
|
||||
extern void font_finish_definitions __PROTO((DviContext *));
|
||||
|
||||
/* lookup an id # in a reference chain */
|
||||
extern DviFontRef* font_find_flat __PROTO((DviContext *, Int32));
|
||||
extern DviFontRef* font_find_mapped __PROTO((DviContext *, Int32));
|
||||
|
||||
/* called to reopen (or rewind) a font file */
|
||||
extern int font_reopen __PROTO((DviFont *));
|
||||
|
||||
/* reads a glyph from a font, and makes all necessary transformations */
|
||||
extern DviFontChar* font_get_glyph __PROTO((DviContext *, DviFont *, int));
|
||||
|
||||
/* transform a glyph according to the given orientation */
|
||||
extern void font_transform_glyph __PROTO((DviOrientation, DviGlyph *));
|
||||
|
||||
/* destroy all fonts that are not being used, returns number of fonts freed */
|
||||
extern int font_free_unused __PROTO((DviDevice *));
|
||||
|
||||
#define font_free_glyph(dev, font, code) \
|
||||
font_reset_one_glyph((dev), \
|
||||
FONTCHAR((font), (code)), MDVI_FONTSEL_GLYPH)
|
||||
|
||||
extern int mdvi_encode_font __PROTO((DviParams *, DviFont *));
|
||||
|
||||
|
||||
/* font lookup functions */
|
||||
extern int mdvi_register_font_type __PROTO((DviFontInfo *, int));
|
||||
extern char **mdvi_list_font_class __PROTO((int));
|
||||
extern int mdvi_get_font_classes __PROTO((void));
|
||||
extern int mdvi_unregister_font_type __PROTO((const char *, int));
|
||||
extern char *mdvi_lookup_font __PROTO((DviFontSearch *));
|
||||
extern DviFont *mdvi_add_font __PROTO((const char *, Int32, int, int, Int32));
|
||||
extern int mdvi_font_retry __PROTO((DviParams *, DviFont *));
|
||||
|
||||
/* Miscellaneous */
|
||||
|
||||
extern int mdvi_set_logfile __PROTO((const char *));
|
||||
extern int mdvi_set_logstream __PROTO((FILE *));
|
||||
extern int mdvi_set_loglevel __PROTO((int));
|
||||
|
||||
#define mdvi_stop_logging(x) mdvi_set_logstream(NULL)
|
||||
|
||||
/* this will check the environment and then `texmf.cnf' for
|
||||
* the given name changed to lowercase, and `_' changed to `-' */
|
||||
extern char* mdvi_getenv __PROTO((const char *));
|
||||
|
||||
#endif /* _MDVI_DVI_H */
|
|
@ -0,0 +1,491 @@
|
|||
/* pagesel.c -- Page selection mechanism */
|
||||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
char *program_name = "page";
|
||||
|
||||
struct _DviPageSpec {
|
||||
DviRange *ranges;
|
||||
int nranges;
|
||||
};
|
||||
|
||||
DviRange *mdvi_parse_range(const char *format, DviRange *limit, int *nitems, char **endptr)
|
||||
{
|
||||
int quoted;
|
||||
int size;
|
||||
int curr;
|
||||
int done;
|
||||
int lower;
|
||||
int upper;
|
||||
int type;
|
||||
char * cp;
|
||||
char * copy;
|
||||
char * text;
|
||||
DviRange one;
|
||||
DviRange *range;
|
||||
|
||||
quoted = (*format == '{');
|
||||
if(quoted) format++;
|
||||
|
||||
size = 0;
|
||||
curr = 0;
|
||||
range = NULL;
|
||||
copy = mdvi_strdup(format);
|
||||
done = 0;
|
||||
lower = 0;
|
||||
upper = 0;
|
||||
type = MDVI_RANGE_UNBOUNDED;
|
||||
|
||||
if(limit) {
|
||||
switch(limit->type) {
|
||||
case MDVI_RANGE_BOUNDED:
|
||||
lower = limit->from;
|
||||
upper = limit->to;
|
||||
break;
|
||||
case MDVI_RANGE_UPPER:
|
||||
lower = INT_MIN;
|
||||
upper = limit->to;
|
||||
break;
|
||||
case MDVI_RANGE_LOWER:
|
||||
lower = limit->from;
|
||||
upper = INT_MAX;
|
||||
break;
|
||||
case MDVI_RANGE_UNBOUNDED:
|
||||
lower = INT_MIN;
|
||||
upper = INT_MAX;
|
||||
break;
|
||||
}
|
||||
type = limit->type;
|
||||
} else {
|
||||
lower = INT_MIN;
|
||||
upper = INT_MAX;
|
||||
type = MDVI_RANGE_UNBOUNDED;
|
||||
}
|
||||
one.type = type;
|
||||
one.from = lower;
|
||||
one.to = upper;
|
||||
one.step = 1;
|
||||
for(cp = text = copy; !done; cp++) {
|
||||
char *p;
|
||||
int f, t, s;
|
||||
int ch;
|
||||
int this_type;
|
||||
int lower_given = 0;
|
||||
int upper_given = 0;
|
||||
|
||||
if(*cp == 0 || *cp == '.' || (*cp == '}' && quoted))
|
||||
done = 1;
|
||||
else if(*cp != ',')
|
||||
continue;
|
||||
|
||||
if(text == cp)
|
||||
continue;
|
||||
ch = *cp;
|
||||
*cp = 0;
|
||||
f = lower;
|
||||
t = upper;
|
||||
s = 1;
|
||||
|
||||
p = strchr(text, ':');
|
||||
if(p) *p++ = 0;
|
||||
if(*text) {
|
||||
lower_given = 1;
|
||||
f = strtol(text, NULL, 0);
|
||||
}
|
||||
if(p == NULL) {
|
||||
if(lower_given) {
|
||||
upper_given = 1;
|
||||
t = f; s = 1;
|
||||
}
|
||||
goto finish;
|
||||
}
|
||||
text = p;
|
||||
p = strchr(text, ':');
|
||||
if(p) *p++ = 0;
|
||||
if(*text) {
|
||||
upper_given = 1;
|
||||
t = strtol(text, NULL, 0);
|
||||
}
|
||||
if(p == NULL)
|
||||
goto finish;
|
||||
text = p;
|
||||
if(*text)
|
||||
s = strtol(text, NULL, 0);
|
||||
finish:
|
||||
if(lower_given && upper_given)
|
||||
this_type = MDVI_RANGE_BOUNDED;
|
||||
else if(lower_given) {
|
||||
if(!RANGE_HAS_UPPER(type))
|
||||
this_type = MDVI_RANGE_LOWER;
|
||||
else
|
||||
this_type = MDVI_RANGE_BOUNDED;
|
||||
t = upper;
|
||||
} else if(upper_given) {
|
||||
if(RANGE_HAS_UPPER(one.type)) {
|
||||
one.to++;
|
||||
this_type = MDVI_RANGE_BOUNDED;
|
||||
} else {
|
||||
one.to = lower;
|
||||
if(!RANGE_HAS_LOWER(type))
|
||||
this_type = MDVI_RANGE_UPPER;
|
||||
else
|
||||
this_type = MDVI_RANGE_BOUNDED;
|
||||
}
|
||||
f = one.to;
|
||||
} else {
|
||||
this_type = type;
|
||||
f = lower;
|
||||
t = upper;
|
||||
}
|
||||
one.type = this_type;
|
||||
one.to = t;
|
||||
one.from = f;
|
||||
one.step = s;
|
||||
|
||||
if(curr == size) {
|
||||
size += 8;
|
||||
range = mdvi_realloc(range, size * sizeof(DviRange));
|
||||
}
|
||||
memcpy(&range[curr++], &one, sizeof(DviRange));
|
||||
*cp = ch;
|
||||
text = cp + 1;
|
||||
}
|
||||
if(done)
|
||||
cp--;
|
||||
if(quoted && *cp == '}')
|
||||
cp++;
|
||||
if(endptr)
|
||||
*endptr = (char *)format + (cp - copy);
|
||||
if(curr && curr < size)
|
||||
range = mdvi_realloc(range, curr * sizeof(DviRange));
|
||||
*nitems = curr;
|
||||
mdvi_free(copy);
|
||||
return range;
|
||||
}
|
||||
|
||||
DviPageSpec *mdvi_parse_page_spec(const char *format)
|
||||
{
|
||||
/*
|
||||
* a page specification looks like this:
|
||||
* '{'RANGE_SPEC'}' for a DVI spec
|
||||
* '{'RANGE_SPEC'}' '.' ... for a TeX spec
|
||||
*/
|
||||
DviPageSpec *spec;
|
||||
DviRange *range;
|
||||
int count;
|
||||
int i;
|
||||
char *ptr;
|
||||
|
||||
spec = xnalloc(struct _DviPageSpec *, 11);
|
||||
for(i = 0; i < 11; i++)
|
||||
spec[i] = NULL;
|
||||
|
||||
/* check what kind of spec we're parsing */
|
||||
if(*format != '*') {
|
||||
range = mdvi_parse_range(format, NULL, &count, &ptr);
|
||||
if(ptr == format) {
|
||||
if(range) mdvi_free(range);
|
||||
mdvi_error(_("invalid page specification `%s'\n"), format);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
range = NULL;
|
||||
|
||||
if(*format == 'D' || *format == 'd' || *ptr != '.')
|
||||
i = 0;
|
||||
else
|
||||
i = 1;
|
||||
|
||||
if(range) {
|
||||
spec[i] = xalloc(struct _DviPageSpec);
|
||||
spec[i]->ranges = range;
|
||||
spec[i]->nranges = count;
|
||||
} else
|
||||
spec[i] = NULL;
|
||||
|
||||
if(*ptr != '.') {
|
||||
if(*ptr)
|
||||
mdvi_warning(_("garbage after DVI page specification ignored\n"));
|
||||
return spec;
|
||||
}
|
||||
|
||||
for(i++; *ptr == '.' && i <= 10; i++) {
|
||||
ptr++;
|
||||
if(*ptr == '*') {
|
||||
ptr++;
|
||||
range = NULL;
|
||||
} else {
|
||||
char *end;
|
||||
|
||||
range = mdvi_parse_range(ptr, NULL, &count, &end);
|
||||
if(end == ptr) {
|
||||
if(range) mdvi_free(range);
|
||||
range = NULL;
|
||||
} else
|
||||
ptr = end;
|
||||
}
|
||||
if(range != NULL) {
|
||||
spec[i] = xalloc(struct _DviPageSpec);
|
||||
spec[i]->ranges = range;
|
||||
spec[i]->nranges = count;
|
||||
} else
|
||||
spec[i] = NULL;
|
||||
}
|
||||
|
||||
if(i > 10)
|
||||
mdvi_warning(_("more than 10 counters in page specification\n"));
|
||||
else if(*ptr)
|
||||
mdvi_warning(_("garbage after TeX page specification ignored\n"));
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
/* returns non-zero if the given page is included by `spec' */
|
||||
int mdvi_page_selected(DviPageSpec *spec, PageNum page, int dvipage)
|
||||
{
|
||||
int i;
|
||||
int not_found;
|
||||
|
||||
if(spec == NULL)
|
||||
return 1;
|
||||
if(spec[0]) {
|
||||
not_found = mdvi_in_range(spec[0]->ranges,
|
||||
spec[0]->nranges, dvipage);
|
||||
if(not_found < 0)
|
||||
return 0;
|
||||
}
|
||||
for(i = 1; i <= 10; i++) {
|
||||
if(spec[i] == NULL)
|
||||
continue;
|
||||
not_found = mdvi_in_range(spec[i]->ranges,
|
||||
spec[i]->nranges, (int)page[i]);
|
||||
if(not_found < 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void mdvi_free_page_spec(DviPageSpec *spec)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 11; i++)
|
||||
if(spec[i]) {
|
||||
mdvi_free(spec[i]->ranges);
|
||||
mdvi_free(spec[i]);
|
||||
}
|
||||
mdvi_free(spec);
|
||||
}
|
||||
|
||||
int mdvi_in_range(DviRange *range, int nitems, int value)
|
||||
{
|
||||
DviRange *r;
|
||||
|
||||
for(r = range; r < range + nitems; r++) {
|
||||
int cond;
|
||||
|
||||
switch(r->type) {
|
||||
case MDVI_RANGE_BOUNDED:
|
||||
if(value == r->from)
|
||||
return (r - range);
|
||||
if(r->step < 0)
|
||||
cond = (value <= r->from) && (value >= r->to);
|
||||
else
|
||||
cond = (value <= r->to) && (value >= r->from);
|
||||
if(cond && ((value - r->from) % r->step) == 0)
|
||||
return (r - range);
|
||||
break;
|
||||
case MDVI_RANGE_LOWER:
|
||||
if(value == r->from)
|
||||
return (r - range);
|
||||
if(r->step < 0)
|
||||
cond = (value < r->from);
|
||||
else
|
||||
cond = (value > r->from);
|
||||
if(cond && ((value - r->from) % r->step) == 0)
|
||||
return (r - range);
|
||||
break;
|
||||
case MDVI_RANGE_UPPER:
|
||||
if(value == r->to)
|
||||
return (r - range);
|
||||
if(r->step < 0)
|
||||
cond = (value > r->to);
|
||||
else
|
||||
cond = (value < r->to);
|
||||
if(cond && ((value - r->to) % r->step) == 0)
|
||||
return (r - range);
|
||||
break;
|
||||
case MDVI_RANGE_UNBOUNDED:
|
||||
if((value % r->step) == 0)
|
||||
return (r - range);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int mdvi_range_length(DviRange *range, int nitems)
|
||||
{
|
||||
int count = 0;
|
||||
DviRange *r;
|
||||
|
||||
for(r = range; r < range + nitems; r++) {
|
||||
int n;
|
||||
|
||||
if(r->type != MDVI_RANGE_BOUNDED)
|
||||
return -2;
|
||||
n = (r->to - r->from) / r->step;
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
count += n + 1;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
void print_range(DviRange *range)
|
||||
{
|
||||
switch(range->type) {
|
||||
case MDVI_RANGE_BOUNDED:
|
||||
printf("From %d to %d, step %d\n",
|
||||
range->from, range->to, range->step);
|
||||
break;
|
||||
case MDVI_RANGE_LOWER:
|
||||
printf("From %d, step %d\n",
|
||||
range->from, range->step);
|
||||
break;
|
||||
case MDVI_RANGE_UPPER:
|
||||
printf("From %d, step -%d\n",
|
||||
range->to, range->step);
|
||||
break;
|
||||
case MDVI_RANGE_UNBOUNDED:
|
||||
printf("From 0, step %d and %d\n",
|
||||
range->step, -range->step);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#if 0
|
||||
char buf[256];
|
||||
DviRange limit;
|
||||
|
||||
limit.from = 0;
|
||||
limit.to = 100;
|
||||
limit.step = 2;
|
||||
limit.type = MDVI_RANGE_UNBOUNDED;
|
||||
while(1) {
|
||||
DviRange *range;
|
||||
char *end;
|
||||
int count;
|
||||
int i;
|
||||
|
||||
printf("Range> "); fflush(stdout);
|
||||
if(fgets(buf, 256, stdin) == NULL)
|
||||
break;
|
||||
if(buf[strlen(buf)-1] == '\n')
|
||||
buf[strlen(buf)-1] = 0;
|
||||
if(buf[0] == 0)
|
||||
continue;
|
||||
end = NULL;
|
||||
range = mdvi_parse_range(buf, &limit, &count, &end);
|
||||
if(range == NULL) {
|
||||
printf("range is empty\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
for(i = 0; i < count; i++) {
|
||||
printf("Range %d (%d elements):\n",
|
||||
i, mdvi_range_length(&range[i], 1));
|
||||
print_range(&range[i]);
|
||||
}
|
||||
if(end && *end)
|
||||
printf("Tail: [%s]\n", end);
|
||||
printf("range has %d elements\n",
|
||||
mdvi_range_length(range, count));
|
||||
#if 1
|
||||
while(1) {
|
||||
int v;
|
||||
|
||||
printf("Value: "); fflush(stdout);
|
||||
if(fgets(buf, 256, stdin) == NULL)
|
||||
break;
|
||||
if(buf[strlen(buf)-1] == '\n')
|
||||
buf[strlen(buf)-1] = 0;
|
||||
if(buf[0] == 0)
|
||||
break;
|
||||
v = atoi(buf);
|
||||
i = mdvi_in_range(range, count, v);
|
||||
if(i == -1)
|
||||
printf("%d not in range\n", v);
|
||||
else {
|
||||
printf("%d in range: ", v);
|
||||
print_range(&range[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(range) mdvi_free(range);
|
||||
}
|
||||
#else
|
||||
DviPageSpec *spec;
|
||||
char buf[256];
|
||||
|
||||
while(1) {
|
||||
printf("Spec> "); fflush(stdout);
|
||||
if(fgets(buf, 256, stdin) == NULL)
|
||||
break;
|
||||
if(buf[strlen(buf)-1] == '\n')
|
||||
buf[strlen(buf)-1] = 0;
|
||||
if(buf[0] == 0)
|
||||
continue;
|
||||
spec = mdvi_parse_page_spec(buf);
|
||||
if(spec == NULL)
|
||||
printf("no spec parsed\n");
|
||||
else {
|
||||
int i;
|
||||
|
||||
printf("spec = ");
|
||||
for(i = 0; i < 11; i++) {
|
||||
printf("Counter %d:\n", i);
|
||||
if(spec[i]) {
|
||||
int k;
|
||||
|
||||
for(k = 0; k < spec[i]->nranges; k++)
|
||||
print_range(&spec[i]->ranges[k]);
|
||||
} else
|
||||
printf("\t*\n");
|
||||
}
|
||||
mdvi_free_page_spec(spec);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
exit(0);
|
||||
|
||||
}
|
||||
#endif /* TEST */
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
static const DviPaperSpec papers[] = {
|
||||
{"ISO", 0, 0},
|
||||
{"4A0", "1682mm", "2378mm"},
|
||||
{"2A0", "1189mm", "1682mm"},
|
||||
{"A0", "841mm", "1189mm"},
|
||||
{"A1", "594mm", "841mm"},
|
||||
{"A2", "420mm", "594mm"},
|
||||
{"A3", "297mm", "420mm"},
|
||||
{"A4", "210mm", "297mm"},
|
||||
{"A5", "148mm", "210mm"},
|
||||
{"A6", "105mm", "148mm"},
|
||||
{"A7", "74mm", "105mm"},
|
||||
{"A8", "52mm", "74mm"},
|
||||
{"A9", "37mm", "52mm"},
|
||||
{"A10", "26mm", "37mm"},
|
||||
{"B0", "1000mm", "1414mm"},
|
||||
{"B1", "707mm", "1000mm"},
|
||||
{"B2", "500mm", "707mm"},
|
||||
{"B3", "353mm", "500mm"},
|
||||
{"B4", "250mm", "353mm"},
|
||||
{"B5", "176mm", "250mm"},
|
||||
{"B6", "125mm", "176mm"},
|
||||
{"B7", "88mm", "125mm"},
|
||||
{"B8", "62mm", "88mm"},
|
||||
{"B9", "44mm", "62mm"},
|
||||
{"B10", "31mm", "44mm"},
|
||||
{"C0", "917mm", "1297mm"},
|
||||
{"C1", "648mm", "917mm"},
|
||||
{"C2", "458mm", "648mm"},
|
||||
{"C3", "324mm", "458mm"},
|
||||
{"C4", "229mm", "324mm"},
|
||||
{"C5", "162mm", "229mm"},
|
||||
{"C6", "114mm", "162mm"},
|
||||
{"C7", "81mm", "114mm"},
|
||||
{"C8", "57mm", "81mm"},
|
||||
{"C9", "40mm", "57mm"},
|
||||
{"C10", "28mm", "40mm"},
|
||||
{"US", 0, 0},
|
||||
{"archA", "9in", "12in"},
|
||||
{"archB", "12in", "18in"},
|
||||
{"archC", "18in", "24in"},
|
||||
{"archD", "24in", "36in"},
|
||||
{"archE", "36in", "48in"},
|
||||
{"executive", "7.5in", "10in"},
|
||||
{"flsa", "8.5in", "13in"},
|
||||
{"flse", "8.5in", "13in"},
|
||||
{"halfletter", "5.5in", "8.5in"},
|
||||
{"letter", "8.5in", "11in"},
|
||||
{"legal", "8.5in", "14in"},
|
||||
{"ledger", "17in", "11in"},
|
||||
{"note", "7.5in", "10in"},
|
||||
{"tabloid", "11in", "17in"},
|
||||
{"statement", "5.5in", "8.5in"},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
static DviPaperClass str2class(const char *name)
|
||||
{
|
||||
if(STRCEQ(name, "ISO"))
|
||||
return MDVI_PAPER_CLASS_ISO;
|
||||
else if(STRCEQ(name, "US"))
|
||||
return MDVI_PAPER_CLASS_US;
|
||||
return MDVI_PAPER_CLASS_CUSTOM;
|
||||
}
|
||||
|
||||
int mdvi_get_paper_size(const char *name, DviPaper *paper)
|
||||
{
|
||||
const DviPaperSpec *sp;
|
||||
double a, b;
|
||||
char c, d, e, f;
|
||||
char buf[32];
|
||||
|
||||
paper->pclass = MDVI_PAPER_CLASS_CUSTOM;
|
||||
if(sscanf(name, "%lfx%lf%c%c", &a, &b, &c, &d) == 4) {
|
||||
sprintf(buf, "%12.16f%c%c", a, c, d);
|
||||
paper->inches_wide = unit2pix_factor(buf);
|
||||
sprintf(buf, "%12.16f%c%c", b, c, d);
|
||||
paper->inches_tall = unit2pix_factor(buf);
|
||||
paper->name = _("custom");
|
||||
return 0;
|
||||
} else if(sscanf(name, "%lf%c%c,%lf%c%c", &a, &c, &d, &b, &e, &f) == 6) {
|
||||
sprintf(buf, "%12.16f%c%c", a, c, d);
|
||||
paper->inches_wide = unit2pix_factor(buf);
|
||||
sprintf(buf, "%12.16f%c%c", b, e, f);
|
||||
paper->inches_tall = unit2pix_factor(buf);
|
||||
paper->name = _("custom");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(sp = &papers[0]; sp->name; sp++) {
|
||||
if(!sp->width || !sp->height) {
|
||||
paper->pclass = str2class(sp->name);
|
||||
continue;
|
||||
}
|
||||
if(strcasecmp(sp->name, name) == 0) {
|
||||
paper->inches_wide = unit2pix_factor(sp->width);
|
||||
paper->inches_tall = unit2pix_factor(sp->height);
|
||||
paper->name = sp->name;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
DviPaperSpec *mdvi_get_paper_specs(DviPaperClass pclass)
|
||||
{
|
||||
int i;
|
||||
int first, count;
|
||||
DviPaperSpec *spec, *ptr;
|
||||
|
||||
first = -1;
|
||||
count = 0;
|
||||
if(pclass == MDVI_PAPER_CLASS_ANY ||
|
||||
pclass == MDVI_PAPER_CLASS_CUSTOM) {
|
||||
first = 0;
|
||||
count = (sizeof(papers) / sizeof(papers[0])) - 3;
|
||||
} else for(i = 0; papers[i].name; i++) {
|
||||
if(papers[i].width == NULL) {
|
||||
if(str2class(papers[i].name) == pclass)
|
||||
first = i;
|
||||
else if(first >= 0)
|
||||
break;
|
||||
} else if(first >= 0)
|
||||
count++;
|
||||
}
|
||||
ptr = spec = xnalloc(DviPaperSpec, count + 1);
|
||||
for(i = first; papers[i].name&& count > 0; i++) {
|
||||
if(papers[i].width) {
|
||||
ptr->name = papers[i].name;
|
||||
ptr->width = papers[i].width;
|
||||
ptr->height = papers[i].height;
|
||||
ptr++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
ptr->name = NULL;
|
||||
ptr->width = NULL;
|
||||
ptr->height = NULL;
|
||||
|
||||
return spec;
|
||||
}
|
||||
|
||||
void mdvi_free_paper_specs(DviPaperSpec *spec)
|
||||
{
|
||||
mdvi_free(spec);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef MDVI_PAPER
|
||||
#define MDVI_PAPER
|
||||
|
||||
typedef struct _DviPaper DviPaper;
|
||||
typedef struct _DviPaperSpec DviPaperSpec;
|
||||
|
||||
typedef enum {
|
||||
MDVI_PAPER_CLASS_ISO,
|
||||
MDVI_PAPER_CLASS_US,
|
||||
MDVI_PAPER_CLASS_ANY,
|
||||
MDVI_PAPER_CLASS_CUSTOM
|
||||
} DviPaperClass;
|
||||
|
||||
struct _DviPaper {
|
||||
DviPaperClass pclass;
|
||||
const char *name;
|
||||
double inches_wide;
|
||||
double inches_tall;
|
||||
};
|
||||
|
||||
struct _DviPaperSpec {
|
||||
const char *name;
|
||||
const char *width;
|
||||
const char *height;
|
||||
};
|
||||
|
||||
|
||||
extern int mdvi_get_paper_size __PROTO((const char *, DviPaper *));
|
||||
extern DviPaperSpec* mdvi_get_paper_specs __PROTO((DviPaperClass));
|
||||
extern void mdvi_free_paper_specs __PROTO((DviPaperSpec *));
|
||||
|
||||
#endif
|
|
@ -0,0 +1,580 @@
|
|||
|
||||
/* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* History:
|
||||
*
|
||||
* 11/3/2000:
|
||||
* - First working version
|
||||
* 11/4/2000:
|
||||
* - FIXED: entirely white/black rows were missed.
|
||||
* 11/8/2000:
|
||||
* - TESTED: Glyphs are rendered correctly in different byte orders.
|
||||
* - Made bitmap code much more efficient and compact.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
#define PK_ID 89
|
||||
#define PK_CMD_START 240
|
||||
#define PK_X1 240
|
||||
#define PK_X2 241
|
||||
#define PK_X3 242
|
||||
#define PK_X4 243
|
||||
#define PK_Y 244
|
||||
#define PK_POST 245
|
||||
#define PK_NOOP 246
|
||||
#define PK_PRE 247
|
||||
|
||||
#define PK_DYN_F(x) (((x) >> 4) & 0xf)
|
||||
#define PK_PACKED(x) (PK_DYN_F(x) != 14)
|
||||
|
||||
static int pk_load_font __PROTO((DviParams *, DviFont *));
|
||||
static int pk_font_get_glyph __PROTO((DviParams *, DviFont *, int));
|
||||
|
||||
static int pk_auto_generate = 1; /* this is ON by default */
|
||||
|
||||
typedef struct {
|
||||
char currbyte;
|
||||
char nybpos;
|
||||
int dyn_f;
|
||||
} pkread;
|
||||
|
||||
static char *pk_lookup __PROTO((const char *, Ushort *, Ushort *));
|
||||
static char *pk_lookupn __PROTO((const char *, Ushort *, Ushort *));
|
||||
|
||||
/* only symbols exported by this file */
|
||||
DviFontInfo pk_font_info = {
|
||||
"PK",
|
||||
0, /* scaling not supported natively */
|
||||
pk_load_font,
|
||||
pk_font_get_glyph,
|
||||
mdvi_shrink_glyph,
|
||||
mdvi_shrink_glyph_grey,
|
||||
NULL, /* free */
|
||||
NULL, /* reset */
|
||||
pk_lookup, /* lookup */
|
||||
kpse_pk_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
DviFontInfo pkn_font_info = {
|
||||
"PKN",
|
||||
0, /* scaling not supported natively */
|
||||
pk_load_font,
|
||||
pk_font_get_glyph,
|
||||
mdvi_shrink_glyph,
|
||||
mdvi_shrink_glyph_grey,
|
||||
NULL, /* free */
|
||||
NULL, /* reset */
|
||||
pk_lookupn, /* lookup */
|
||||
kpse_pk_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi)
|
||||
{
|
||||
kpse_glyph_file_type type;
|
||||
char *filename;
|
||||
|
||||
if(pk_auto_generate == 0) {
|
||||
kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
|
||||
pk_auto_generate = 1;
|
||||
}
|
||||
filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
|
||||
kpse_pk_format, &type);
|
||||
if(filename && type.source == kpse_glyph_source_fallback) {
|
||||
mdvi_free(filename);
|
||||
filename = NULL;
|
||||
} else if(filename) {
|
||||
*hdpi = *vdpi = type.dpi;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
static char *pk_lookupn(const char *name, Ushort *hdpi, Ushort *vdpi)
|
||||
{
|
||||
kpse_glyph_file_type type;
|
||||
char *filename;
|
||||
|
||||
if(pk_auto_generate) {
|
||||
kpse_set_program_enabled(kpse_pk_format, 0, kpse_src_cmdline);
|
||||
pk_auto_generate = 0;
|
||||
}
|
||||
filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
|
||||
kpse_pk_format, &type);
|
||||
if(filename && type.source == kpse_glyph_source_fallback) {
|
||||
mdvi_free(filename);
|
||||
filename = NULL;
|
||||
} else if(filename) {
|
||||
*hdpi = *vdpi = type.dpi;
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
static inline int pk_get_nyb(FILE *p, pkread *pk)
|
||||
{
|
||||
unsigned t;
|
||||
int nb;
|
||||
char c;
|
||||
|
||||
t = c = pk->currbyte;
|
||||
nb = pk->nybpos;
|
||||
|
||||
switch(nb) {
|
||||
case 0:
|
||||
c = pk->currbyte = fuget1(p);
|
||||
t = (c >> 4);
|
||||
break;
|
||||
case 1:
|
||||
t = c;
|
||||
break;
|
||||
}
|
||||
pk->nybpos = !nb;
|
||||
return (t & 0xf);
|
||||
}
|
||||
|
||||
/*
|
||||
* this is a bit cumbersome because we have to pass around
|
||||
* the `pkread' data...
|
||||
*/
|
||||
static int pk_packed_num(FILE *p, pkread *pkr, int *repeat)
|
||||
{
|
||||
int i, j;
|
||||
int dyn_f = pkr->dyn_f;
|
||||
|
||||
i = pk_get_nyb(p, pkr);
|
||||
if(i == 0) {
|
||||
do {
|
||||
j = pk_get_nyb(p, pkr);
|
||||
i++;
|
||||
} while(j == 0);
|
||||
while(i-- > 0)
|
||||
j = (j << 4) + pk_get_nyb(p, pkr);
|
||||
return (j - 15 + ((13 - dyn_f) << 4) +
|
||||
dyn_f);
|
||||
} else if(i <= dyn_f)
|
||||
return i;
|
||||
else if(i < 14)
|
||||
return ((i - dyn_f - 1) << 4) +
|
||||
pk_get_nyb(p, pkr) + dyn_f + 1;
|
||||
else {
|
||||
*repeat = 1;
|
||||
if(i == 14)
|
||||
*repeat = pk_packed_num(p, pkr, repeat);
|
||||
return pk_packed_num(p, pkr, repeat);
|
||||
}
|
||||
}
|
||||
|
||||
#define ROUND(x,y) (((x) + (y) - 1) / (y))
|
||||
|
||||
static BITMAP *get_bitmap(FILE *p, int w, int h, int flags)
|
||||
{
|
||||
int i, j;
|
||||
BmUnit *ptr;
|
||||
BITMAP *bm;
|
||||
int bitpos;
|
||||
int currch;
|
||||
|
||||
flags = 0; /* shut up that compiler */
|
||||
bitpos = -1;
|
||||
if((bm = bitmap_alloc(w, h)) == NULL)
|
||||
return NULL;
|
||||
DEBUG((DBG_BITMAPS, "get_bitmap(%d,%d,%d): reading raw bitmap\n",
|
||||
w, h, flags));
|
||||
ptr = bm->data;
|
||||
currch = 0;
|
||||
for(i = 0; i < h; i++) {
|
||||
BmUnit mask;
|
||||
|
||||
mask = FIRSTMASK;
|
||||
for(j = 0; j < w; j++) {
|
||||
if(bitpos < 0) {
|
||||
currch = fuget1(p);
|
||||
bitpos = 7;
|
||||
}
|
||||
if(currch & (1 << bitpos))
|
||||
*ptr |= mask;
|
||||
bitpos--;
|
||||
if(mask == LASTMASK) {
|
||||
ptr++;
|
||||
mask = FIRSTMASK;
|
||||
} else
|
||||
NEXTMASK(mask);
|
||||
}
|
||||
ptr = bm_offset(ptr, bm->stride);
|
||||
}
|
||||
return bm;
|
||||
}
|
||||
|
||||
static BITMAP *get_packed(FILE *p, int w, int h, int flags)
|
||||
{
|
||||
int inrow, count;
|
||||
int row;
|
||||
BITMAP *bm;
|
||||
int repeat_count;
|
||||
int paint;
|
||||
pkread pkr;
|
||||
|
||||
pkr.nybpos = 0;
|
||||
pkr.currbyte = 0;
|
||||
pkr.dyn_f = PK_DYN_F(flags);
|
||||
paint = !!(flags & 0x8);
|
||||
|
||||
repeat_count = 0;
|
||||
row = 0;
|
||||
inrow = w;
|
||||
if((bm = bitmap_alloc(w, h)) == NULL)
|
||||
return NULL;
|
||||
DEBUG((DBG_BITMAPS, "get_packed(%d,%d,%d): reading packed glyph\n",
|
||||
w, h, flags));
|
||||
while(row < h) {
|
||||
int i = 0;
|
||||
|
||||
count = pk_packed_num(p, &pkr, &i);
|
||||
if(i > 0) {
|
||||
if(repeat_count)
|
||||
fprintf(stderr, "second repeat count for this row (had %d and got %d)\n",
|
||||
repeat_count, i);
|
||||
repeat_count = i;
|
||||
}
|
||||
|
||||
if(count >= inrow) {
|
||||
Uchar *r, *t;
|
||||
BmUnit *a, mask;
|
||||
|
||||
/* first finish current row */
|
||||
if(paint)
|
||||
bitmap_set_row(bm, row, w - inrow, inrow, paint);
|
||||
/* now copy it as many times as required */
|
||||
r = (Uchar *)bm->data + row * bm->stride;
|
||||
while(repeat_count-- > 0) {
|
||||
t = r + bm->stride;
|
||||
/* copy entire lines */
|
||||
memcpy(t, r, bm->stride);
|
||||
r = t;
|
||||
row++;
|
||||
}
|
||||
repeat_count = 0;
|
||||
/* count first row we drew */
|
||||
row++;
|
||||
/* update run count */
|
||||
count -= inrow;
|
||||
/* now r points to the beginning of the last row we finished */
|
||||
if(paint)
|
||||
mask = ~((BmUnit)0);
|
||||
else
|
||||
mask = 0;
|
||||
/* goto next row */
|
||||
a = (BmUnit *)(r + bm->stride);
|
||||
/* deal with entirely with/black rows */
|
||||
while(count >= w) {
|
||||
/* count number of atoms in a row */
|
||||
i = ROUND(w, BITMAP_BITS);
|
||||
while(i-- > 0)
|
||||
*a++ = mask;
|
||||
count -= w;
|
||||
row++;
|
||||
}
|
||||
inrow = w;
|
||||
}
|
||||
if(count > 0)
|
||||
bitmap_set_row(bm, row, w - inrow, count, paint);
|
||||
inrow -= count;
|
||||
paint = !paint;
|
||||
}
|
||||
if(row != h || inrow != w) {
|
||||
mdvi_error(_("Bad PK file: More bits than required\n"));
|
||||
bitmap_destroy(bm);
|
||||
return NULL;
|
||||
}
|
||||
return bm;
|
||||
}
|
||||
|
||||
static BITMAP *get_char(FILE *p, int w, int h, int flags)
|
||||
{
|
||||
/* check if dyn_f == 14 */
|
||||
if(((flags >> 4) & 0xf) == 14)
|
||||
return get_bitmap(p, w, h, flags);
|
||||
else
|
||||
return get_packed(p, w, h, flags);
|
||||
}
|
||||
|
||||
/* supports any number of characters in a font */
|
||||
static int pk_load_font(DviParams *unused, DviFont *font)
|
||||
{
|
||||
int i;
|
||||
int flag_byte;
|
||||
int hic, maxch;
|
||||
Int32 checksum;
|
||||
FILE *p;
|
||||
#ifndef NODEBUG
|
||||
char s[256];
|
||||
#endif
|
||||
long alpha, beta, z;
|
||||
unsigned int loc;
|
||||
|
||||
font->chars = xnalloc(DviFontChar, 256);
|
||||
p = font->in;
|
||||
memzero(font->chars, 256 * sizeof(DviFontChar));
|
||||
for(i = 0; i < 256; i++)
|
||||
font->chars[i].offset = 0;
|
||||
|
||||
/* check the preamble */
|
||||
loc = fuget1(p); hic = fuget1(p);
|
||||
if(loc != PK_PRE || hic != PK_ID)
|
||||
goto badpk;
|
||||
i = fuget1(p);
|
||||
#ifndef NODEBUG
|
||||
for(loc = 0; loc < i; loc++)
|
||||
s[loc] = fuget1(p);
|
||||
s[loc] = 0;
|
||||
DEBUG((DBG_FONTS, "(pk) %s: %s\n", font->fontname, s));
|
||||
#else
|
||||
fseek(in, (long)i, SEEK_CUR);
|
||||
#endif
|
||||
/* get the design size */
|
||||
font->design = fuget4(p);
|
||||
/* get the checksum */
|
||||
checksum = fuget4(p);
|
||||
if(checksum && font->checksum && font->checksum != checksum) {
|
||||
mdvi_warning(_("%s: checksum mismatch (expected %u, got %u)\n"),
|
||||
font->fontname, font->checksum, checksum);
|
||||
} else if(!font->checksum)
|
||||
font->checksum = checksum;
|
||||
/* skip pixel per point ratios */
|
||||
fuget4(p);
|
||||
fuget4(p);
|
||||
if(feof(p))
|
||||
goto badpk;
|
||||
|
||||
/* now start reading the font */
|
||||
loc = 256; hic = -1; maxch = 256;
|
||||
|
||||
/* initialize alpha and beta for TFM width computation */
|
||||
TFMPREPARE(font->scale, z, alpha, beta);
|
||||
|
||||
while((flag_byte = fuget1(p)) != PK_POST) {
|
||||
if(feof(p))
|
||||
break;
|
||||
if(flag_byte >= PK_CMD_START) {
|
||||
switch(flag_byte) {
|
||||
case PK_X1:
|
||||
case PK_X2:
|
||||
case PK_X3:
|
||||
case PK_X4: {
|
||||
#ifndef NODEBUG
|
||||
char *t;
|
||||
int n;
|
||||
|
||||
i = fugetn(p, flag_byte - PK_X1 + 1);
|
||||
if(i < 256)
|
||||
t = &s[0];
|
||||
else
|
||||
t = mdvi_malloc(i + 1);
|
||||
for(n = 0; n < i; n++)
|
||||
t[n] = fuget1(p);
|
||||
t[n] = 0;
|
||||
DEBUG((DBG_SPECIAL, "(pk) %s: Special \"%s\"\n",
|
||||
font->fontname, t));
|
||||
if(t != &s[0])
|
||||
mdvi_free(t);
|
||||
#else
|
||||
i = fugetn(p, flag_byte - PK_X1 + 1);
|
||||
while(i-- > 0)
|
||||
fuget1(p);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case PK_Y:
|
||||
i = fuget4(p);
|
||||
DEBUG((DBG_SPECIAL, "(pk) %s: MF special %u\n",
|
||||
font->fontname, (unsigned)i));
|
||||
break;
|
||||
case PK_POST:
|
||||
case PK_NOOP:
|
||||
break;
|
||||
case PK_PRE:
|
||||
mdvi_error(_("%s: unexpected preamble\n"), font->fontname);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
int pl;
|
||||
int cc;
|
||||
int w, h;
|
||||
int x, y;
|
||||
int offset;
|
||||
long tfm;
|
||||
|
||||
switch(flag_byte & 0x7) {
|
||||
case 7:
|
||||
pl = fuget4(p);
|
||||
cc = fuget4(p);
|
||||
offset = ftell(p) + pl;
|
||||
tfm = fuget4(p);
|
||||
fsget4(p); /* skip dx */
|
||||
fsget4(p); /* skip dy */
|
||||
w = fuget4(p);
|
||||
h = fuget4(p);
|
||||
x = fsget4(p);
|
||||
y = fsget4(p);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
pl = (flag_byte % 4) * 65536 + fuget2(p);
|
||||
cc = fuget1(p);
|
||||
offset = ftell(p) + pl;
|
||||
tfm = fuget3(p);
|
||||
fsget2(p); /* skip dx */
|
||||
/* dy assumed 0 */
|
||||
w = fuget2(p);
|
||||
h = fuget2(p);
|
||||
x = fsget2(p);
|
||||
y = fsget2(p);
|
||||
break;
|
||||
default:
|
||||
pl = (flag_byte % 4) * 256 + fuget1(p);
|
||||
cc = fuget1(p);
|
||||
offset = ftell(p) + pl;
|
||||
tfm = fuget3(p);
|
||||
fsget1(p); /* skip dx */
|
||||
/* dy assumed 0 */
|
||||
w = fuget1(p);
|
||||
h = fuget1(p);
|
||||
x = fsget1(p);
|
||||
y = fsget1(p);
|
||||
}
|
||||
if(feof(p))
|
||||
break;
|
||||
|
||||
/* Although the PK format support bigger char codes,
|
||||
* XeTeX and other extended TeX engines support charcodes up to
|
||||
* 65536, while normal TeX engine supports only charcode up to 255.*/
|
||||
if (cc < 0 || cc > 65536) {
|
||||
mdvi_error (_("%s: unexpected charcode (%d)\n"),
|
||||
font->fontname,cc);
|
||||
goto error;
|
||||
}
|
||||
if(cc < loc)
|
||||
loc = cc;
|
||||
if(cc > hic)
|
||||
hic = cc;
|
||||
if(cc > maxch) {
|
||||
font->chars = xresize(font->chars,
|
||||
DviFontChar, cc + 16);
|
||||
for(i = maxch; i < cc + 16; i++)
|
||||
font->chars[i].offset = 0;
|
||||
maxch = cc + 16;
|
||||
}
|
||||
font->chars[cc].code = cc;
|
||||
font->chars[cc].flags = flag_byte;
|
||||
font->chars[cc].offset = ftell(p);
|
||||
font->chars[cc].width = w;
|
||||
font->chars[cc].height = h;
|
||||
font->chars[cc].glyph.data = NULL;
|
||||
font->chars[cc].x = x;
|
||||
font->chars[cc].y = y;
|
||||
font->chars[cc].glyph.x = x;
|
||||
font->chars[cc].glyph.y = y;
|
||||
font->chars[cc].glyph.w = w;
|
||||
font->chars[cc].glyph.h = h;
|
||||
font->chars[cc].grey.data = NULL;
|
||||
font->chars[cc].shrunk.data = NULL;
|
||||
font->chars[cc].tfmwidth = TFMSCALE(z, tfm, alpha, beta);
|
||||
font->chars[cc].loaded = 0;
|
||||
fseek(p, (long)offset, SEEK_SET);
|
||||
}
|
||||
}
|
||||
if(flag_byte != PK_POST) {
|
||||
mdvi_error(_("%s: unexpected end of file (no postamble)\n"),
|
||||
font->fontname);
|
||||
goto error;
|
||||
}
|
||||
while((flag_byte = fuget1(p)) != EOF) {
|
||||
if(flag_byte != PK_NOOP) {
|
||||
mdvi_error(_("invalid PK file! (junk in postamble)\n"));
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
/* resize font char data */
|
||||
if(loc > 0 || hic < maxch-1) {
|
||||
memmove(font->chars, font->chars + loc,
|
||||
(hic - loc + 1) * sizeof(DviFontChar));
|
||||
font->chars = xresize(font->chars,
|
||||
DviFontChar, hic - loc + 1);
|
||||
}
|
||||
font->loc = loc;
|
||||
font->hic = hic;
|
||||
return 0;
|
||||
|
||||
badpk:
|
||||
mdvi_error(_("%s: File corrupted, or not a PK file\n"), font->fontname);
|
||||
error:
|
||||
mdvi_free(font->chars);
|
||||
font->chars = NULL;
|
||||
font->loc = font->hic = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int pk_font_get_glyph(DviParams *params, DviFont *font, int code)
|
||||
{
|
||||
DviFontChar *ch;
|
||||
|
||||
if((ch = FONTCHAR(font, code)) == NULL)
|
||||
return -1;
|
||||
|
||||
if(ch->offset == 0)
|
||||
return -1;
|
||||
DEBUG((DBG_GLYPHS, "(pk) loading glyph for character %d (%dx%d) in font `%s'\n",
|
||||
code, ch->width, ch->height, font->fontname));
|
||||
if(font->in == NULL && font_reopen(font) < 0)
|
||||
return -1;
|
||||
if(!ch->width || !ch->height) {
|
||||
/* this happens for ` ' (ASCII 32) in some fonts */
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
ch->glyph.data = NULL;
|
||||
return 0;
|
||||
}
|
||||
if(fseek(font->in, ch->offset, SEEK_SET) == -1)
|
||||
return -1;
|
||||
ch->glyph.data = get_char(font->in,
|
||||
ch->width, ch->height, ch->flags);
|
||||
if(ch->glyph.data) {
|
||||
/* restore original settings */
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
} else
|
||||
return -1;
|
||||
ch->loaded = 1;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _MDVI_PRIVATE_H
|
||||
#define _MDVI_PRIVATE_H 1
|
||||
|
||||
#define HAVE_PROTOTYPES 1
|
||||
|
||||
#if STDC_HEADERS
|
||||
# /* kpathsea's headers (wrongly!) redefine strchr() and strrchr() to
|
||||
# non ANSI C functions if HAVE_STRCHR and HAVE_STRRCHR are not defined.
|
||||
# */
|
||||
# ifndef HAVE_STRCHR
|
||||
# define HAVE_STRCHR
|
||||
# endif
|
||||
# ifndef HAVE_STRRCHR
|
||||
# define HAVE_STRRCHR
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <kpathsea/debug.h>
|
||||
#include <kpathsea/tex-file.h>
|
||||
#include <kpathsea/tex-glyph.h>
|
||||
#include <kpathsea/cnf.h>
|
||||
#include <kpathsea/proginit.h>
|
||||
#include <kpathsea/progname.h>
|
||||
#include <kpathsea/tex-make.h>
|
||||
#include <kpathsea/lib.h>
|
||||
|
||||
#define ISSP(p) (*(p) == ' ' || *(p) == '\t')
|
||||
#define SKIPSP(p) while(ISSP(p)) p++
|
||||
#define SKIPNSP(p) while(*(p) && !ISSP(p)) p++
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
#include <libintl.h>
|
||||
#define _(x) gettext(x)
|
||||
#define _G(x) x
|
||||
#else
|
||||
#define _(x) x
|
||||
#define _G(x) x
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2
|
||||
#define _BREAKPOINT() do { __asm__ __volatile__ ("int $03"); } while(0)
|
||||
#elif defined (__alpha__) && defined (__GNUC__) && __GNUC__ >= 2
|
||||
#define _BREAKPOINT() do { __asm__ __volatile__ ("bpt"); } while(0)
|
||||
#else /* !__i386__ && !__alpha__ */
|
||||
#define _BREAKPOINT()
|
||||
#endif /* __i386__ */
|
||||
|
||||
#endif /* _MDVI_PRIVATE_H */
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
void mdvi_init_kpathsea(const char *program,
|
||||
const char *mfmode, const char *font, int dpi,
|
||||
const char *texmfcnf)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
/* Stop meaningless output generation. */
|
||||
kpse_make_tex_discard_errors = FALSE;
|
||||
|
||||
p = strrchr(program, '/');
|
||||
p = (p ? p + 1 : program);
|
||||
kpse_set_program_name(program, p);
|
||||
kpse_init_prog(p, dpi, mfmode, font);
|
||||
kpse_set_program_enabled(kpse_any_glyph_format, 1, kpse_src_compile);
|
||||
kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_compile);
|
||||
kpse_set_program_enabled(kpse_tfm_format, 1, kpse_src_compile);
|
||||
kpse_set_program_enabled(kpse_ofm_format, 1, kpse_src_compile);
|
||||
if (texmfcnf != NULL)
|
||||
xputenv("TEXMFCNF", texmfcnf);
|
||||
}
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* postscript specials */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
typedef struct {
|
||||
double ox;
|
||||
double oy;
|
||||
double bw;
|
||||
double bh;
|
||||
double angle;
|
||||
} EpsfBox;
|
||||
|
||||
#define LLX 0
|
||||
#define LLY 1
|
||||
#define URX 2
|
||||
#define URY 3
|
||||
#define RWI 4
|
||||
#define RHI 5
|
||||
#define HOFF 6
|
||||
#define VOFF 7
|
||||
#define HSIZE 8
|
||||
#define VSIZE 9
|
||||
#define HSCALE 10
|
||||
#define VSCALE 11
|
||||
#define ANGLE 12
|
||||
#define CLIP 13
|
||||
|
||||
void epsf_special __PROTO((DviContext *dvi, char *prefix, char *arg));
|
||||
|
||||
/* Note: the given strings are modified in place */
|
||||
static char *parse_epsf_special(EpsfBox *box, char **ret,
|
||||
char *prefix, char *arg)
|
||||
{
|
||||
static struct {
|
||||
char *name;
|
||||
int has_arg;
|
||||
char *value;
|
||||
} keys[] = {
|
||||
{"llx", 1, "0"},
|
||||
{"lly", 1, "0"},
|
||||
{"urx", 1, "0"},
|
||||
{"ury", 1, "0"},
|
||||
{"rwi", 1, "0"},
|
||||
{"rhi", 1, "0"},
|
||||
{"hoffset", 1, "0"},
|
||||
{"voffset", 1, "0"},
|
||||
{"hsize", 1, "612"},
|
||||
{"vsize", 1, "792"},
|
||||
{"hscale", 1, "100"},
|
||||
{"vscale", 1, "100"},
|
||||
{"angle", 1, "0"},
|
||||
{"clip", 0, "0"}
|
||||
};
|
||||
#define NKEYS (sizeof(keys) / sizeof(keys[0]))
|
||||
char *ptr;
|
||||
char *filename;
|
||||
double value[NKEYS];
|
||||
Uchar present[NKEYS];
|
||||
Buffer buffer;
|
||||
char *name;
|
||||
int i;
|
||||
double originx;
|
||||
double originy;
|
||||
double hsize;
|
||||
double vsize;
|
||||
double hscale;
|
||||
double vscale;
|
||||
|
||||
/* this special has the form
|
||||
* ["]file.ps["] [key=valye]*
|
||||
*/
|
||||
|
||||
/* scan the filename */
|
||||
while(*arg == ' ' || *arg == '\t')
|
||||
arg++;
|
||||
|
||||
/* make a copy of the string */
|
||||
ptr = arg;
|
||||
|
||||
if(*ptr == '"')
|
||||
for(name = ++ptr; *ptr && *ptr != '"'; ptr++);
|
||||
else
|
||||
for(name = ptr; *ptr && *ptr != ' ' && *ptr != '\t'; ptr++);
|
||||
if(ptr == name)
|
||||
return NULL;
|
||||
*ptr++ = 0;
|
||||
filename = name;
|
||||
|
||||
/* reset values to defaults */
|
||||
for(i = 0; i < NKEYS; i++) {
|
||||
value[i] = atof(keys[i].value);
|
||||
present[i] = 0;
|
||||
}
|
||||
|
||||
buff_init(&buffer);
|
||||
buff_add(&buffer, "@beginspecial ", 0);
|
||||
|
||||
while(*ptr) {
|
||||
const char *keyname;
|
||||
char *val;
|
||||
char *p;
|
||||
|
||||
while(*ptr == ' ' || *ptr == '\t')
|
||||
ptr++;
|
||||
keyname = ptr;
|
||||
|
||||
/* get the whole key=value pair */
|
||||
for(; *ptr && *ptr != ' ' && *ptr != '\t'; ptr++);
|
||||
|
||||
if(*ptr) *ptr++ = 0;
|
||||
/* now we shouldn't touch `ptr' anymore */
|
||||
|
||||
/* now work on this pair */
|
||||
p = strchr(keyname, '=');
|
||||
if(p == NULL)
|
||||
val = NULL;
|
||||
else {
|
||||
*p++ = 0;
|
||||
if(*p == '"') {
|
||||
val = ++p;
|
||||
/* skip until closing quote */
|
||||
while(*p && *p != '"')
|
||||
p++;
|
||||
if(*p != '"')
|
||||
mdvi_warning(
|
||||
_("%s: malformed value for key `%s'\n"),
|
||||
filename, keyname);
|
||||
} else
|
||||
val = p;
|
||||
}
|
||||
|
||||
/* lookup the key */
|
||||
for(i = 0; i < NKEYS; i++)
|
||||
if(STRCEQ(keys[i].name, keyname))
|
||||
break;
|
||||
if(i == NKEYS) {
|
||||
mdvi_warning(_("%s: unknown key `%s' ignored\n"),
|
||||
filename, keyname);
|
||||
continue;
|
||||
}
|
||||
if(keys[i].has_arg && val == NULL) {
|
||||
mdvi_warning(_("%s: no argument for key `%s', using defaults\n"),
|
||||
filename, keyname);
|
||||
val = keys[i].value;
|
||||
} else if(!keys[i].has_arg && val) {
|
||||
mdvi_warning(_("%s: argument `%s' ignored for key `%s'\n"),
|
||||
filename, val, keyname);
|
||||
val = NULL;
|
||||
}
|
||||
if(val)
|
||||
value[i] = atof(val);
|
||||
|
||||
/* put the argument */
|
||||
buff_add(&buffer, val, 0);
|
||||
buff_add(&buffer, " @", 2);
|
||||
buff_add(&buffer, keyname, 0);
|
||||
buff_add(&buffer, " ", 1);
|
||||
|
||||
/* remember that this option was given */
|
||||
present[i] = 0xff;
|
||||
}
|
||||
buff_add(&buffer, " @setspecial", 0);
|
||||
|
||||
/* now compute the bounding box (code comes from dvips) */
|
||||
originx = 0;
|
||||
originy = 0;
|
||||
hscale = 1;
|
||||
vscale = 1;
|
||||
hsize = 0;
|
||||
vsize = 0;
|
||||
|
||||
if(present[HSIZE])
|
||||
hsize = value[HSIZE];
|
||||
if(present[VSIZE])
|
||||
vsize = value[VSIZE];
|
||||
if(present[HOFF])
|
||||
originx = value[HOFF];
|
||||
if(present[VOFF])
|
||||
originy = value[VOFF];
|
||||
if(present[HSCALE])
|
||||
hscale = value[HSCALE] / 100.0;
|
||||
if(present[VSCALE])
|
||||
vscale = value[VSCALE] / 100.0;
|
||||
if(present[URX] && present[LLX])
|
||||
hsize = value[URX] - value[LLX];
|
||||
if(present[URY] && present[LLY])
|
||||
vsize = value[URY] - value[LLY];
|
||||
if(present[RWI] || present[RHI]) {
|
||||
if(present[RWI] && !present[RHI])
|
||||
hscale = vscale = value[RWI] / (10.0 * hsize);
|
||||
else if(present[RHI] && !present[RWI])
|
||||
hscale = vscale = value[RHI] / (10.0 * vsize);
|
||||
else {
|
||||
hscale = value[RWI] / (10.0 * hsize);
|
||||
vscale = value[RHI] / (10.0 * vsize);
|
||||
}
|
||||
}
|
||||
|
||||
box->ox = originx;
|
||||
box->oy = originy;
|
||||
box->bw = hsize * hscale;
|
||||
box->bh = vsize * vscale;
|
||||
box->angle = value[ANGLE];
|
||||
|
||||
*ret = buffer.data;
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
void epsf_special(DviContext *dvi, char *prefix, char *arg)
|
||||
{
|
||||
char *file;
|
||||
char *special;
|
||||
char *psfile;
|
||||
char *tmp;
|
||||
EpsfBox box = {0, 0, 0, 0};
|
||||
int x, y;
|
||||
int w, h;
|
||||
double xf, vf;
|
||||
struct stat buf;
|
||||
|
||||
file = parse_epsf_special(&box, &special, prefix, arg);
|
||||
if (file != NULL)
|
||||
mdvi_free (special);
|
||||
|
||||
xf = dvi->params.dpi * dvi->params.mag / (72.0 * dvi->params.hshrink);
|
||||
vf = dvi->params.vdpi * dvi->params.mag / (72.0 * dvi->params.vshrink);
|
||||
w = FROUND(box.bw * xf);
|
||||
h = FROUND(box.bh * vf);
|
||||
x = FROUND(box.ox * xf) + dvi->pos.hh;
|
||||
y = FROUND(box.oy * vf) + dvi->pos.vv - h + 1;
|
||||
|
||||
if (!file || !dvi->device.draw_ps) {
|
||||
dvi->device.draw_rule (dvi, x, y, w, h, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file[0] == '/') { /* Absolute path */
|
||||
if (stat (file, &buf) == 0)
|
||||
dvi->device.draw_ps (dvi, file, x, y, w, h);
|
||||
else
|
||||
dvi->device.draw_rule (dvi, x, y, w, h, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
tmp = mdvi_strrstr (dvi->filename, "/");
|
||||
if (tmp) { /* Document directory */
|
||||
int path_len = strlen (dvi->filename) - strlen (tmp + 1);
|
||||
int file_len = strlen (file);
|
||||
|
||||
psfile = mdvi_malloc (path_len + file_len + 1);
|
||||
psfile[0] = '\0';
|
||||
strncat (psfile, dvi->filename, path_len);
|
||||
strncat (psfile, file, file_len);
|
||||
|
||||
if (stat (psfile, &buf) == 0) {
|
||||
dvi->device.draw_ps (dvi, psfile, x, y, w, h);
|
||||
mdvi_free (psfile);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mdvi_free (psfile);
|
||||
}
|
||||
|
||||
psfile = mdvi_build_path_from_cwd (file);
|
||||
if (stat (psfile, &buf) == 0) { /* Current working dir */
|
||||
dvi->device.draw_ps (dvi, psfile, x, y, w, h);
|
||||
mdvi_free (psfile);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mdvi_free (psfile);
|
||||
|
||||
psfile = kpse_find_pict (file);
|
||||
if (psfile) { /* kpse */
|
||||
dvi->device.draw_ps (dvi, psfile, x, y, w, h);
|
||||
} else {
|
||||
dvi->device.draw_rule(dvi, x, y, w, h, 0);
|
||||
}
|
||||
|
||||
free (psfile);
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
#if defined(WITH_REGEX_SPECIALS) && defined(HAVE_REGEX_H)
|
||||
#include <regex.h>
|
||||
#endif
|
||||
|
||||
typedef struct _DviSpecial {
|
||||
struct _DviSpecial *next;
|
||||
struct _DviSpecial *prev;
|
||||
char *label;
|
||||
char *prefix;
|
||||
size_t plen;
|
||||
#ifdef WITH_REGEX_SPECIALS
|
||||
regex_t reg;
|
||||
int has_reg;
|
||||
#endif
|
||||
DviSpecialHandler handler;
|
||||
} DviSpecial;
|
||||
|
||||
static ListHead specials = {NULL, NULL, 0};
|
||||
|
||||
#define SPECIAL(x) \
|
||||
void x __PROTO((DviContext *, const char *, const char *))
|
||||
|
||||
static SPECIAL(sp_layer);
|
||||
extern SPECIAL(epsf_special);
|
||||
extern SPECIAL(do_color_special);
|
||||
|
||||
static struct {
|
||||
char *label;
|
||||
char *prefix;
|
||||
char *regex;
|
||||
DviSpecialHandler handler;
|
||||
} builtins[] = {
|
||||
{"Layers", "layer", NULL, sp_layer},
|
||||
{"EPSF", "psfile", NULL, epsf_special}
|
||||
};
|
||||
#define NSPECIALS (sizeof(builtins) / sizeof(builtins[0]))
|
||||
static int registered_builtins = 0;
|
||||
|
||||
static void register_builtin_specials(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ASSERT(registered_builtins == 0);
|
||||
registered_builtins = 1;
|
||||
for(i = 0; i < NSPECIALS; i++)
|
||||
mdvi_register_special(
|
||||
builtins[i].label,
|
||||
builtins[i].prefix,
|
||||
builtins[i].regex,
|
||||
builtins[i].handler,
|
||||
1 /* replace if exists */);
|
||||
}
|
||||
|
||||
static DviSpecial *find_special_prefix(const char *prefix)
|
||||
{
|
||||
DviSpecial *sp;
|
||||
|
||||
/* should have a hash table here, but I'm so lazy */
|
||||
for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
|
||||
if(STRCEQ(sp->prefix, prefix))
|
||||
break;
|
||||
}
|
||||
return sp;
|
||||
}
|
||||
|
||||
int mdvi_register_special(const char *label, const char *prefix,
|
||||
const char *regex, DviSpecialHandler handler, int replace)
|
||||
{
|
||||
DviSpecial *sp;
|
||||
int newsp = 0;
|
||||
|
||||
if(!registered_builtins)
|
||||
register_builtin_specials();
|
||||
|
||||
sp = find_special_prefix(prefix);
|
||||
if(sp == NULL) {
|
||||
sp = xalloc(DviSpecial);
|
||||
sp->prefix = mdvi_strdup(prefix);
|
||||
newsp = 1;
|
||||
} else if(!replace)
|
||||
return -1;
|
||||
else {
|
||||
mdvi_free(sp->label);
|
||||
sp->label = NULL;
|
||||
}
|
||||
|
||||
#ifdef WITH_REGEX_SPECIALS
|
||||
if(!newsp && sp->has_reg) {
|
||||
regfree(&sp->reg);
|
||||
sp->has_reg = 0;
|
||||
}
|
||||
if(regex && regcomp(&sp->reg, regex, REG_NOSUB) != 0) {
|
||||
if(newsp) {
|
||||
mdvi_free(sp->prefix);
|
||||
mdvi_free(sp);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
sp->has_reg = (regex != NULL);
|
||||
#endif
|
||||
sp->handler = handler;
|
||||
sp->label = mdvi_strdup(label);
|
||||
sp->plen = strlen(prefix);
|
||||
if(newsp)
|
||||
listh_prepend(&specials, LIST(sp));
|
||||
DEBUG((DBG_SPECIAL,
|
||||
"New \\special handler `%s' with prefix `%s'\n",
|
||||
label, prefix));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdvi_unregister_special(const char *prefix)
|
||||
{
|
||||
DviSpecial *sp;
|
||||
|
||||
sp = find_special_prefix(prefix);
|
||||
if(sp == NULL)
|
||||
return -1;
|
||||
mdvi_free(sp->prefix);
|
||||
#ifdef WITH_REGEX_SPECIALS
|
||||
if(sp->has_reg)
|
||||
regfree(&sp->reg);
|
||||
#endif
|
||||
listh_remove(&specials, LIST(sp));
|
||||
mdvi_free(sp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define IS_PREFIX_DELIMITER(x) (strchr(" \t\n:=", (x)) != NULL)
|
||||
|
||||
int mdvi_do_special(DviContext *dvi, char *string)
|
||||
{
|
||||
char *prefix;
|
||||
char *ptr;
|
||||
DviSpecial *sp;
|
||||
|
||||
if(!registered_builtins) {
|
||||
}
|
||||
|
||||
if(!string || !*string)
|
||||
return 0;
|
||||
|
||||
/* skip leading spaces */
|
||||
while(*string && isspace(*string))
|
||||
string++;
|
||||
|
||||
DEBUG((DBG_SPECIAL, "Looking for a handler for `%s'\n", string));
|
||||
|
||||
/* now try to find a match */
|
||||
ptr = string;
|
||||
for(sp = (DviSpecial *)specials.head; sp; sp = sp->next) {
|
||||
#ifdef WITH_REGEX_SPECIALS
|
||||
if(sp->has_reg && !regexec(&sp->reg, ptr, 0, 0, 0))
|
||||
break;
|
||||
#endif
|
||||
/* check the prefix */
|
||||
if(STRNCEQ(sp->prefix, ptr, sp->plen)) {
|
||||
ptr += sp->plen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(sp == NULL) {
|
||||
DEBUG((DBG_SPECIAL, "None found\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* extract the prefix */
|
||||
if(ptr == string) {
|
||||
prefix = NULL;
|
||||
DEBUG((DBG_SPECIAL,
|
||||
"REGEX match with `%s' (arg `%s')\n",
|
||||
sp->label, ptr));
|
||||
} else {
|
||||
if(*ptr) *ptr++ = 0;
|
||||
prefix = string;
|
||||
DEBUG((DBG_SPECIAL,
|
||||
"PREFIX match with `%s' (prefix `%s', arg `%s')\n",
|
||||
sp->label, prefix, ptr));
|
||||
}
|
||||
|
||||
/* invoke the handler */
|
||||
sp->handler(dvi, prefix, ptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mdvi_flush_specials(void)
|
||||
{
|
||||
DviSpecial *sp, *list;
|
||||
|
||||
|
||||
for(list = (DviSpecial *)specials.head; (sp = list); ) {
|
||||
list = sp->next;
|
||||
if(sp->prefix) mdvi_free(sp->prefix);
|
||||
if(sp->label) mdvi_free(sp->label);
|
||||
#ifdef WITH_REGEX_SPECIALS
|
||||
if(sp->has_reg)
|
||||
regfree(&sp->reg);
|
||||
#endif
|
||||
mdvi_free(sp);
|
||||
}
|
||||
specials.head = NULL;
|
||||
specials.tail = NULL;
|
||||
specials.count = 0;
|
||||
}
|
||||
|
||||
/* some builtin specials */
|
||||
|
||||
void sp_layer(DviContext *dvi, const char *prefix, const char *arg)
|
||||
{
|
||||
if(STREQ("push", arg))
|
||||
dvi->curr_layer++;
|
||||
else if(STREQ("pop", arg)) {
|
||||
if(dvi->curr_layer)
|
||||
dvi->curr_layer--;
|
||||
else
|
||||
mdvi_warning(_("%s: tried to pop top level layer\n"),
|
||||
dvi->filename);
|
||||
} else if(STREQ("reset", arg))
|
||||
dvi->curr_layer = 0;
|
||||
DEBUG((DBG_SPECIAL, "Layer level: %d\n", dvi->curr_layer));
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef _SYSDEP_H
|
||||
#define _SYSDEP_H 1
|
||||
|
||||
/*
|
||||
* The purpose of this file is to define symbols that describe the
|
||||
* system-dependent features we use. Namely, byte order, native integer
|
||||
* types of various sizes, and safe pointer<->integer conversion.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define WORD_BIG_ENDIAN 1
|
||||
#else
|
||||
#define WORD_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
|
||||
typedef unsigned long Ulong;
|
||||
typedef unsigned int Uint;
|
||||
typedef unsigned short Ushort;
|
||||
typedef unsigned char Uchar;
|
||||
|
||||
/* this one's easy */
|
||||
typedef unsigned char Uint8;
|
||||
typedef char Int8;
|
||||
|
||||
/* define a datatype for 32bit integers (either int or long) */
|
||||
#if SIZEOF_LONG == 4
|
||||
typedef unsigned long Uint32;
|
||||
typedef long Int32;
|
||||
#else /* SIZEOF_LONG != 4 */
|
||||
#if SIZEOF_INT == 4
|
||||
typedef unsigned int Uint32;
|
||||
typedef int Int32;
|
||||
#else /* SIZEOF_INT != 4 */
|
||||
#ifdef __cplusplus
|
||||
#include "No.appropriate.32bit.native.type.found.Fix.sysdeps.h"
|
||||
#else
|
||||
#error No appropriate 32bit native type found. Fix sysdeps.h
|
||||
#endif /* ! __cplusplus */
|
||||
#endif /* SIZEOF_INT != 4 */
|
||||
#endif /* SIZEOF_LONG != 4 */
|
||||
|
||||
/* now 16bit integers (one of long, int or short) */
|
||||
#if SIZEOF_SHORT == 2
|
||||
typedef unsigned short Uint16;
|
||||
typedef short Int16;
|
||||
#else /* SIZEOF_SHORT != 2 */
|
||||
#if SIZEOF_INT == 2
|
||||
typedef unsigned int Uint16;
|
||||
typedef short Int16;
|
||||
#else /* SIZEOF_INT != 2 */
|
||||
#ifdef __cplusplus
|
||||
#include "No.appropriate.16bit.native.type.found.Fix.sysdeps.h"
|
||||
#else
|
||||
#error No appropriate 16bit native type found. Fix sysdeps.h
|
||||
#endif /* ! __cplusplus */
|
||||
#endif /* SIZEOF_INT != 2 */
|
||||
#endif /* SIZEOF_SHORT != 2 */
|
||||
|
||||
/*
|
||||
* An integer type to convert to and from pointers safely. All we do here is
|
||||
* look for an integer type with the same size as a pointer.
|
||||
*/
|
||||
#if SIZEOF_LONG == SIZEOF_VOID_P
|
||||
typedef unsigned long UINT;
|
||||
typedef long INT;
|
||||
#else
|
||||
#if SIZEOF_INT == SIZEOF_VOID_P
|
||||
typedef unsigned int UINT;
|
||||
typedef int INT;
|
||||
#else
|
||||
#if SIZEOF_SHORT == SIZEOF_VOID_P
|
||||
typedef unsigned short UINT;
|
||||
typedef short INT;
|
||||
#else
|
||||
#ifdef __cplusplus
|
||||
#include "No.native.pointer-compatible.integer.type.found.Fix.sysdeps.h"
|
||||
#else
|
||||
#error No native pointer-compatible integer type found. Fix sysdeps.h
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* nice, uh? */
|
||||
typedef void *Pointer;
|
||||
|
||||
/* macros to do the safe pointer <-> integer conversions */
|
||||
#define Ptr2Int(x) ((INT)((Pointer)(x)))
|
||||
#define Int2Ptr(x) ((Pointer)((INT)(x)))
|
||||
|
||||
#ifdef _NO_PROTO
|
||||
#define __PROTO(x) ()
|
||||
#else
|
||||
#define __PROTO(x) x
|
||||
#endif
|
||||
|
||||
#endif /* _SYSDEP_H */
|
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Type1 font support for MDVI
|
||||
*
|
||||
* We use T1lib only as a rasterizer, not to draw glyphs.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "mdvi.h"
|
||||
|
||||
#ifdef WITH_TYPE1_FONTS
|
||||
|
||||
#include <stdio.h>
|
||||
#include <t1lib.h>
|
||||
#include "private.h"
|
||||
|
||||
static int t1lib_initialized = 0;
|
||||
|
||||
typedef struct t1info {
|
||||
struct t1info *next;
|
||||
struct t1info *prev;
|
||||
char *fontname; /* (short) name of this font */
|
||||
int t1id; /* T1lib's id for this font */
|
||||
int hasmetrics; /* have we processed this font? */
|
||||
TFMInfo *tfminfo; /* TFM data is shared */
|
||||
DviFontMapInfo mapinfo;
|
||||
DviEncoding *encoding;
|
||||
} T1Info;
|
||||
|
||||
static void t1_font_remove __PROTO((T1Info *));
|
||||
static int t1_load_font __PROTO((DviParams *, DviFont *));
|
||||
static int t1_font_get_glyph __PROTO((DviParams *, DviFont *, int));
|
||||
static void t1_font_shrink_glyph
|
||||
__PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
|
||||
static void t1_free_data __PROTO((DviFont *));
|
||||
static void t1_reset_font __PROTO((DviFont *));
|
||||
static char *t1_lookup_font __PROTO((const char *, Ushort *, Ushort *));
|
||||
|
||||
/* only symbol exported by this file */
|
||||
DviFontInfo t1_font_info = {
|
||||
"Type1",
|
||||
1, /* scaling supported by format */
|
||||
t1_load_font,
|
||||
t1_font_get_glyph,
|
||||
t1_font_shrink_glyph,
|
||||
mdvi_shrink_glyph_grey,
|
||||
t1_free_data,
|
||||
t1_reset_font,
|
||||
t1_lookup_font, /* lookup */
|
||||
kpse_type1_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* this seems good enough for most DVI files */
|
||||
#define T1_HASH_SIZE 31
|
||||
|
||||
/* If these parameters change, we must delete all size information
|
||||
* in all fonts, and reset the device resolutions in T1lib */
|
||||
static int t1lib_xdpi = -1;
|
||||
static int t1lib_ydpi = -1;
|
||||
|
||||
static ListHead t1fonts = {NULL, NULL, 0};
|
||||
static DviHashTable t1hash;
|
||||
|
||||
/* Type1 fonts need their own `lookup' function. Here is how it works:
|
||||
* First we try to find the font by its given name. If that fails, we
|
||||
* query the font maps. A typical font map entry may contain the line
|
||||
*
|
||||
* ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc <ptmr
|
||||
*
|
||||
* which means: If you're looking for the font `ptmr8rn' load `Times-Roman'
|
||||
* which is in `ptmr' instead, and extend it by 0.82 points, then reencode
|
||||
* it with the vector TeXBase1Encoding from the file `8r.enc'. This will
|
||||
* fail if the entry looks like this:
|
||||
*
|
||||
* ptmr8rn Times-Roman ".82 ExtendFont TeXBase1Encoding ReEncodeFont" <8r.enc
|
||||
*
|
||||
* because to deal with this we would need to be able to locate the font file
|
||||
* for the `Times-Roman' font ourselves, and that's beyond the scope of mdvi.
|
||||
* But hey, we tried hard.
|
||||
*/
|
||||
char *t1_lookup_font(const char *name, Ushort *hdpi, Ushort *vdpi)
|
||||
{
|
||||
char *filename;
|
||||
char *newname;
|
||||
const char *ext;
|
||||
DviFontMapInfo info;
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) looking for `%s'\n", name));
|
||||
|
||||
/* first let's try the font we were asked for */
|
||||
filename = kpse_find_file(name, kpse_type1_format, 1);
|
||||
if(filename != NULL) {
|
||||
/* we got it */
|
||||
return filename;
|
||||
}
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: not found, querying font maps\n", name));
|
||||
/* now query the fontmap */
|
||||
if(mdvi_query_fontmap(&info, name) < 0) {
|
||||
/* it's not there either */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check what we got */
|
||||
if(info.fullfile) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: found `%s' (cached)\n",
|
||||
name, info.fullfile));
|
||||
/* this is a cached lookup */
|
||||
return mdvi_strdup(info.fullfile);
|
||||
}
|
||||
|
||||
/* no file associated to this font? */
|
||||
if(info.fontfile == NULL)
|
||||
return info.psname ? mdvi_ps_find_font(info.psname) : NULL;
|
||||
|
||||
/* let's extract the extension */
|
||||
ext = file_extension(info.fontfile);
|
||||
if(ext && !STREQ(ext, "pfa") && !STREQ(ext, "pfb")) {
|
||||
DEBUG((DBG_TYPE1,
|
||||
"(t1) %s: associated name `%s' is not Type1\n",
|
||||
name, info.fontfile));
|
||||
/* it's not a Type1 font */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the `base' name */
|
||||
if(ext) {
|
||||
newname = mdvi_strdup(info.fontfile);
|
||||
newname[ext - info.fontfile - 1] = 0;
|
||||
} else
|
||||
newname = (char *)name; /* we don't modify this */
|
||||
|
||||
/* look it up */
|
||||
DEBUG((DBG_TYPE1, "(t1) looking for `%s' on behalf of `%s'\n",
|
||||
newname, name));
|
||||
filename = kpse_find_file(newname, kpse_type1_format, 1);
|
||||
|
||||
/* we don't need this anymore */
|
||||
if(newname != name)
|
||||
mdvi_free(newname);
|
||||
if(filename == NULL) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: not found\n", name));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: found as `%s'\n", name, filename));
|
||||
/* got it! let's remember this */
|
||||
mdvi_add_fontmap_file(name, filename);
|
||||
return filename;
|
||||
}
|
||||
|
||||
static void t1_reset_resolution(int xdpi, int ydpi)
|
||||
{
|
||||
int i;
|
||||
int nfonts;
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) resetting device resolution (current: (%d,%d))\n",
|
||||
t1lib_xdpi, t1lib_ydpi));
|
||||
#if T1LIB_VERSION < 5
|
||||
nfonts = T1_Get_no_fonts();
|
||||
#else
|
||||
nfonts = T1_GetNoFonts();
|
||||
#endif
|
||||
|
||||
for(i = 0; i < nfonts; i++)
|
||||
T1_DeleteAllSizes(i);
|
||||
/* reset device resolutions */
|
||||
if(T1_SetDeviceResolutions((float)xdpi, (float)ydpi) < 0)
|
||||
mdvi_warning(_("(t1) failed to reset device resolution\n"));
|
||||
else
|
||||
DEBUG((DBG_TYPE1,
|
||||
"(t1) reset successful, new resolution is (%d, %d)\n",
|
||||
xdpi, ydpi));
|
||||
t1lib_xdpi = xdpi;
|
||||
t1lib_ydpi = ydpi;
|
||||
}
|
||||
|
||||
static void t1_reset_font(DviFont *font)
|
||||
{
|
||||
T1Info *info = (T1Info *)font->private;
|
||||
|
||||
if(info == NULL)
|
||||
return;
|
||||
DEBUG((DBG_FONTS, "(t1) resetting font `%s'\n", font->fontname));
|
||||
/* just mark the font as not having metric info. It will be reset
|
||||
* automatically later */
|
||||
info->hasmetrics = 0;
|
||||
}
|
||||
|
||||
static void t1_transform_font(T1Info *info)
|
||||
{
|
||||
if(!info->hasmetrics && info->encoding != NULL) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: encoding with vector `%s'\n",
|
||||
info->fontname, info->encoding->name));
|
||||
T1_DeleteAllSizes(info->t1id);
|
||||
if(T1_ReencodeFont(info->t1id, info->encoding->vector) < 0)
|
||||
mdvi_warning(_("%s: could not encode font\n"), info->fontname);
|
||||
}
|
||||
if(info->mapinfo.slant) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: slanting by %.3f\n",
|
||||
info->fontname,
|
||||
MDVI_FMAP_SLANT(&info->mapinfo)));
|
||||
T1_SlantFont(info->t1id,
|
||||
MDVI_FMAP_SLANT(&info->mapinfo));
|
||||
}
|
||||
if(info->mapinfo.extend) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: extending by %.3f\n",
|
||||
info->fontname,
|
||||
MDVI_FMAP_EXTEND(&info->mapinfo)));
|
||||
T1_ExtendFont(info->t1id,
|
||||
MDVI_FMAP_EXTEND(&info->mapinfo));
|
||||
}
|
||||
}
|
||||
|
||||
/* if this function is called, we really need this font */
|
||||
static int t1_really_load_font(DviParams *params, DviFont *font, T1Info *info)
|
||||
{
|
||||
int i;
|
||||
T1Info *old;
|
||||
int t1id;
|
||||
int copied;
|
||||
int status;
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) really_load_font(%s)\n", info->fontname));
|
||||
|
||||
/* if the parameters changed, reset T1lib */
|
||||
if(t1lib_xdpi != params->dpi || t1lib_ydpi != params->vdpi)
|
||||
t1_reset_resolution(params->dpi, params->vdpi);
|
||||
|
||||
/* if we already have a T1lib id, do nothing */
|
||||
if(info->t1id != -1) {
|
||||
info->hasmetrics = 1;
|
||||
/* apply slant and extend again */
|
||||
t1_transform_font(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* before we even attempt to load the font, make sure we have metric
|
||||
* data for it */
|
||||
info->tfminfo = mdvi_ps_get_metrics(info->fontname);
|
||||
if(info->tfminfo == NULL) {
|
||||
DEBUG((DBG_FONTS,
|
||||
"(t1) %s: no metric data, font ignored\n",
|
||||
info->fontname));
|
||||
goto t1_error;
|
||||
}
|
||||
/* fix this */
|
||||
font->design = info->tfminfo->design;
|
||||
|
||||
/* check if we have a font with this name (maybe at a different size) */
|
||||
old = (T1Info *)mdvi_hash_lookup(&t1hash, (unsigned char *)info->fontname);
|
||||
if(old == info) {
|
||||
/* let's avoid confusion */
|
||||
old = NULL;
|
||||
}
|
||||
if(old && old->t1id != -1) {
|
||||
/* let's take advantage of T1lib's font sharing */
|
||||
t1id = T1_CopyFont(old->t1id);
|
||||
DEBUG((DBG_TYPE1, "(t1) %s -> %d (CopyFont)\n",
|
||||
info->fontname, t1id));
|
||||
copied = 1;
|
||||
} else {
|
||||
t1id = T1_AddFont(font->filename);
|
||||
DEBUG((DBG_TYPE1, "(t1) %s -> %d (AddFont)\n",
|
||||
info->fontname, t1id));
|
||||
copied = 0;
|
||||
}
|
||||
if(t1id < 0)
|
||||
goto t1_error;
|
||||
info->t1id = t1id;
|
||||
|
||||
/*
|
||||
* a minor optimization: If the old font in the hash table has
|
||||
* not been loaded yet, replace it by this one, so we can use
|
||||
* CopyFont later.
|
||||
*/
|
||||
if(old && old->t1id == -1) {
|
||||
DEBUG((DBG_TYPE1, "(t1) font `%s' exchanged in hash table\n",
|
||||
info->fontname));
|
||||
mdvi_hash_remove(&t1hash, (unsigned char *)old->fontname);
|
||||
mdvi_hash_add(&t1hash, (unsigned char *)info->fontname,
|
||||
info, MDVI_HASH_UNCHECKED);
|
||||
}
|
||||
|
||||
/* now let T1lib load it */
|
||||
if(!copied && T1_LoadFont(info->t1id) < 0) {
|
||||
DEBUG((DBG_TYPE1, "(t1) T1_LoadFont(%d) failed with error %d\n",
|
||||
info->t1id, T1_errno));
|
||||
goto t1_error;
|
||||
}
|
||||
DEBUG((DBG_TYPE1, "(t1) T1_LoadFont(%d) -> Ok\n", info->t1id));
|
||||
|
||||
/* get information from the fontmap */
|
||||
status = mdvi_query_fontmap(&info->mapinfo, info->fontname);
|
||||
if(!status && info->mapinfo.encoding)
|
||||
info->encoding = mdvi_request_encoding(info->mapinfo.encoding);
|
||||
t1_transform_font(info);
|
||||
|
||||
i = info->tfminfo->hic - info->tfminfo->loc + 1;
|
||||
if(i != font->hic - font->loc + 1) {
|
||||
/* reset to optimal size */
|
||||
font->chars = mdvi_realloc(font->chars, i * sizeof(DviFontChar));
|
||||
}
|
||||
|
||||
/* get the scaled characters metrics */
|
||||
get_tfm_chars(params, font, info->tfminfo, 0);
|
||||
info->hasmetrics = 1;
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) font `%s' really-loaded\n", info->fontname));
|
||||
return 0;
|
||||
|
||||
t1_error:
|
||||
/* some error does not allows us to use this font. We need to reset
|
||||
* the font structure, so the font system can try to read this
|
||||
* font in a different class */
|
||||
|
||||
/* first destroy the private data */
|
||||
t1_font_remove(info);
|
||||
/* now reset all chars -- this is the important part */
|
||||
mdvi_free(font->chars);
|
||||
font->chars = NULL;
|
||||
font->loc = font->hic = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int init_t1lib(DviParams *params)
|
||||
{
|
||||
int t1flags;
|
||||
|
||||
#ifdef WORD_LITTLE_ENDIAN
|
||||
/* try making T1lib use bitmaps in our format, but if this
|
||||
* fails we'll convert the bitmap ourselves */
|
||||
T1_SetBitmapPad(BITMAP_BITS);
|
||||
#endif
|
||||
T1_SetDeviceResolutions((float)params->dpi, (float)params->vdpi);
|
||||
t1flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE|T1_NO_AFM;
|
||||
if(DEBUGGING(TYPE1))
|
||||
t1flags |= LOGFILE;
|
||||
if(T1_InitLib(t1flags) == NULL)
|
||||
return (t1lib_initialized = -1);
|
||||
if(DEBUGGING(TYPE1)) {
|
||||
DEBUG((DBG_TYPE1, "T1lib debugging output saved in t1lib.log\n"));
|
||||
T1_SetLogLevel(T1LOG_DEBUG);
|
||||
}
|
||||
/* initialize our hash table, but don't allocate memory for it
|
||||
* until we use it */
|
||||
mdvi_hash_init(&t1hash);
|
||||
DEBUG((DBG_TYPE1, "(t1) t1lib %s initialized -- resolution is (%d, %d), pad is %d bits\n",
|
||||
T1_GetLibIdent(), params->dpi, params->vdpi, T1_GetBitmapPad()));
|
||||
t1lib_initialized = 1;
|
||||
t1lib_xdpi = params->dpi;
|
||||
t1lib_ydpi = params->vdpi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t1_load_font(DviParams *params, DviFont *font)
|
||||
{
|
||||
T1Info *info;
|
||||
int i;
|
||||
|
||||
if(t1lib_initialized < 0)
|
||||
return -1;
|
||||
else if(t1lib_initialized == 0 && init_t1lib(params) < 0)
|
||||
return -1;
|
||||
|
||||
if(font->in != NULL) {
|
||||
/* we don't need this */
|
||||
fclose(font->in);
|
||||
font->in = NULL;
|
||||
}
|
||||
|
||||
info = xalloc(T1Info);
|
||||
|
||||
/*
|
||||
* mark the font as `unregistered' with T1lib. It will
|
||||
* be added when we actually use it
|
||||
*/
|
||||
info->t1id = -1;
|
||||
|
||||
/* add the font to our list */
|
||||
info->fontname = font->fontname;
|
||||
info->hasmetrics = 0;
|
||||
info->encoding = NULL;
|
||||
info->mapinfo.psname = NULL;
|
||||
info->mapinfo.encoding = NULL;
|
||||
info->mapinfo.fontfile = NULL;
|
||||
info->mapinfo.extend = 0;
|
||||
info->mapinfo.slant = 0;
|
||||
info->encoding = NULL;
|
||||
|
||||
/* create the hash table if we have not done so yet */
|
||||
if(t1hash.nbucks == 0)
|
||||
mdvi_hash_create(&t1hash, T1_HASH_SIZE);
|
||||
mdvi_hash_add(&t1hash, (unsigned char *) info->fontname, info, MDVI_HASH_UNIQUE);
|
||||
listh_append(&t1fonts, LIST(info));
|
||||
|
||||
font->private = info;
|
||||
|
||||
/* reset everything */
|
||||
font->chars = xnalloc(DviFontChar, 256);
|
||||
font->loc = 0;
|
||||
font->hic = 255;
|
||||
for(i = 0; i < 256; i++) {
|
||||
font->chars[i].code = i;
|
||||
font->chars[i].offset = 1;
|
||||
font->chars[i].loaded = 0;
|
||||
font->chars[i].glyph.data = NULL;
|
||||
font->chars[i].shrunk.data = NULL;
|
||||
font->chars[i].grey.data = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define GLYPH_WIDTH(g) \
|
||||
((g)->metrics.rightSideBearing - (g)->metrics.leftSideBearing)
|
||||
#define GLYPH_HEIGHT(g) \
|
||||
((g)->metrics.ascent - (g)->metrics.descent)
|
||||
|
||||
static inline BITMAP *t1_glyph_bitmap(GLYPH *glyph)
|
||||
{
|
||||
int w, h, pad;
|
||||
|
||||
w = GLYPH_WIDTH(glyph);
|
||||
h = GLYPH_HEIGHT(glyph);
|
||||
|
||||
if(!w || !h)
|
||||
return MDVI_GLYPH_EMPTY;
|
||||
|
||||
pad = T1_GetBitmapPad();
|
||||
return bitmap_convert_lsb8((unsigned char *)glyph->bits, w, h, ROUND(w, pad) * (pad >> 3));
|
||||
}
|
||||
|
||||
static void t1_font_shrink_glyph(DviContext *dvi, DviFont *font, DviFontChar *ch, DviGlyph *dest)
|
||||
{
|
||||
double size;
|
||||
GLYPH *glyph;
|
||||
T1Info *info;
|
||||
T1_TMATRIX matrix;
|
||||
|
||||
info = (T1Info *)font->private;
|
||||
ASSERT(info != NULL);
|
||||
|
||||
DEBUG((DBG_TYPE1, "(t1) shrinking glyph for character %d in `%s' (%d,%d)\n",
|
||||
ch->code, font->fontname, ch->width, ch->height));
|
||||
size = (double)font->scale / (dvi->params.tfm_conv * 0x100000);
|
||||
size = 72.0 * size / 72.27;
|
||||
matrix.cxx = 1.0/(double)dvi->params.hshrink;
|
||||
matrix.cyy = 1.0/(double)dvi->params.vshrink;
|
||||
matrix.cxy = 0.0;
|
||||
matrix.cyx = 0.0;
|
||||
glyph = T1_SetChar(info->t1id, ch->code, (float)size, &matrix);
|
||||
|
||||
dest->data = t1_glyph_bitmap(glyph);
|
||||
dest->x = -glyph->metrics.leftSideBearing;
|
||||
dest->y = glyph->metrics.ascent;
|
||||
dest->w = GLYPH_WIDTH(glyph);
|
||||
dest->h = GLYPH_HEIGHT(glyph);
|
||||
|
||||
#ifndef NODEBUG
|
||||
if(DEBUGGING(BITMAP_DATA)) {
|
||||
DEBUG((DBG_BITMAP_DATA,
|
||||
"(t1) %s: t1_shrink_glyph(%d): (%dw,%dh,%dx,%dy) -> (%dw,%dh,%dx,%dy)\n",
|
||||
ch->glyph.w, ch->glyph.h, ch->glyph.x, ch->glyph.y,
|
||||
dest->w, dest->h, dest->x, dest->y));
|
||||
bitmap_print(stderr, (BITMAP *)dest->data);
|
||||
}
|
||||
#endif
|
||||
/* transform the glyph - we could do this with t1lib, but we do
|
||||
* it ourselves for now */
|
||||
font_transform_glyph(dvi->params.orientation, dest);
|
||||
}
|
||||
|
||||
static int t1_font_get_glyph(DviParams *params, DviFont *font, int code)
|
||||
{
|
||||
T1Info *info = (T1Info *)font->private;
|
||||
GLYPH *glyph;
|
||||
DviFontChar *ch;
|
||||
double size;
|
||||
T1_TMATRIX matrix;
|
||||
int dpi;
|
||||
|
||||
ASSERT(info != NULL);
|
||||
if(!info->hasmetrics && t1_really_load_font(params, font, info) < 0)
|
||||
return -1;
|
||||
ch = FONTCHAR(font, code);
|
||||
if(!ch || !glyph_present(ch))
|
||||
return -1;
|
||||
ch->loaded = 1;
|
||||
if(!ch->width || !ch->height) {
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
ch->glyph.data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load the glyph with T1lib (this is done only once for each glyph) */
|
||||
|
||||
/* get size in TeX points (tfm_conv includes dpi and magnification) */
|
||||
size = (double)font->scale / (params->tfm_conv * 0x100000);
|
||||
/* and transform into PostScript points */
|
||||
size = 72.0 * size / 72.27;
|
||||
|
||||
dpi = Max(font->hdpi, font->vdpi);
|
||||
/* we don't want the glyph to be cached twice (once by us, another by
|
||||
* T1lib), so we use an identity matrix to tell T1lib not to keep the
|
||||
* glyph around */
|
||||
matrix.cxx = (double)font->hdpi / dpi;
|
||||
matrix.cyy = (double)font->vdpi / dpi;
|
||||
matrix.cxy = matrix.cyx = 0.0;
|
||||
glyph = T1_SetChar(info->t1id, ch->code, (float)size, &matrix);
|
||||
if(glyph == NULL) {
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
ch->glyph.data = NULL;
|
||||
ch->missing = 1;
|
||||
return 0;
|
||||
}
|
||||
/* and make it a bitmap */
|
||||
ch->glyph.data = t1_glyph_bitmap(glyph);
|
||||
ch->glyph.x = -glyph->metrics.leftSideBearing;
|
||||
ch->glyph.y = glyph->metrics.ascent;
|
||||
ch->glyph.w = GLYPH_WIDTH(glyph);
|
||||
ch->glyph.h = GLYPH_HEIGHT(glyph);
|
||||
|
||||
/* let's also fix the glyph's origin
|
||||
* (which is not contained in the TFM) */
|
||||
ch->x = ch->glyph.x;
|
||||
ch->y = ch->glyph.y;
|
||||
/* let's fix these too */
|
||||
ch->width = ch->glyph.w;
|
||||
ch->height = ch->glyph.h;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void t1_font_remove(T1Info *info)
|
||||
{
|
||||
T1Info *old;
|
||||
|
||||
/* first remove it from our list */
|
||||
listh_remove(&t1fonts, LIST(info));
|
||||
|
||||
/* it it's in the hash table, we may need to replace this by another font */
|
||||
old = (T1Info *)mdvi_hash_lookup(&t1hash, (unsigned char *)info->fontname);
|
||||
if(old == info) {
|
||||
mdvi_hash_remove(&t1hash, (unsigned char *) info->fontname);
|
||||
/* go through the list and see if there is another
|
||||
* font with this name */
|
||||
for(old = (T1Info *)t1fonts.head; old; old = old->next)
|
||||
if(STREQ(old->fontname, info->fontname))
|
||||
break;
|
||||
if(old != NULL)
|
||||
mdvi_hash_add(&t1hash, (unsigned char *) old->fontname, old,
|
||||
MDVI_HASH_UNCHECKED);
|
||||
}
|
||||
/* release our encoding vector */
|
||||
if(info->encoding) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: releasing vector `%s'\n",
|
||||
info->fontname, info->encoding->name));
|
||||
mdvi_release_encoding(info->encoding, 1);
|
||||
}
|
||||
|
||||
/* now get rid of it */
|
||||
if(info->t1id != -1) {
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: T1_DeleteFont(%d)\n",
|
||||
info->fontname, info->t1id));
|
||||
T1_DeleteFont(info->t1id);
|
||||
} else
|
||||
DEBUG((DBG_TYPE1, "(t1) %s: not loaded yet, DeleteFont skipped\n",
|
||||
info->fontname));
|
||||
|
||||
if(info->tfminfo)
|
||||
free_font_metrics(info->tfminfo);
|
||||
/*mdvi_free(info->fontname);*/
|
||||
mdvi_free(info);
|
||||
}
|
||||
|
||||
static void t1_free_data(DviFont *font)
|
||||
{
|
||||
/* called after all the glyphs are destroyed */
|
||||
|
||||
if(font->private == NULL) {
|
||||
/* this is perfectly normal, it just means the font has
|
||||
* not been requested by MDVI yet */
|
||||
return;
|
||||
}
|
||||
|
||||
/* destroy this data */
|
||||
|
||||
t1_font_remove((T1Info *)font->private);
|
||||
font->private = NULL;
|
||||
|
||||
/*
|
||||
* if this is the last T1 font, reset the T1 library
|
||||
* It is important that we do this, because this is will be called
|
||||
* when the resolution or the magnification changes.
|
||||
*/
|
||||
if(t1fonts.count == 0) {
|
||||
DEBUG((DBG_TYPE1, "(t1) last font removed -- closing T1lib\n"));
|
||||
T1_CloseLib();
|
||||
t1lib_initialized = 0;
|
||||
t1lib_xdpi = -1;
|
||||
t1lib_ydpi = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WITH_TYPE1_FONTS */
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
static int tfm_load_font __PROTO((DviParams *, DviFont *));
|
||||
static int tfm_font_get_glyph __PROTO((DviParams *, DviFont *, int));
|
||||
|
||||
DviFontInfo tfm_font_info = {
|
||||
"TFM",
|
||||
0, /* scaling not supported by format */
|
||||
tfm_load_font,
|
||||
tfm_font_get_glyph,
|
||||
mdvi_shrink_box,
|
||||
mdvi_shrink_box,
|
||||
NULL, /* free */
|
||||
NULL, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_tfm_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
DviFontInfo ofm_font_info = {
|
||||
"OFM",
|
||||
0, /* scaling not supported by format */
|
||||
tfm_load_font,
|
||||
tfm_font_get_glyph,
|
||||
mdvi_shrink_box,
|
||||
mdvi_shrink_box,
|
||||
NULL, /* free */
|
||||
NULL, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_ofm_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
DviFontInfo afm_font_info = {
|
||||
"AFM",
|
||||
0, /* scaling not supported by format */
|
||||
tfm_load_font,
|
||||
tfm_font_get_glyph,
|
||||
mdvi_shrink_box,
|
||||
mdvi_shrink_box,
|
||||
NULL, /* free */
|
||||
NULL, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_afm_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define TYPENAME(font) \
|
||||
((font)->search.info ? (font)->search.info : "none")
|
||||
|
||||
/*
|
||||
* Although it does not seem that way, this conversion is independent of the
|
||||
* shrinking factors, within roundoff (that's because `conv' and `vconv'
|
||||
* have already been scaled by hshrink and vshrink, repsectively). We
|
||||
* should really use `dviconv' and `dvivconv', but I'm not so sure those
|
||||
* should be moved to the DviParams structure.
|
||||
*/
|
||||
#define XCONV(x) FROUND(params->conv * (x) * params->hshrink)
|
||||
#define YCONV(y) FROUND(params->vconv * (y) * params->vshrink)
|
||||
|
||||
/* this is used quite often in several places, so I made it standalone */
|
||||
int get_tfm_chars(DviParams *params, DviFont *font, TFMInfo *info, int loaded)
|
||||
{
|
||||
Int32 z, alpha, beta;
|
||||
int n;
|
||||
DviFontChar *ch;
|
||||
TFMChar *ptr;
|
||||
|
||||
n = info->hic - info->loc + 1;
|
||||
if(n != FONT_GLYPH_COUNT(font)) {
|
||||
font->chars = mdvi_realloc(font->chars,
|
||||
n * sizeof(DviFontChar));
|
||||
}
|
||||
font->loc = info->loc;
|
||||
font->hic = info->hic;
|
||||
ch = font->chars;
|
||||
ptr = info->chars;
|
||||
|
||||
/* Prepare z, alpha and beta for TFM width computation */
|
||||
TFMPREPARE(font->scale, z, alpha, beta);
|
||||
|
||||
/* get the character metrics */
|
||||
for(n = info->loc; n <= info->hic; ch++, ptr++, n++) {
|
||||
int a, b, c, d;
|
||||
|
||||
ch->offset = ptr->present;
|
||||
if(ch->offset == 0)
|
||||
continue;
|
||||
/* this is what we came here for */
|
||||
ch->tfmwidth = TFMSCALE(z, ptr->advance, alpha, beta);
|
||||
/* scale all other TFM units (so they are in DVI units) */
|
||||
a = TFMSCALE(z, ptr->left, alpha, beta);
|
||||
b = TFMSCALE(z, ptr->right, alpha, beta);
|
||||
c = TFMSCALE(z, ptr->height, alpha, beta);
|
||||
d = TFMSCALE(z, ptr->depth, alpha, beta);
|
||||
|
||||
/* now convert to unscaled pixels */
|
||||
ch->width = XCONV(b - a);
|
||||
ch->height = YCONV(c - d);
|
||||
if(ch->height < 0) ch->height = -ch->height;
|
||||
ch->x = XCONV(a);
|
||||
ch->y = YCONV(c);
|
||||
/*
|
||||
* the offset is not used, but we might as well set it to
|
||||
* something meaningful (and it MUST be non-zero)
|
||||
*/
|
||||
ch->flags = 0;
|
||||
ch->code = n;
|
||||
ch->glyph.data = NULL;
|
||||
ch->grey.data = NULL;
|
||||
ch->shrunk.data = NULL;
|
||||
ch->loaded = loaded;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We use this function as a last resort to find the character widths in a
|
||||
* font The DVI rendering code can correctly skip over a glyph if it knows
|
||||
* its TFM width, which is what we try to find here.
|
||||
*/
|
||||
static int tfm_load_font(DviParams *params, DviFont *font)
|
||||
{
|
||||
TFMInfo *tfm;
|
||||
int type;
|
||||
|
||||
switch(font->search.info->kpse_type) {
|
||||
case kpse_tfm_format:
|
||||
type = DviFontTFM;
|
||||
break;
|
||||
case kpse_afm_format:
|
||||
type = DviFontAFM;
|
||||
break;
|
||||
case kpse_ofm_format:
|
||||
type = DviFontOFM;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we don't need this */
|
||||
if(font->in) {
|
||||
fclose(font->in);
|
||||
font->in = NULL;
|
||||
}
|
||||
tfm = get_font_metrics(font->fontname, type, font->filename);
|
||||
if(tfm == NULL)
|
||||
return -1;
|
||||
|
||||
if(tfm->checksum && font->checksum && tfm->checksum != font->checksum) {
|
||||
mdvi_warning(_("%s: Checksum mismatch (got %u, expected %u)\n"),
|
||||
font->fontname, (unsigned)tfm->checksum,
|
||||
(unsigned)font->checksum);
|
||||
}
|
||||
font->checksum = tfm->checksum;
|
||||
font->design = tfm->design;
|
||||
font->loc = 0;
|
||||
font->hic = 0;
|
||||
font->chars = NULL;
|
||||
get_tfm_chars(params, font, tfm, 1);
|
||||
|
||||
/* free everything */
|
||||
free_font_metrics(tfm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tfm_font_get_glyph(DviParams *params, DviFont *font, int code)
|
||||
{
|
||||
DviFontChar *ch;
|
||||
|
||||
ch = FONTCHAR(font, code);
|
||||
if(!glyph_present(ch))
|
||||
return -1;
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
/*
|
||||
* This has two purposes: (1) avoid unnecessary calls to this function,
|
||||
* and (2) detect when the glyph data for a TFM font is actually used
|
||||
* (we'll get a SEGV). Any occurrence of that is a bug.
|
||||
*/
|
||||
ch->glyph.data = MDVI_GLYPH_EMPTY;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,747 @@
|
|||
/* tfmfile.c -- readers for TFM, AFM, OTFM-0 and OTFM-1 files */
|
||||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h> /* tex-file.h needs this */
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
#ifdef WITH_AFM_FILES
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
#include "afmparse.h"
|
||||
#endif
|
||||
|
||||
typedef struct tfmpool {
|
||||
struct tfmpool *next;
|
||||
struct tfmpool *prev;
|
||||
char *short_name;
|
||||
int links;
|
||||
TFMInfo tfminfo;
|
||||
} TFMPool;
|
||||
|
||||
static ListHead tfmpool = {NULL, NULL, 0};
|
||||
static DviHashTable tfmhash;
|
||||
|
||||
#define TFM_HASH_SIZE 31
|
||||
|
||||
#ifdef WORD_LITTLE_ENDIAN
|
||||
static inline void swap_array(Uint32 *ptr, int n)
|
||||
{
|
||||
Uint32 i;
|
||||
|
||||
while(n-- > 0) {
|
||||
i = *ptr;
|
||||
*ptr++ = ((i & 0xff000000) >> 24)
|
||||
| ((i & 0x00ff0000) >> 8)
|
||||
| ((i & 0x0000ff00) << 8)
|
||||
| ((i & 0x000000ff) << 24);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_AFM_FILES
|
||||
|
||||
static int __PROTO(ofm_load_file(const char *filename, TFMInfo *info));
|
||||
|
||||
/* reading of AFM files */
|
||||
/* macro to convert between AFM and TFM units */
|
||||
#define AFM2TFM(x) FROUND((double)(x) * 0x100000 / 1000)
|
||||
int afm_load_file(const char *filename, TFMInfo *info)
|
||||
{
|
||||
/* the information we want is:
|
||||
* - tfmwidth
|
||||
* - width and heights
|
||||
* - character origins
|
||||
*/
|
||||
FontInfo *fi = NULL;
|
||||
int status;
|
||||
CharMetricInfo *cm;
|
||||
FILE *in;
|
||||
|
||||
in = fopen(filename, "rb");
|
||||
if(in == NULL)
|
||||
return -1;
|
||||
status = afm_parse_file(in, &fi, P_GM);
|
||||
fclose(in);
|
||||
|
||||
if(status != ok) {
|
||||
mdvi_error(_("%s: Error reading AFM data\n"), filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* aim high */
|
||||
info->chars = xnalloc(TFMChar, 256);
|
||||
info->loc = 256;
|
||||
info->hic = 0;
|
||||
info->design = 0xa00000; /* fake -- 10pt */
|
||||
info->checksum = 0; /* no checksum */
|
||||
info->type = DviFontAFM;
|
||||
mdvi_strncpy(info->coding, fi->gfi->encodingScheme, 63);
|
||||
mdvi_strncpy(info->family, fi->gfi->familyName, 63);
|
||||
|
||||
/* now get the data */
|
||||
for(cm = fi->cmi; cm < fi->cmi + fi->numOfChars; cm++) {
|
||||
int code;
|
||||
TFMChar *ch;
|
||||
|
||||
code = cm->code;
|
||||
if(code < 0 || code > 255)
|
||||
continue; /* ignore it */
|
||||
ch = &info->chars[code];
|
||||
ch->present = 1;
|
||||
if(code < info->loc)
|
||||
info->loc = code;
|
||||
if(code > info->hic)
|
||||
info->hic = code;
|
||||
ch->advance = AFM2TFM(cm->wx);
|
||||
/* this is the `leftSideBearing' */
|
||||
ch->left = AFM2TFM(cm->charBBox.llx);
|
||||
/* this is the height (ascent - descent) -- the sign is to follow
|
||||
* TeX conventions, as opposed to Adobe's ones */
|
||||
ch->depth = -AFM2TFM(cm->charBBox.lly);
|
||||
/* this is the width (rightSideBearing - leftSideBearing) */
|
||||
ch->right = AFM2TFM(cm->charBBox.urx);
|
||||
/* this is the `ascent' */
|
||||
ch->height = AFM2TFM(cm->charBBox.ury);
|
||||
}
|
||||
|
||||
/* we don't need this anymore */
|
||||
afm_free_fontinfo(fi);
|
||||
|
||||
/* optimize storage */
|
||||
if(info->loc > 0 || info->hic < 256) {
|
||||
memmove(&info->chars[0],
|
||||
&info->chars[info->loc],
|
||||
(info->hic - info->loc + 1) * sizeof(TFMChar));
|
||||
info->chars = mdvi_realloc(info->chars,
|
||||
(info->hic - info->loc + 1) * sizeof(TFMChar));
|
||||
}
|
||||
|
||||
/* we're done */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* WITH_AFM_FILES */
|
||||
|
||||
int tfm_load_file(const char *filename, TFMInfo *info)
|
||||
{
|
||||
int lf, lh, bc, ec, nw, nh, nd, ne;
|
||||
int i, n;
|
||||
Uchar *tfm;
|
||||
Uchar *ptr;
|
||||
struct stat st;
|
||||
int size;
|
||||
FILE *in;
|
||||
Int32 *cb;
|
||||
Int32 *charinfo;
|
||||
Int32 *widths;
|
||||
Int32 *heights;
|
||||
Int32 *depths;
|
||||
Uint32 checksum;
|
||||
|
||||
in = fopen(filename, "rb");
|
||||
if(in == NULL)
|
||||
return -1;
|
||||
tfm = NULL;
|
||||
|
||||
DEBUG((DBG_FONTS, "(mt) reading TFM file `%s'\n",
|
||||
filename));
|
||||
/* We read the entire TFM file into core */
|
||||
if(fstat(fileno(in), &st) < 0)
|
||||
return -1;
|
||||
/* according to the spec, TFM files are smaller than 16K */
|
||||
if(st.st_size == 0 || st.st_size >= 16384)
|
||||
goto bad_tfm;
|
||||
|
||||
/* allocate a word-aligned buffer to hold the file */
|
||||
size = 4 * ROUND(st.st_size, 4);
|
||||
if(size != st.st_size)
|
||||
mdvi_warning(_("Warning: TFM file `%s' has suspicious size\n"),
|
||||
filename);
|
||||
tfm = (Uchar *)mdvi_malloc(size);
|
||||
if(fread(tfm, st.st_size, 1, in) != 1)
|
||||
goto error;
|
||||
/* we don't need this anymore */
|
||||
fclose(in);
|
||||
in = NULL;
|
||||
|
||||
/* not a checksum, but serves a similar purpose */
|
||||
checksum = 0;
|
||||
|
||||
ptr = tfm;
|
||||
/* get the counters */
|
||||
lf = muget2(ptr);
|
||||
lh = muget2(ptr); checksum += 6 + lh;
|
||||
bc = muget2(ptr);
|
||||
ec = muget2(ptr); checksum += ec - bc + 1;
|
||||
nw = muget2(ptr); checksum += nw;
|
||||
nh = muget2(ptr); checksum += nh;
|
||||
nd = muget2(ptr); checksum += nd;
|
||||
checksum += muget2(ptr); /* skip italics correction count */
|
||||
checksum += muget2(ptr); /* skip lig/kern table size */
|
||||
checksum += muget2(ptr); /* skip kern table size */
|
||||
ne = muget2(ptr); checksum += ne;
|
||||
checksum += muget2(ptr); /* skip # of font parameters */
|
||||
|
||||
size = ec - bc + 1;
|
||||
cb = (Int32 *)tfm; cb += 6 + lh;
|
||||
charinfo = cb; cb += size;
|
||||
widths = cb; cb += nw;
|
||||
heights = cb; cb += nh;
|
||||
depths = cb;
|
||||
|
||||
if(widths[0] || heights[0] || depths[0] ||
|
||||
checksum != lf || bc - 1 > ec || ec > 255 || ne > 256)
|
||||
goto bad_tfm;
|
||||
|
||||
/* from this point on, no error checking is done */
|
||||
|
||||
/* now we're at the header */
|
||||
/* get the checksum */
|
||||
info->checksum = muget4(ptr);
|
||||
/* get the design size */
|
||||
info->design = muget4(ptr);
|
||||
/* get the coding scheme */
|
||||
if(lh > 2) {
|
||||
/* get the coding scheme */
|
||||
i = n = msget1(ptr);
|
||||
if(n < 0 || n > 39) {
|
||||
mdvi_warning(_("%s: font coding scheme truncated to 40 bytes\n"),
|
||||
filename);
|
||||
n = 39;
|
||||
}
|
||||
memcpy(info->coding, ptr, n);
|
||||
info->coding[n] = 0;
|
||||
ptr += i;
|
||||
} else
|
||||
strcpy(info->coding, "FontSpecific");
|
||||
/* get the font family */
|
||||
if(lh > 12) {
|
||||
n = msget1(ptr);
|
||||
if(n > 0) {
|
||||
i = Max(n, 63);
|
||||
memcpy(info->family, ptr, i);
|
||||
info->family[i] = 0;
|
||||
} else
|
||||
strcpy(info->family, "unspecified");
|
||||
ptr += n;
|
||||
}
|
||||
/* now we don't read from `ptr' anymore */
|
||||
|
||||
info->loc = bc;
|
||||
info->hic = ec;
|
||||
info->type = DviFontTFM;
|
||||
|
||||
/* allocate characters */
|
||||
info->chars = xnalloc(TFMChar, size);
|
||||
|
||||
|
||||
#ifdef WORD_LITTLE_ENDIAN
|
||||
/* byte-swap the three arrays at once (they are consecutive in memory) */
|
||||
swap_array((Uint32 *)widths, nw + nh + nd);
|
||||
#endif
|
||||
|
||||
/* get the relevant data */
|
||||
ptr = (Uchar *)charinfo;
|
||||
for(i = bc; i <= ec; ptr += 3, i++) {
|
||||
int ndx;
|
||||
|
||||
ndx = (int)*ptr; ptr++;
|
||||
info->chars[i-bc].advance = widths[ndx];
|
||||
/* TFM files lack this information */
|
||||
info->chars[i-bc].left = 0;
|
||||
info->chars[i-bc].right = widths[ndx];
|
||||
info->chars[i-bc].present = (ndx != 0);
|
||||
if(ndx) {
|
||||
ndx = ((*ptr >> 4) & 0xf);
|
||||
info->chars[i-bc].height = heights[ndx];
|
||||
ndx = (*ptr & 0xf);
|
||||
info->chars[i-bc].depth = depths[ndx];
|
||||
}
|
||||
}
|
||||
|
||||
/* free everything */
|
||||
mdvi_free(tfm);
|
||||
|
||||
return 0;
|
||||
|
||||
bad_tfm:
|
||||
mdvi_error(_("%s: File corrupted, or not a TFM file\n"), filename);
|
||||
error:
|
||||
if(tfm) mdvi_free(tfm);
|
||||
if(in) fclose(in);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ofm1_load_file(FILE *in, TFMInfo *info)
|
||||
{
|
||||
int lh, bc, ec, nw, nh, nd;
|
||||
int nco, ncw, npc;
|
||||
int i;
|
||||
int n;
|
||||
int size;
|
||||
Int32 *tfm;
|
||||
Int32 *widths;
|
||||
Int32 *heights;
|
||||
Int32 *depths;
|
||||
TFMChar *tch;
|
||||
TFMChar *end;
|
||||
|
||||
lh = fuget4(in);
|
||||
bc = fuget4(in);
|
||||
ec = fuget4(in);
|
||||
nw = fuget4(in);
|
||||
nh = fuget4(in);
|
||||
nd = fuget4(in);
|
||||
fuget4(in); /* italics */
|
||||
fuget4(in); /* lig-kern */
|
||||
fuget4(in); /* kern */
|
||||
fuget4(in); /* extensible recipe */
|
||||
fuget4(in); /* parameters */
|
||||
fuget4(in); /* direction */
|
||||
nco = fuget4(in);
|
||||
ncw = fuget4(in);
|
||||
npc = fuget4(in);
|
||||
|
||||
/* get the checksum */
|
||||
info->checksum = fuget4(in);
|
||||
/* the design size */
|
||||
info->design = fuget4(in);
|
||||
/* get the coding scheme */
|
||||
if(lh > 2) {
|
||||
/* get the coding scheme */
|
||||
i = n = fsget1(in);
|
||||
if(n < 0 || n > 39)
|
||||
n = 39;
|
||||
fread(info->coding, 39, 1, in);
|
||||
info->coding[n] = 0;
|
||||
} else
|
||||
strcpy(info->coding, "FontSpecific");
|
||||
/* get the font family */
|
||||
if(lh > 12) {
|
||||
n = fsget1(in);
|
||||
if(n > 0) {
|
||||
i = Max(n, 63);
|
||||
fread(info->family, i, 1, in);
|
||||
info->family[i] = 0;
|
||||
} else
|
||||
strcpy(info->family, "unspecified");
|
||||
}
|
||||
tfm = NULL;
|
||||
|
||||
/* jump to the beginning of the char-info table */
|
||||
fseek(in, 4L*nco, SEEK_SET);
|
||||
|
||||
size = ec - bc + 1;
|
||||
info->loc = bc;
|
||||
info->hic = ec;
|
||||
info->chars = xnalloc(TFMChar, size);
|
||||
end = info->chars + size;
|
||||
|
||||
for(tch = info->chars, i = 0; i < ncw; i++) {
|
||||
TFMChar ch;
|
||||
int nr;
|
||||
|
||||
/* in the characters we store the actual indices */
|
||||
ch.advance = fuget2(in);
|
||||
ch.height = fuget1(in);
|
||||
ch.depth = fuget1(in);
|
||||
/* skip 2nd word */
|
||||
fuget4(in);
|
||||
/* get # of repeats */
|
||||
nr = fuget2(in);
|
||||
/* skip parameters */
|
||||
fseek(in, (long)npc * 2, SEEK_CUR);
|
||||
/* if npc is odd, skip padding */
|
||||
if(npc & 1) fuget2(in);
|
||||
|
||||
/* now repeat the character */
|
||||
while(nr-- >= 0 && tch < end)
|
||||
memcpy(tch++, &ch, sizeof(TFMChar));
|
||||
if(tch == end)
|
||||
goto bad_tfm;
|
||||
}
|
||||
|
||||
/* I wish we were done, but we aren't */
|
||||
|
||||
/* get the widths, heights and depths */
|
||||
size = nw + nh + nd;
|
||||
tfm = xnalloc(Int32, size);
|
||||
/* read them in one sweep */
|
||||
if(fread(tfm, 4, size, in) != size) {
|
||||
mdvi_free(tfm);
|
||||
goto bad_tfm;
|
||||
}
|
||||
|
||||
/* byte-swap things if necessary */
|
||||
#ifdef WORD_LITTLE_ENDIAN
|
||||
swap_array((Uint32 *)tfm, size);
|
||||
#endif
|
||||
widths = tfm;
|
||||
heights = widths + nw;
|
||||
depths = heights + nh;
|
||||
|
||||
if(widths[0] || heights[0] || depths[0])
|
||||
goto bad_tfm;
|
||||
|
||||
/* now fix the characters */
|
||||
size = ec - bc + 1;
|
||||
for(tch = info->chars; tch < end; tch++) {
|
||||
tch->present = (tch->advance != 0);
|
||||
tch->advance = widths[tch->advance];
|
||||
tch->height = heights[tch->height];
|
||||
tch->depth = depths[tch->depth];
|
||||
tch->left = 0;
|
||||
tch->right = tch->advance;
|
||||
}
|
||||
|
||||
/* NOW we're done */
|
||||
mdvi_free(tfm);
|
||||
return 0;
|
||||
|
||||
bad_tfm:
|
||||
if(tfm) mdvi_free(tfm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we don't read OFM files into memory, because they can potentially be large */
|
||||
static int ofm_load_file(const char *filename, TFMInfo *info)
|
||||
{
|
||||
int lf, lh, bc, ec, nw, nh, nd;
|
||||
int i, n;
|
||||
Int32 *tfm;
|
||||
Uchar *ptr;
|
||||
int size;
|
||||
FILE *in;
|
||||
Int32 *cb;
|
||||
Int32 *charinfo;
|
||||
Int32 *widths;
|
||||
Int32 *heights;
|
||||
Int32 *depths;
|
||||
Uint32 checksum;
|
||||
int olevel;
|
||||
int nwords;
|
||||
|
||||
in = fopen(filename, "rb");
|
||||
if(in == NULL)
|
||||
return -1;
|
||||
|
||||
/* not a checksum, but serves a similar purpose */
|
||||
checksum = 0;
|
||||
|
||||
/* get the counters */
|
||||
/* get file level */
|
||||
olevel = fsget2(in);
|
||||
if(olevel != 0)
|
||||
goto bad_tfm;
|
||||
olevel = fsget2(in);
|
||||
if(olevel != 0) {
|
||||
DEBUG((DBG_FONTS, "(mt) reading Level-1 OFM file `%s'\n",
|
||||
filename));
|
||||
/* we handle level-1 files separately */
|
||||
if(ofm1_load_file(in, info) < 0)
|
||||
goto bad_tfm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG((DBG_FONTS, "(mt) reading Level-0 OFM file `%s'\n", filename));
|
||||
nwords = 14;
|
||||
lf = fuget4(in); checksum = nwords;
|
||||
lh = fuget4(in); checksum += lh;
|
||||
bc = fuget4(in);
|
||||
ec = fuget4(in); checksum += 2 * (ec - bc + 1);
|
||||
nw = fuget4(in); checksum += nw;
|
||||
nh = fuget4(in); checksum += nh;
|
||||
nd = fuget4(in); checksum += nd;
|
||||
checksum += fuget4(in); /* skip italics correction count */
|
||||
checksum += 2*fuget4(in); /* skip lig/kern table size */
|
||||
checksum += fuget4(in); /* skip kern table size */
|
||||
checksum += 2*fuget4(in); /* skip extensible recipe count */
|
||||
checksum += fuget4(in); /* skip # of font parameters */
|
||||
|
||||
/* I have found several .ofm files that seem to have the
|
||||
* font-direction word missing, so we try to detect that here */
|
||||
if(checksum == lf + 1) {
|
||||
DEBUG((DBG_FONTS, "(mt) font direction missing in `%s'\n",
|
||||
filename));
|
||||
checksum--;
|
||||
nwords--;
|
||||
} else {
|
||||
/* skip font direction */
|
||||
fuget4(in);
|
||||
}
|
||||
|
||||
if(checksum != lf || bc > ec + 1 || ec > 65535)
|
||||
goto bad_tfm;
|
||||
|
||||
/* now we're at the header */
|
||||
|
||||
/* get the checksum */
|
||||
info->checksum = fuget4(in);
|
||||
/* get the design size */
|
||||
info->design = fuget4(in);
|
||||
|
||||
/* get the coding scheme */
|
||||
if(lh > 2) {
|
||||
/* get the coding scheme */
|
||||
i = n = fsget1(in);
|
||||
if(n < 0 || n > 39) {
|
||||
mdvi_warning(_("%s: font coding scheme truncated to 40 bytes\n"),
|
||||
filename);
|
||||
n = 39;
|
||||
}
|
||||
fread(info->coding, 39, 1, in);
|
||||
info->coding[n] = 0;
|
||||
} else
|
||||
strcpy(info->coding, "FontSpecific");
|
||||
/* get the font family */
|
||||
if(lh > 12) {
|
||||
n = fsget1(in);
|
||||
if(n > 0) {
|
||||
i = Max(n, 63);
|
||||
fread(info->family, i, 1, in);
|
||||
info->family[i] = 0;
|
||||
} else
|
||||
strcpy(info->family, "unspecified");
|
||||
}
|
||||
|
||||
/* now skip anything else in the header */
|
||||
fseek(in, 4L*(nwords + lh), SEEK_SET);
|
||||
/* and read everything at once */
|
||||
size = 2*(ec - bc + 1) + nw + nh + nd;
|
||||
tfm = xnalloc(Int32, size * sizeof(Int32));
|
||||
if(fread(tfm, 4, size, in) != size) {
|
||||
mdvi_free(tfm);
|
||||
goto bad_tfm;
|
||||
}
|
||||
/* byte-swap all the tables at once */
|
||||
#ifdef WORD_LITTLE_ENDIAN
|
||||
swap_array((Uint32 *)tfm, size);
|
||||
#endif
|
||||
cb = tfm;
|
||||
charinfo = cb; cb += 2*(ec - bc + 1);
|
||||
widths = cb; cb += nw;
|
||||
heights = cb; cb += nh;
|
||||
depths = cb;
|
||||
|
||||
if(widths[0] || heights[0] || depths[0]) {
|
||||
mdvi_free(tfm);
|
||||
goto bad_tfm;
|
||||
}
|
||||
|
||||
/* from this point on, no error checking is done */
|
||||
|
||||
/* we don't need this anymore */
|
||||
fclose(in);
|
||||
|
||||
/* now we don't read from `ptr' anymore */
|
||||
|
||||
info->loc = bc;
|
||||
info->hic = ec;
|
||||
info->type = DviFontTFM;
|
||||
|
||||
/* allocate characters */
|
||||
info->chars = xnalloc(TFMChar, size);
|
||||
|
||||
/* get the relevant data */
|
||||
ptr = (Uchar *)charinfo;
|
||||
for(i = bc; i <= ec; ptr += 4, i++) {
|
||||
int ndx;
|
||||
|
||||
ndx = muget2(ptr);
|
||||
info->chars[i-bc].advance = widths[ndx];
|
||||
/* TFM files lack this information */
|
||||
info->chars[i-bc].left = 0;
|
||||
info->chars[i-bc].right = widths[ndx];
|
||||
info->chars[i-bc].present = (ndx != 0);
|
||||
ndx = muget1(ptr);
|
||||
info->chars[i-bc].height = heights[ndx];
|
||||
ndx = muget1(ptr);
|
||||
info->chars[i-bc].depth = depths[ndx];
|
||||
}
|
||||
|
||||
mdvi_free(tfm);
|
||||
return 0;
|
||||
|
||||
bad_tfm:
|
||||
mdvi_error(_("%s: File corrupted, or not a TFM file\n"), filename);
|
||||
fclose(in);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *lookup_font_metrics(const char *name, int *type)
|
||||
{
|
||||
char *file;
|
||||
|
||||
switch(*type) {
|
||||
#ifndef WITH_AFM_FILES
|
||||
case DviFontAny:
|
||||
#endif
|
||||
case DviFontTFM:
|
||||
file = kpse_find_tfm(name);
|
||||
*type = DviFontTFM;
|
||||
break;
|
||||
case DviFontOFM: {
|
||||
file = kpse_find_ofm(name);
|
||||
/* we may have gotten a TFM back */
|
||||
if(file != NULL) {
|
||||
const char *ext = file_extension(file);
|
||||
if(ext && STREQ(ext, "tfm"))
|
||||
*type = DviFontTFM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef WITH_AFM_FILES
|
||||
case DviFontAFM:
|
||||
file = kpse_find_file(name, kpse_afm_format, 0);
|
||||
break;
|
||||
case DviFontAny:
|
||||
file = kpse_find_file(name, kpse_afm_format, 0);
|
||||
*type = DviFontAFM;
|
||||
if(file == NULL) {
|
||||
file = kpse_find_tfm(name);
|
||||
*type = DviFontTFM;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/*
|
||||
* The next two functions are just wrappers for the font metric loaders,
|
||||
* and use the pool of TFM data
|
||||
*/
|
||||
|
||||
/* this is how we interpret arguments:
|
||||
* - if filename is NULL, we look for files of the given type,
|
||||
* unless type is DviFontAny, in which case we try all the
|
||||
* types we know of.
|
||||
* - if filename is not NULL, we look at `type' to decide
|
||||
* how to read the file. If type is DviFontAny, we just
|
||||
* return an error.
|
||||
*/
|
||||
TFMInfo *get_font_metrics(const char *short_name, int type, const char *filename)
|
||||
{
|
||||
TFMPool *tfm = NULL;
|
||||
int status;
|
||||
char *file;
|
||||
|
||||
if(tfmpool.count) {
|
||||
tfm = (TFMPool *)mdvi_hash_lookup(&tfmhash,
|
||||
MDVI_KEY(short_name));
|
||||
if(tfm != NULL) {
|
||||
DEBUG((DBG_FONTS, "(mt) reusing metric file `%s' (%d links)\n",
|
||||
short_name, tfm->links));
|
||||
tfm->links++;
|
||||
return &tfm->tfminfo;
|
||||
}
|
||||
}
|
||||
|
||||
file = filename ? (char *)filename : lookup_font_metrics(short_name, &type);
|
||||
if(file == NULL)
|
||||
return NULL;
|
||||
|
||||
tfm = xalloc(TFMPool);
|
||||
DEBUG((DBG_FONTS, "(mt) loading font metric data from `%s'\n", file, file));
|
||||
switch(type) {
|
||||
case DviFontTFM:
|
||||
status = tfm_load_file(file, &tfm->tfminfo);
|
||||
break;
|
||||
case DviFontOFM:
|
||||
status = ofm_load_file(file, &tfm->tfminfo);
|
||||
break;
|
||||
#ifdef WITH_AFM_FILES
|
||||
case DviFontAFM:
|
||||
status = afm_load_file(file, &tfm->tfminfo);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
status = -1;
|
||||
break;
|
||||
}
|
||||
if(file != filename)
|
||||
mdvi_free(file);
|
||||
if(status < 0) {
|
||||
mdvi_free(tfm);
|
||||
return NULL;
|
||||
}
|
||||
tfm->short_name = mdvi_strdup(short_name);
|
||||
|
||||
/* add it to the pool */
|
||||
if(tfmpool.count == 0)
|
||||
mdvi_hash_create(&tfmhash, TFM_HASH_SIZE);
|
||||
mdvi_hash_add(&tfmhash, MDVI_KEY(tfm->short_name),
|
||||
tfm, MDVI_HASH_UNCHECKED);
|
||||
listh_prepend(&tfmpool, LIST(tfm));
|
||||
tfm->links = 1;
|
||||
|
||||
return &tfm->tfminfo;
|
||||
}
|
||||
|
||||
void free_font_metrics(TFMInfo *info)
|
||||
{
|
||||
TFMPool *tfm;
|
||||
|
||||
if(tfmpool.count == 0)
|
||||
return;
|
||||
/* get the entry -- can't use the hash table for this, because
|
||||
* we don't have the short name */
|
||||
for(tfm = (TFMPool *)tfmpool.head; tfm; tfm = tfm->next)
|
||||
if(info == &tfm->tfminfo)
|
||||
break;
|
||||
if(tfm == NULL)
|
||||
return;
|
||||
if(--tfm->links > 0) {
|
||||
DEBUG((DBG_FONTS, "(mt) %s not removed, still in use\n",
|
||||
tfm->short_name));
|
||||
return;
|
||||
}
|
||||
mdvi_hash_remove_ptr(&tfmhash, MDVI_KEY(tfm->short_name));
|
||||
|
||||
DEBUG((DBG_FONTS, "(mt) removing unused TFM data for `%s'\n", tfm->short_name));
|
||||
listh_remove(&tfmpool, LIST(tfm));
|
||||
mdvi_free(tfm->short_name);
|
||||
mdvi_free(tfm->tfminfo.chars);
|
||||
mdvi_free(tfm);
|
||||
}
|
||||
|
||||
void flush_font_metrics(void)
|
||||
{
|
||||
TFMPool *ptr;
|
||||
|
||||
for(; (ptr = (TFMPool *)tfmpool.head); ) {
|
||||
tfmpool.head = LIST(ptr->next);
|
||||
|
||||
mdvi_free(ptr->short_name);
|
||||
mdvi_free(ptr->tfminfo.chars);
|
||||
mdvi_free(ptr);
|
||||
}
|
||||
mdvi_hash_reset(&tfmhash, 0);
|
||||
}
|
|
@ -0,0 +1,495 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "mdvi.h"
|
||||
|
||||
#ifdef WITH_TRUETYPE_FONTS
|
||||
|
||||
#include <string.h>
|
||||
#include <freetype.h>
|
||||
#include <ftxpost.h>
|
||||
#include <ftxerr18.h>
|
||||
|
||||
#include "private.h"
|
||||
|
||||
static TT_Engine tt_handle;
|
||||
static int initialized = 0;
|
||||
|
||||
typedef struct ftinfo {
|
||||
struct ftinfo *next;
|
||||
struct ftinfo *prev;
|
||||
char *fontname;
|
||||
char *fmfname;
|
||||
TT_Face face;
|
||||
TT_Instance instance;
|
||||
TT_Glyph glyph;
|
||||
int hasmetrics;
|
||||
int loaded;
|
||||
int fmftype;
|
||||
TFMInfo *tfminfo;
|
||||
DviFontMapInfo mapinfo;
|
||||
DviEncoding *encoding;
|
||||
} FTInfo;
|
||||
|
||||
static int tt_load_font __PROTO((DviParams *, DviFont *));
|
||||
static int tt_font_get_glyph __PROTO((DviParams *, DviFont *, int));
|
||||
static void tt_free_data __PROTO((DviFont *));
|
||||
static void tt_reset_font __PROTO((DviFont *));
|
||||
static void tt_shrink_glyph
|
||||
__PROTO((DviContext *, DviFont *, DviFontChar *, DviGlyph *));
|
||||
static void tt_font_remove __PROTO((FTInfo *));
|
||||
|
||||
DviFontInfo tt_font_info = {
|
||||
"TT",
|
||||
0,
|
||||
tt_load_font,
|
||||
tt_font_get_glyph,
|
||||
tt_shrink_glyph,
|
||||
mdvi_shrink_glyph_grey,
|
||||
tt_free_data, /* free */
|
||||
tt_reset_font, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_truetype_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
#define FT_HASH_SIZE 31
|
||||
|
||||
static ListHead ttfonts = {NULL, NULL, 0};
|
||||
|
||||
static int init_freetype(void)
|
||||
{
|
||||
TT_Error code;
|
||||
|
||||
ASSERT(initialized == 0);
|
||||
code = TT_Init_FreeType(&tt_handle);
|
||||
if(code) {
|
||||
DEBUG((DBG_TT, "(tt) Init_Freetype: error %d\n", code));
|
||||
return -1;
|
||||
}
|
||||
code = TT_Init_Post_Extension(tt_handle);
|
||||
if(code) {
|
||||
TT_Done_FreeType(tt_handle);
|
||||
return -1;
|
||||
}
|
||||
/* we're on */
|
||||
initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tt_encode_font(DviFont *font, FTInfo *info)
|
||||
{
|
||||
TT_Face_Properties prop;
|
||||
int i;
|
||||
|
||||
if(TT_Get_Face_Properties(info->face, &prop))
|
||||
return;
|
||||
|
||||
for(i = 0; i < prop.num_Glyphs; i++) {
|
||||
char *string;
|
||||
int ndx;
|
||||
|
||||
if(TT_Get_PS_Name(info->face, i, &string))
|
||||
continue;
|
||||
ndx = mdvi_encode_glyph(info->encoding, string);
|
||||
if(ndx < font->loc || ndx > font->hic)
|
||||
continue;
|
||||
font->chars[ndx - font->loc].code = i;
|
||||
}
|
||||
}
|
||||
|
||||
static int tt_really_load_font(DviParams *params, DviFont *font, FTInfo *info)
|
||||
{
|
||||
DviFontChar *ch;
|
||||
TFMChar *ptr;
|
||||
Int32 z, alpha, beta;
|
||||
int i;
|
||||
FTInfo *old;
|
||||
TT_Error status;
|
||||
double point_size;
|
||||
static int warned = 0;
|
||||
TT_CharMap cmap;
|
||||
TT_Face_Properties props;
|
||||
int map_found;
|
||||
|
||||
DEBUG((DBG_TT, "(tt) really_load_font(%s)\n", info->fontname));
|
||||
|
||||
/* get the point size */
|
||||
point_size = (double)font->scale / (params->tfm_conv * 0x100000);
|
||||
point_size = 72.0 * point_size / 72.27;
|
||||
if(info->loaded) {
|
||||
/* just reset the size info */
|
||||
TT_Set_Instance_Resolutions(info->instance,
|
||||
params->dpi, params->vdpi);
|
||||
TT_Set_Instance_CharSize(info->instance, FROUND(point_size * 64));
|
||||
/* FIXME: should extend/slant again */
|
||||
info->hasmetrics = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* load the face */
|
||||
DEBUG((DBG_TT, "(tt) loading new face `%s'\n",
|
||||
info->fontname));
|
||||
status = TT_Open_Face(tt_handle, font->filename, &info->face);
|
||||
if(status) {
|
||||
mdvi_warning(_("(tt) %s: could not load face: %s\n"),
|
||||
info->fontname, TT_ErrToString18(status));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create a new instance of this face */
|
||||
status = TT_New_Instance(info->face, &info->instance);
|
||||
if(status) {
|
||||
mdvi_warning(_("(tt) %s: could not create face: %s\n"),
|
||||
info->fontname, TT_ErrToString18(status));
|
||||
TT_Close_Face(info->face);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create a glyph */
|
||||
status = TT_New_Glyph(info->face, &info->glyph);
|
||||
if(status) {
|
||||
mdvi_warning(_("(tt) %s: could not create glyph: %s\n"),
|
||||
info->fontname, TT_ErrToString18(status));
|
||||
goto tt_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* We'll try to find a Unicode charmap. It's not that important that we
|
||||
* actually find one, especially if the fontmap files are installed
|
||||
* properly, but it's good to have some predefined behaviour
|
||||
*/
|
||||
TT_Get_Face_Properties(info->face, &props);
|
||||
|
||||
map_found = -1;
|
||||
for(i = 0; map_found < 0 && i < props.num_CharMaps; i++) {
|
||||
TT_UShort pid, eid;
|
||||
|
||||
TT_Get_CharMap_ID(info->face, i, &pid, &eid);
|
||||
switch(pid) {
|
||||
case TT_PLATFORM_APPLE_UNICODE:
|
||||
map_found = i;
|
||||
break;
|
||||
case TT_PLATFORM_ISO:
|
||||
if(eid == TT_ISO_ID_7BIT_ASCII ||
|
||||
eid == TT_ISO_ID_8859_1)
|
||||
map_found = 1;
|
||||
break;
|
||||
case TT_PLATFORM_MICROSOFT:
|
||||
if(eid == TT_MS_ID_UNICODE_CS)
|
||||
map_found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(map_found < 0) {
|
||||
mdvi_warning(_("(tt) %s: no acceptable map found, using #0\n"),
|
||||
info->fontname);
|
||||
map_found = 0;
|
||||
}
|
||||
DEBUG((DBG_TT, "(tt) %s: using charmap #%d\n",
|
||||
info->fontname, map_found));
|
||||
TT_Get_CharMap(info->face, map_found, &cmap);
|
||||
|
||||
DEBUG((DBG_TT, "(tt) %s: Set_Char_Size(%.2f, %d, %d)\n",
|
||||
font->fontname, point_size, font->hdpi, font->vdpi));
|
||||
status = TT_Set_Instance_Resolutions(info->instance,
|
||||
params->dpi, params->vdpi);
|
||||
if(status) {
|
||||
error(_("(tt) %s: could not set resolution: %s\n"),
|
||||
info->fontname, TT_ErrToString18(status));
|
||||
goto tt_error;
|
||||
}
|
||||
status = TT_Set_Instance_CharSize(info->instance,
|
||||
FROUND(point_size * 64));
|
||||
if(status) {
|
||||
error(_("(tt) %s: could not set point size: %s\n"),
|
||||
info->fontname, TT_ErrToString18(status));
|
||||
goto tt_error;
|
||||
}
|
||||
|
||||
/* after this point we don't fail */
|
||||
|
||||
/* get information from the fontmap */
|
||||
status = mdvi_query_fontmap(&info->mapinfo, info->fontname);
|
||||
if(!status && info->mapinfo.encoding)
|
||||
info->encoding = mdvi_request_encoding(info->mapinfo.encoding);
|
||||
else
|
||||
info->encoding = NULL;
|
||||
|
||||
if(info->encoding != NULL) {
|
||||
TT_Post post;
|
||||
|
||||
status = TT_Load_PS_Names(info->face, &post);
|
||||
if(status) {
|
||||
mdvi_warning(_("(tt) %s: could not load PS name table\n"),
|
||||
info->fontname);
|
||||
mdvi_release_encoding(info->encoding, 0);
|
||||
info->encoding = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* get the metrics. If this fails, it's not fatal, but certainly bad */
|
||||
info->tfminfo = get_font_metrics(info->fontname,
|
||||
info->fmftype, info->fmfname);
|
||||
|
||||
if(info->tfminfo == NULL) {
|
||||
mdvi_warning("(tt) %s: no metrics data, font ignored\n",
|
||||
info->fontname);
|
||||
goto tt_error;
|
||||
}
|
||||
/* fix this */
|
||||
font->design = info->tfminfo->design;
|
||||
|
||||
/* get the scaled character metrics */
|
||||
get_tfm_chars(params, font, info->tfminfo, 0);
|
||||
|
||||
if(info->encoding)
|
||||
tt_encode_font(font, info);
|
||||
else {
|
||||
mdvi_warning(_("%s: no encoding vector found, expect bad output\n"),
|
||||
info->fontname);
|
||||
/* this is better than nothing */
|
||||
for(i = font->loc; i <= font->hic; i++)
|
||||
font->chars[i - font->loc].code = TT_Char_Index(cmap, i);
|
||||
}
|
||||
|
||||
info->loaded = 1;
|
||||
info->hasmetrics = 1;
|
||||
return 0;
|
||||
|
||||
tt_error:
|
||||
tt_font_remove(info);
|
||||
mdvi_free(font->chars);
|
||||
font->chars = NULL;
|
||||
font->loc = font->hic = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int tt_load_font(DviParams *params, DviFont *font)
|
||||
{
|
||||
int i;
|
||||
FTInfo *info;
|
||||
|
||||
if(!initialized && init_freetype() < 0)
|
||||
return -1;
|
||||
|
||||
if(font->in != NULL) {
|
||||
fclose(font->in);
|
||||
font->in = NULL;
|
||||
}
|
||||
|
||||
info = xalloc(FTInfo);
|
||||
|
||||
memzero(info, sizeof(FTInfo));
|
||||
info->fmftype = DviFontAny; /* any metrics type will do */
|
||||
info->fmfname = lookup_font_metrics(font->fontname, &info->fmftype);
|
||||
info->fontname = font->fontname;
|
||||
info->hasmetrics = 0;
|
||||
info->loaded = 0;
|
||||
|
||||
/* these will be obtained from the fontmaps */
|
||||
info->mapinfo.psname = NULL;
|
||||
info->mapinfo.encoding = NULL;
|
||||
info->mapinfo.fontfile = NULL;
|
||||
info->mapinfo.extend = 0;
|
||||
info->mapinfo.slant = 0;
|
||||
|
||||
/* initialize these */
|
||||
font->chars = xnalloc(DviFontChar, 256);
|
||||
font->loc = 0;
|
||||
font->hic = 255;
|
||||
for(i = 0; i < 256; i++) {
|
||||
font->chars[i].offset = 1;
|
||||
font->chars[i].glyph.data = NULL;
|
||||
font->chars[i].shrunk.data = NULL;
|
||||
font->chars[i].grey.data = NULL;
|
||||
}
|
||||
|
||||
if(info->fmfname == NULL)
|
||||
mdvi_warning(_("(tt) %s: no font metric data\n"), font->fontname);
|
||||
|
||||
listh_append(&ttfonts, LIST(info));
|
||||
font->private = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tt_get_bitmap(DviParams *params, DviFont *font,
|
||||
int code, double xscale, double yscale, DviGlyph *glyph)
|
||||
{
|
||||
TT_Outline outline;
|
||||
TT_Raster_Map raster;
|
||||
TT_BBox bbox;
|
||||
TT_Glyph_Metrics metrics;
|
||||
TT_Matrix mat;
|
||||
FTInfo *info;
|
||||
int error;
|
||||
int have_outline = 0;
|
||||
int w, h;
|
||||
|
||||
info = (FTInfo *)font->private;
|
||||
if(info == NULL)
|
||||
return -1;
|
||||
|
||||
error = TT_Load_Glyph(info->instance, info->glyph,
|
||||
code, TTLOAD_DEFAULT);
|
||||
if(error) goto tt_error;
|
||||
error = TT_Get_Glyph_Outline(info->glyph, &outline);
|
||||
if(error) goto tt_error;
|
||||
have_outline = 1;
|
||||
mat.xx = FROUND(xscale * 65536);
|
||||
mat.yy = FROUND(yscale * 65536);
|
||||
mat.yx = 0;
|
||||
mat.xy = 0;
|
||||
TT_Transform_Outline(&outline, &mat);
|
||||
error = TT_Get_Outline_BBox(&outline, &bbox);
|
||||
if(error) goto tt_error;
|
||||
bbox.xMin &= -64;
|
||||
bbox.yMin &= -64;
|
||||
bbox.xMax = (bbox.xMax + 63) & -64;
|
||||
bbox.yMax = (bbox.yMax + 63) & -64;
|
||||
w = (bbox.xMax - bbox.xMin) / 64;
|
||||
h = (bbox.yMax - bbox.yMin) / 64;
|
||||
|
||||
glyph->w = w;
|
||||
glyph->h = h;
|
||||
glyph->x = -bbox.xMin / 64;
|
||||
glyph->y = bbox.yMax / 64;
|
||||
if(!w || !h)
|
||||
goto tt_error;
|
||||
raster.rows = h;
|
||||
raster.width = w;
|
||||
raster.cols = ROUND(w, 8);
|
||||
raster.size = h * raster.cols;
|
||||
raster.flow = TT_Flow_Down;
|
||||
raster.bitmap = mdvi_calloc(h, raster.cols);
|
||||
|
||||
TT_Translate_Outline(&outline, -bbox.xMin, -bbox.yMin);
|
||||
TT_Get_Outline_Bitmap(tt_handle, &outline, &raster);
|
||||
glyph->data = bitmap_convert_msb8(raster.bitmap, w, h, ROUND(w, 8));
|
||||
TT_Done_Outline(&outline);
|
||||
mdvi_free(raster.bitmap);
|
||||
|
||||
return 0;
|
||||
tt_error:
|
||||
if(have_outline)
|
||||
TT_Done_Outline(&outline);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int tt_font_get_glyph(DviParams *params, DviFont *font, int code)
|
||||
{
|
||||
FTInfo *info = (FTInfo *)font->private;
|
||||
DviFontChar *ch;
|
||||
int error;
|
||||
double xs, ys;
|
||||
int dpi;
|
||||
|
||||
ASSERT(info != NULL);
|
||||
if(!info->hasmetrics && tt_really_load_font(params, font, info) < 0)
|
||||
return -1;
|
||||
ch = FONTCHAR(font, code);
|
||||
if(!ch || !glyph_present(ch))
|
||||
return -1;
|
||||
ch->loaded = 1;
|
||||
if(!ch->width || !ch->height)
|
||||
goto blank;
|
||||
if(ch->code == 0) {
|
||||
ch->glyph.data = NULL;
|
||||
goto missing;
|
||||
}
|
||||
/* get the glyph */
|
||||
dpi = Max(font->hdpi, font->vdpi);
|
||||
error = tt_get_bitmap(params, font, ch->code,
|
||||
(double)font->hdpi / dpi,
|
||||
(double)font->vdpi / dpi,
|
||||
&ch->glyph);
|
||||
if(error)
|
||||
goto missing;
|
||||
ch->x = ch->glyph.x;
|
||||
ch->y = ch->glyph.y;
|
||||
|
||||
return 0;
|
||||
|
||||
missing:
|
||||
ch->glyph.data = MDVI_GLYPH_EMPTY;
|
||||
ch->missing = 1;
|
||||
blank:
|
||||
ch->glyph.w = ch->width;
|
||||
ch->glyph.h = ch->height;
|
||||
ch->glyph.x = ch->x;
|
||||
ch->glyph.y = ch->y;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tt_shrink_glyph(DviContext *dvi, DviFont *font, DviFontChar *ch, DviGlyph *dest)
|
||||
{
|
||||
tt_get_bitmap(&dvi->params, font,
|
||||
ch->code,
|
||||
(double)font->hdpi / (dvi->params.dpi * dvi->params.hshrink),
|
||||
(double)font->vdpi / (dvi->params.vdpi * dvi->params.vshrink),
|
||||
dest);
|
||||
/* transform the glyph for the current orientation */
|
||||
font_transform_glyph(dvi->params.orientation, dest);
|
||||
}
|
||||
|
||||
static void tt_reset_font(DviFont *font)
|
||||
{
|
||||
FTInfo *info = (FTInfo *)font->private;
|
||||
|
||||
if(info == NULL)
|
||||
return;
|
||||
info->hasmetrics = 0;
|
||||
}
|
||||
|
||||
static void tt_font_remove(FTInfo *info)
|
||||
{
|
||||
FTInfo *old;
|
||||
|
||||
if(info->loaded) {
|
||||
/* all fonts in the hash table have called TT_Open_Face */
|
||||
TT_Done_Instance(info->instance);
|
||||
TT_Close_Face(info->face);
|
||||
}
|
||||
listh_remove(&ttfonts, LIST(info));
|
||||
/* release our encodings */
|
||||
if(info->encoding)
|
||||
mdvi_release_encoding(info->encoding, 1);
|
||||
/* and destroy the font */
|
||||
if(info->tfminfo)
|
||||
free_font_metrics(info->tfminfo);
|
||||
if(info->fmfname)
|
||||
mdvi_free(info->fmfname);
|
||||
mdvi_free(info);
|
||||
}
|
||||
|
||||
static void tt_free_data(DviFont *font)
|
||||
{
|
||||
if(font->private == NULL)
|
||||
return;
|
||||
|
||||
tt_font_remove((FTInfo *)font->private);
|
||||
if(initialized && ttfonts.count == 0) {
|
||||
DEBUG((DBG_TT, "(tt) last font removed -- closing FreeType\n"));
|
||||
TT_Done_FreeType(tt_handle);
|
||||
initialized = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* WITH_TRUETYPE_FONTS */
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "private.h"
|
||||
|
||||
static char *const messages[] = {
|
||||
_G("Ooops!"),
|
||||
_G("Aieeeee!!"),
|
||||
_G("Ouch!"),
|
||||
_G("Houston, we have a problem"),
|
||||
_G("3.. 2.. 1.. BOOM!"),
|
||||
_G("I'm history"),
|
||||
_G("I'm going down"),
|
||||
_G("I smell a rat")
|
||||
};
|
||||
#define NMSGS (sizeof(messages) / sizeof(char *))
|
||||
|
||||
static FILE *logfile = NULL;
|
||||
static int _mdvi_log_level;
|
||||
|
||||
int mdvi_set_logfile(const char *filename);
|
||||
int mdvi_set_logstream(FILE *file);
|
||||
int mdvi_set_loglevel(int level);
|
||||
|
||||
static void vputlog(int level, const char *head, const char *format, va_list ap)
|
||||
{
|
||||
if(logfile != NULL && _mdvi_log_level >= level) {
|
||||
if(head != NULL)
|
||||
fprintf(logfile, "%s: ", head);
|
||||
vfprintf(logfile, format, ap);
|
||||
}
|
||||
}
|
||||
|
||||
int mdvi_set_logfile(const char *filename)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
|
||||
if(filename && (f = fopen(filename, "w")) == NULL)
|
||||
return -1;
|
||||
if(logfile != NULL && !isatty(fileno(logfile))) {
|
||||
fclose(logfile);
|
||||
logfile = NULL;
|
||||
}
|
||||
if(filename)
|
||||
logfile = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdvi_set_logstream(FILE *file)
|
||||
{
|
||||
if(logfile && !isatty(fileno(logfile))) {
|
||||
fclose(logfile);
|
||||
logfile = NULL;
|
||||
}
|
||||
logfile = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdvi_set_loglevel(int level)
|
||||
{
|
||||
int old = _mdvi_log_level;
|
||||
|
||||
_mdvi_log_level = level;
|
||||
return old;
|
||||
}
|
||||
|
||||
#ifndef NODEBUG
|
||||
Uint32 _mdvi_debug_mask = 0;
|
||||
|
||||
void __debug(int mask, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
if(_mdvi_debug_mask & mask) {
|
||||
if(!DEBUGGING(SILENT)) {
|
||||
fprintf(stderr, "Debug: ");
|
||||
vfprintf(stderr, format, ap);
|
||||
fflush(stderr);
|
||||
}
|
||||
#ifndef __GNUC__
|
||||
/* let's be portable */
|
||||
va_end(ap);
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
vputlog(LOG_DEBUG, "Debug", format, ap);
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
void mdvi_message(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
if(_mdvi_log_level >= LOG_INFO) {
|
||||
fprintf(stderr, "%s: ", program_name);
|
||||
vfprintf(stderr, format, ap);
|
||||
#ifndef __GNUC__
|
||||
va_end(ap);
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
}
|
||||
vputlog(LOG_INFO, NULL, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void mdvi_crash(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
fprintf(stderr, "%s: %s: ",
|
||||
program_name,
|
||||
gettext(messages[(int)time(NULL) % NMSGS]));
|
||||
vfprintf(stderr, format, ap);
|
||||
#ifndef __GNUC__
|
||||
/* let's be portable */
|
||||
va_end(ap);
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
vputlog(LOG_ERROR, _("Crashing"), format, ap);
|
||||
va_end(ap);
|
||||
abort();
|
||||
}
|
||||
|
||||
void mdvi_error(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
fprintf(stderr, _("%s: Error: "), program_name);
|
||||
vfprintf(stderr, format, ap);
|
||||
#ifndef __GNUC__
|
||||
/* let's be portable */
|
||||
va_end(ap);
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
vputlog(LOG_ERROR, _("Error"), format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void mdvi_warning(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
fprintf(stderr, _("%s: Warning: "), program_name);
|
||||
vfprintf(stderr, format, ap);
|
||||
#ifndef __GNUC__
|
||||
/* let's be portable */
|
||||
va_end(ap);
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
vputlog(LOG_WARN, _("Warning"), format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void mdvi_fatal(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
fprintf(stderr, _("%s: Fatal: "), program_name);
|
||||
vfprintf(stderr, format, ap);
|
||||
#ifndef __GNUC__
|
||||
/* let's be portable */
|
||||
va_end(ap);
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
vputlog(LOG_ERROR, _("Fatal"), format, ap);
|
||||
va_end(ap);
|
||||
#ifndef NODEBUG
|
||||
abort();
|
||||
#else
|
||||
exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void *mdvi_malloc(size_t nelems)
|
||||
{
|
||||
void *ptr = malloc(nelems);
|
||||
|
||||
if(ptr == NULL)
|
||||
mdvi_fatal(_("out of memory allocating %u bytes\n"),
|
||||
(unsigned)nelems);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *mdvi_realloc(void *data, size_t newsize)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if(newsize == 0)
|
||||
mdvi_crash(_("attempted to reallocate with zero size\n"));
|
||||
ptr = realloc(data, newsize);
|
||||
if(ptr == NULL)
|
||||
mdvi_fatal(_("failed to reallocate %u bytes\n"), (unsigned)newsize);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *mdvi_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if(nmemb == 0)
|
||||
mdvi_crash(_("attempted to callocate 0 members\n"));
|
||||
if(size == 0)
|
||||
mdvi_crash(_("attempted to callocate %u members with size 0\n"),
|
||||
(unsigned)nmemb);
|
||||
ptr = calloc(nmemb, size);
|
||||
if(ptr == 0)
|
||||
mdvi_fatal(_("failed to allocate %ux%u bytes\n"),
|
||||
(unsigned)nmemb, (unsigned)size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void mdvi_free(void *ptr)
|
||||
{
|
||||
if(ptr == NULL)
|
||||
mdvi_crash(_("attempted to free NULL pointer\n"));
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
char *mdvi_strdup(const char *string)
|
||||
{
|
||||
int length;
|
||||
char *ptr;
|
||||
|
||||
length = strlen(string) + 1;
|
||||
ptr = (char *)mdvi_malloc(length);
|
||||
memcpy(ptr, string, length);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* `to' should have room for length+1 bytes */
|
||||
char *mdvi_strncpy(char *to, const char *from, size_t length)
|
||||
{
|
||||
strncpy(to, from, length);
|
||||
to[length] = '\0';
|
||||
return to;
|
||||
}
|
||||
|
||||
char *mdvi_strndup(const char *string, size_t length)
|
||||
{
|
||||
int n;
|
||||
char *ptr;
|
||||
|
||||
n = strlen(string);
|
||||
if(n > length)
|
||||
n = length;
|
||||
ptr = (char *)mdvi_malloc(n + 1);
|
||||
memcpy(ptr, string, n);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *mdvi_memdup(const void *data, size_t length)
|
||||
{
|
||||
void *ptr = mdvi_malloc(length);
|
||||
|
||||
memcpy(ptr, data, length);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *mdvi_strrstr (const char *haystack, const char *needle)
|
||||
{
|
||||
size_t i;
|
||||
size_t needle_len;
|
||||
size_t haystack_len;
|
||||
const char *p;
|
||||
|
||||
needle_len = strlen (needle);
|
||||
haystack_len = strlen (haystack);
|
||||
|
||||
if (needle_len == 0)
|
||||
return NULL;
|
||||
|
||||
if (haystack_len < needle_len)
|
||||
return (char *)haystack;
|
||||
|
||||
p = haystack + haystack_len - needle_len;
|
||||
while (p >= haystack) {
|
||||
for (i = 0; i < needle_len; i++)
|
||||
if (p[i] != needle[i])
|
||||
goto next;
|
||||
|
||||
return (char *)p;
|
||||
|
||||
next:
|
||||
p--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *mdvi_build_path_from_cwd (const char *path)
|
||||
{
|
||||
char *ptr;
|
||||
char *buf = NULL;
|
||||
size_t buf_size = 512;
|
||||
|
||||
while (1) {
|
||||
buf = mdvi_realloc (buf, buf_size);
|
||||
if ((ptr = getcwd (buf, buf_size)) == NULL && errno == ERANGE) {
|
||||
buf_size *= 2;
|
||||
} else {
|
||||
buf = ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buf = mdvi_realloc (buf, strlen (buf) + strlen (path) + 2);
|
||||
strcat (buf, "/");
|
||||
strncat (buf, path, strlen (path));
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
double unit2pix_factor(const char *spec)
|
||||
{
|
||||
double val;
|
||||
double factor;
|
||||
const char *p, *q;
|
||||
static const char *units = "incmmmmtptpcddccspbpftydcs";
|
||||
|
||||
val = 0.0;
|
||||
|
||||
for(p = spec; *p >= '0' && *p <= '9'; p++)
|
||||
val = 10.0 * val + (double)(*p - '0');
|
||||
if(*p == '.') {
|
||||
p++;
|
||||
factor = 0.1;
|
||||
while(*p && *p >= '0' && *p <= '9') {
|
||||
val += (*p++ - '0') * factor;
|
||||
factor = factor * 0.1;
|
||||
}
|
||||
}
|
||||
factor = 1.0;
|
||||
for(q = units; *q; q += 2) {
|
||||
if(p[0] == q[0] && p[1] == q[1])
|
||||
break;
|
||||
}
|
||||
switch((int)(q - units)) {
|
||||
/*in*/ case 0: factor = 1.0; break;
|
||||
/*cm*/ case 2: factor = 1.0 / 2.54; break;
|
||||
/*mm*/ case 4: factor = 1.0 / 25.4; break;
|
||||
/*mt*/ case 6: factor = 1.0 / 0.0254; break;
|
||||
/*pt*/ case 8: factor = 1.0 / 72.27; break;
|
||||
/*pc*/ case 10: factor = 12.0 / 72.27; break;
|
||||
/*dd*/ case 12: factor = (1238.0 / 1157.0) / 72.27; break;
|
||||
/*cc*/ case 14: factor = 12 * (1238.0 / 1157.0) / 72.27; break;
|
||||
/*sp*/ case 16: factor = 1.0 / (72.27 * 65536); break;
|
||||
/*bp*/ case 18: factor = 1.0 / 72.0; break;
|
||||
/*ft*/ case 20: factor = 12.0; break;
|
||||
/*yd*/ case 22: factor = 36.0; break;
|
||||
/*cs*/ case 24: factor = 1.0 / 72000.0; break;
|
||||
default: factor = 1.0;
|
||||
}
|
||||
return factor * val;
|
||||
}
|
||||
|
||||
int unit2pix(int dpi, const char *spec)
|
||||
{
|
||||
double factor = unit2pix_factor(spec);
|
||||
|
||||
return (int)(factor * dpi + 0.5);
|
||||
}
|
||||
|
||||
Ulong get_mtime(int fd)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if(fstat(fd, &st) == 0)
|
||||
return (Ulong)st.st_mtime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *xstradd(char *dest, size_t *size, size_t n, const char *src, size_t m)
|
||||
{
|
||||
if(m == 0)
|
||||
m = strlen(src);
|
||||
if(n + m >= *size) {
|
||||
dest = mdvi_realloc(dest, n + m + 1);
|
||||
*size = n + m + 1;
|
||||
}
|
||||
memcpy(dest + n, src, m);
|
||||
dest[n + m] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *getword(char *string, const char *delim, char **end)
|
||||
{
|
||||
char *ptr;
|
||||
char *word;
|
||||
|
||||
/* skip leading delimiters */
|
||||
for(ptr = string; *ptr && strchr(delim, *ptr); ptr++);
|
||||
|
||||
if(*ptr == 0)
|
||||
return NULL;
|
||||
word = ptr++;
|
||||
/* skip non-delimiters */
|
||||
while(*ptr && !strchr(delim, *ptr))
|
||||
ptr++;
|
||||
*end = (char *)ptr;
|
||||
return word;
|
||||
}
|
||||
|
||||
char *getstring(char *string, const char *delim, char **end)
|
||||
{
|
||||
char *ptr;
|
||||
char *word;
|
||||
int quoted = 0;
|
||||
|
||||
/* skip leading delimiters */
|
||||
for(ptr = string; *ptr && strchr(delim, *ptr); ptr++);
|
||||
|
||||
if(ptr == NULL)
|
||||
return NULL;
|
||||
quoted = (*ptr == '"');
|
||||
if(quoted)
|
||||
for(word = ++ptr; *ptr && *ptr != '"'; ptr++);
|
||||
else
|
||||
for(word = ptr; *ptr && !strchr(delim, *ptr); ptr++);
|
||||
*end = (char *)ptr;
|
||||
return word;
|
||||
}
|
||||
|
||||
static long pow2(size_t n)
|
||||
{
|
||||
long x = 8; /* don't bother allocating less than this */
|
||||
|
||||
while(x < n)
|
||||
x <<= 1L;
|
||||
return x;
|
||||
}
|
||||
|
||||
void dstring_init(Dstring *dstr)
|
||||
{
|
||||
dstr->data = NULL;
|
||||
dstr->size = 0;
|
||||
dstr->length = 0;
|
||||
}
|
||||
|
||||
int dstring_append(Dstring *dstr, const char *string, int len)
|
||||
{
|
||||
if(len < 0)
|
||||
len = strlen(string);
|
||||
if(len) {
|
||||
if(dstr->length + len >= dstr->size) {
|
||||
dstr->size = pow2(dstr->length + len + 1);
|
||||
dstr->data = mdvi_realloc(dstr->data, dstr->size);
|
||||
}
|
||||
memcpy(dstr->data + dstr->length, string, len);
|
||||
dstr->length += len;
|
||||
dstr->data[dstr->length] = 0;
|
||||
} else if(dstr->size == 0) {
|
||||
ASSERT(dstr->data == NULL);
|
||||
dstr->size = 8;
|
||||
dstr->data = mdvi_malloc(8);
|
||||
dstr->data[0] = 0;
|
||||
}
|
||||
|
||||
return dstr->length;
|
||||
}
|
||||
|
||||
int dstring_copy(Dstring *dstr, int pos, const char *string, int len)
|
||||
{
|
||||
ASSERT(pos >= 0);
|
||||
if(len < 0)
|
||||
len = strlen(string);
|
||||
if(len) {
|
||||
if(pos + len >= dstr->length) {
|
||||
dstr->length = pos;
|
||||
return dstring_append(dstr, string, len);
|
||||
}
|
||||
memcpy(dstr->data + pos, string, len);
|
||||
}
|
||||
return dstr->length;
|
||||
}
|
||||
|
||||
int dstring_insert(Dstring *dstr, int pos, const char *string, int len)
|
||||
{
|
||||
ASSERT(pos >= 0);
|
||||
if(pos == dstr->length)
|
||||
return dstring_append(dstr, string, len);
|
||||
if(len < 0)
|
||||
len = strlen(string);
|
||||
if(len) {
|
||||
if(dstr->length + len >= dstr->size) {
|
||||
dstr->size = pow2(dstr->length + len + 1);
|
||||
dstr->data = mdvi_realloc(dstr->data, dstr->size);
|
||||
}
|
||||
/* make room */
|
||||
memmove(dstr->data + pos, dstr->data + pos + len, len);
|
||||
/* now copy */
|
||||
memcpy(dstr->data + pos, string, len);
|
||||
dstr->length += len;
|
||||
dstr->data[dstr->length] = 0;
|
||||
}
|
||||
return dstr->length;
|
||||
}
|
||||
|
||||
int dstring_new(Dstring *dstr, const char *string, int len)
|
||||
{
|
||||
if(len < 0)
|
||||
len = strlen(string);
|
||||
if(len) {
|
||||
dstr->size = pow2(len + 1);
|
||||
dstr->data = mdvi_malloc(dstr->size * len);
|
||||
memcpy(dstr->data, string, len);
|
||||
} else
|
||||
dstring_init(dstr);
|
||||
return dstr->length;
|
||||
}
|
||||
|
||||
void dstring_reset(Dstring *dstr)
|
||||
{
|
||||
if(dstr->data)
|
||||
mdvi_free(dstr->data);
|
||||
dstring_init(dstr);
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
/* vf.c -- VF font support */
|
||||
/*
|
||||
* Copyright (C) 2000, Matias Atria
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mdvi.h"
|
||||
#include "private.h"
|
||||
|
||||
static int vf_load_font __PROTO((DviParams *, DviFont *));
|
||||
static void vf_free_macros __PROTO((DviFont *));
|
||||
|
||||
/* only symbol exported by this file */
|
||||
DviFontInfo vf_font_info = {
|
||||
"VF",
|
||||
1, /* virtual fonts scale just fine */
|
||||
vf_load_font,
|
||||
NULL, /* get_glyph */
|
||||
NULL, /* shrink0 */
|
||||
NULL, /* shrink1 */
|
||||
vf_free_macros,
|
||||
NULL, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_vf_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
DviFontInfo ovf_font_info = {
|
||||
"OVF",
|
||||
1, /* virtual fonts scale just fine */
|
||||
vf_load_font,
|
||||
NULL, /* get_glyph */
|
||||
NULL, /* shrink0 */
|
||||
NULL, /* shrink1 */
|
||||
vf_free_macros,
|
||||
NULL, /* reset */
|
||||
NULL, /* lookup */
|
||||
kpse_ovf_format,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int vf_load_font(DviParams *params, DviFont *font)
|
||||
{
|
||||
FILE *p;
|
||||
Uchar *macros;
|
||||
int msize;
|
||||
int mlen;
|
||||
Int32 checksum;
|
||||
long alpha, beta, z;
|
||||
int op;
|
||||
int i;
|
||||
int nchars;
|
||||
int loc, hic;
|
||||
DviFontRef *last;
|
||||
|
||||
macros = NULL;
|
||||
msize = mlen = 0;
|
||||
p = font->in;
|
||||
|
||||
if(fuget1(p) != 247 || fuget1(p) != 202)
|
||||
goto badvf;
|
||||
mlen = fuget1(p);
|
||||
fseek(p, (long)mlen, SEEK_CUR);
|
||||
checksum = fuget4(p);
|
||||
if(checksum && font->checksum && checksum != font->checksum) {
|
||||
mdvi_warning(_("%s: Checksum mismatch (expected %u, got %u)\n"),
|
||||
font->fontname, font->checksum, checksum);
|
||||
} else if(!font->checksum)
|
||||
font->checksum = checksum;
|
||||
font->design = fuget4(p);
|
||||
|
||||
/* read all the fonts in the preamble */
|
||||
last = NULL;
|
||||
|
||||
/* initialize alpha, beta and z for TFM width computation */
|
||||
TFMPREPARE(font->scale, z, alpha, beta);
|
||||
|
||||
op = fuget1(p);
|
||||
while(op >= DVI_FNT_DEF1 && op <= DVI_FNT_DEF4) {
|
||||
DviFontRef *ref;
|
||||
Int32 scale, design;
|
||||
Uint32 checksum;
|
||||
int id;
|
||||
int n;
|
||||
int hdpi;
|
||||
int vdpi;
|
||||
char *name;
|
||||
|
||||
/* process fnt_def commands */
|
||||
|
||||
id = fugetn(p, op - DVI_FNT_DEF1 + 1);
|
||||
checksum = fuget4(p);
|
||||
scale = fuget4(p);
|
||||
design = fuget4(p);
|
||||
|
||||
/* scale this font according to our parent's scale */
|
||||
scale = TFMSCALE(scale, z, alpha, beta);
|
||||
design = FROUND(params->tfm_conv * design);
|
||||
|
||||
/* compute the resolution */
|
||||
hdpi = FROUND(params->mag * params->dpi * scale / design);
|
||||
vdpi = FROUND(params->mag * params->vdpi * scale / design);
|
||||
n = fuget1(p) + fuget1(p);
|
||||
name = mdvi_malloc(n + 1);
|
||||
fread(name, 1, n, p);
|
||||
name[n] = 0;
|
||||
DEBUG((DBG_FONTS, "(vf) %s: defined font `%s' at %.1fpt (%dx%d dpi)\n",
|
||||
font->fontname, name,
|
||||
(double)scale / (params->tfm_conv * 0x100000), hdpi, vdpi));
|
||||
|
||||
/* get the font */
|
||||
ref = font_reference(params, id, name, checksum, hdpi, vdpi, scale);
|
||||
if(ref == NULL) {
|
||||
mdvi_error(_("(vf) %s: could not load font `%s'\n"),
|
||||
font->fontname, name);
|
||||
goto error;
|
||||
}
|
||||
mdvi_free(name);
|
||||
if(last == NULL)
|
||||
font->subfonts = last = ref;
|
||||
else
|
||||
last->next = ref;
|
||||
ref->next = NULL;
|
||||
op = fuget1(p);
|
||||
}
|
||||
|
||||
if(op >= DVI_FNT_DEF1 && op <= DVI_FNT_DEF4)
|
||||
goto error;
|
||||
|
||||
/* This function correctly reads both .vf and .ovf files */
|
||||
|
||||
font->chars = xnalloc(DviFontChar, 256);
|
||||
for(i = 0; i < 256; i++)
|
||||
font->chars[i].offset = 0;
|
||||
nchars = 256;
|
||||
loc = -1; hic = -1;
|
||||
/* now read the characters themselves */
|
||||
while(op <= 242) {
|
||||
int pl;
|
||||
Int32 cc;
|
||||
Int32 tfm;
|
||||
|
||||
if(op == 242) {
|
||||
pl = fuget4(p);
|
||||
cc = fuget4(p);
|
||||
tfm = fuget4(p);
|
||||
} else {
|
||||
pl = op;
|
||||
cc = fuget1(p);
|
||||
tfm = fuget3(p);
|
||||
}
|
||||
if (cc < 0 || cc > 65536) {
|
||||
/* TeX engines do not support char codes bigger than 65535 */
|
||||
mdvi_error(_("(vf) %s: unexpected character %d\n"),
|
||||
font->fontname, cc);
|
||||
goto error;
|
||||
}
|
||||
if(loc < 0 || cc < loc)
|
||||
loc = cc;
|
||||
if(hic < 0 || cc > hic)
|
||||
hic = cc;
|
||||
if(cc >= nchars) {
|
||||
font->chars = xresize(font->chars,
|
||||
DviFontChar, cc + 16);
|
||||
for(i = nchars; i < cc + 16; i++)
|
||||
font->chars[i].offset = 0;
|
||||
nchars = cc + 16;
|
||||
}
|
||||
if(font->chars[cc].offset) {
|
||||
mdvi_error(_("(vf) %s: character %d redefined\n"),
|
||||
font->fontname, cc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
DEBUG((DBG_GLYPHS, "(vf) %s: defined character %d (macro length %d)\n",
|
||||
font->fontname, cc, pl));
|
||||
font->chars[cc].width = pl + 1;
|
||||
font->chars[cc].code = cc;
|
||||
font->chars[cc].tfmwidth = TFMSCALE(tfm, z, alpha, beta);
|
||||
font->chars[cc].offset = mlen;
|
||||
font->chars[cc].loaded = 1;
|
||||
if(mlen + pl + 1 > msize) {
|
||||
msize = mlen + pl + 256;
|
||||
macros = xresize(macros, Uchar, msize);
|
||||
}
|
||||
if(pl && fread(macros + mlen, 1, pl, p) != pl)
|
||||
break;
|
||||
macros[mlen+pl] = DVI_EOP;
|
||||
mlen += pl + 1;
|
||||
op = fuget1(p);
|
||||
}
|
||||
if(op != 248) {
|
||||
mdvi_error(_("(vf) %s: no postamble\n"), font->fontname);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* make macro memory just big enough */
|
||||
if(msize > mlen) {
|
||||
macros = xresize(macros, Uchar, mlen);
|
||||
msize = mlen;
|
||||
}
|
||||
|
||||
DEBUG((DBG_FONTS|DBG_GLYPHS,
|
||||
"(vf) %s: macros use %d bytes\n", font->fontname, msize));
|
||||
|
||||
if(loc > 0 || hic < nchars-1) {
|
||||
memmove(font->chars, font->chars + loc,
|
||||
(hic - loc + 1) * sizeof(DviFontChar));
|
||||
font->chars = xresize(font->chars,
|
||||
DviFontChar, hic - loc + 1);
|
||||
}
|
||||
font->loc = loc;
|
||||
font->hic = hic;
|
||||
font->private = macros;
|
||||
|
||||
return 0;
|
||||
|
||||
badvf:
|
||||
mdvi_error(_("%s: File corrupted, or not a VF file.\n"), font->fontname);
|
||||
error:
|
||||
if(font->chars)
|
||||
mdvi_free(font->chars);
|
||||
if(macros)
|
||||
mdvi_free(macros);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void vf_free_macros(DviFont *font)
|
||||
{
|
||||
mdvi_free(font->private);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
SUBDIRS = minizip
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-I$(srcdir)/minizip \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(WARN_CXXFLAGS) \
|
||||
$(EPUB_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libepubdocument.la
|
||||
|
||||
libepubdocument_la_SOURCES = \
|
||||
epub-document.c \
|
||||
epub-document.h
|
||||
|
||||
libepubdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libepubdocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
minizip/libminizip.la \
|
||||
$(EPUB_LIBS) \
|
||||
$(BACKEND_LIBS)
|
||||
|
||||
|
||||
backend_in_files = epubdocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
|||
#ifndef __EPUB_DOCUMENT_H__
|
||||
#define __EPUB_DOCUMENT_H__
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define EPUB_TYPE_DOCUMENT (epub_document_get_type ())
|
||||
#define EPUB_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPUB_TYPE_DOCUMENT, EpubDocument))
|
||||
#define EPUB_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPUB_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _EpubDocument EpubDocument;
|
||||
|
||||
GType epub_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __EPUB_DOCUMENT_H__ */
|
|
@ -0,0 +1,4 @@
|
|||
[Atril Backend]
|
||||
Module=epubdocument
|
||||
TypeDescription=epub Documents
|
||||
MimeType=application/epub+zip;
|
|
@ -0,0 +1,16 @@
|
|||
AM_CPPFLAGS = \
|
||||
$(WARN_CFLAGS) \
|
||||
$(ZLIB_CFLAGS)
|
||||
|
||||
noinst_LTLIBRARIES = libminizip.la
|
||||
|
||||
libminizip_la_SOURCES = \
|
||||
unzip.c \
|
||||
ioapi.c \
|
||||
unzip.h \
|
||||
ioapi.h
|
||||
|
||||
libminizip_la_LIBADD = \
|
||||
$(ZLIB_LIBS)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,247 @@
|
|||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(IOAPI_NO_64)
|
||||
// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
|
||||
#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello(stream)
|
||||
#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
|
||||
#else
|
||||
#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
|
||||
#define FTELLO_FUNC(stream) ftello64(stream)
|
||||
#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
|
||||
#endif
|
||||
|
||||
|
||||
#include "ioapi.h"
|
||||
|
||||
voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
|
||||
{
|
||||
if (pfilefunc->zfile_func64.zopen64_file != NULL)
|
||||
return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
|
||||
else
|
||||
{
|
||||
return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
|
||||
}
|
||||
}
|
||||
|
||||
long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
|
||||
{
|
||||
if (pfilefunc->zfile_func64.zseek64_file != NULL)
|
||||
return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
|
||||
else
|
||||
{
|
||||
uLong offsetTruncated = (uLong)offset;
|
||||
if (offsetTruncated != offset)
|
||||
return -1;
|
||||
else
|
||||
return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
|
||||
}
|
||||
}
|
||||
|
||||
ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
|
||||
{
|
||||
if (pfilefunc->zfile_func64.zseek64_file != NULL)
|
||||
return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
|
||||
else
|
||||
{
|
||||
uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
|
||||
if ((tell_uLong) == MAXU32)
|
||||
return (ZPOS64_T)-1;
|
||||
else
|
||||
return tell_uLong;
|
||||
}
|
||||
}
|
||||
|
||||
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
|
||||
{
|
||||
p_filefunc64_32->zfile_func64.zopen64_file = NULL;
|
||||
p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
|
||||
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
|
||||
p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
|
||||
p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
|
||||
p_filefunc64_32->zfile_func64.ztell64_file = NULL;
|
||||
p_filefunc64_32->zfile_func64.zseek64_file = NULL;
|
||||
p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
|
||||
p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
|
||||
p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
|
||||
p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
|
||||
p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
|
||||
static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
|
||||
static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
|
||||
static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
|
||||
static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
|
||||
static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
|
||||
static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
|
||||
|
||||
static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
|
||||
{
|
||||
FILE* file = NULL;
|
||||
const char* mode_fopen = NULL;
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
|
||||
mode_fopen = "rb";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
|
||||
mode_fopen = "r+b";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||
mode_fopen = "wb";
|
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL))
|
||||
file = fopen(filename, mode_fopen);
|
||||
return file;
|
||||
}
|
||||
|
||||
static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
|
||||
{
|
||||
FILE* file = NULL;
|
||||
const char* mode_fopen = NULL;
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
|
||||
mode_fopen = "rb";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
|
||||
mode_fopen = "r+b";
|
||||
else
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE)
|
||||
mode_fopen = "wb";
|
||||
|
||||
if ((filename!=NULL) && (mode_fopen != NULL))
|
||||
file = FOPEN_FUNC((const char*)filename, mode_fopen);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
|
||||
{
|
||||
uLong ret;
|
||||
ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
|
||||
{
|
||||
long ret;
|
||||
ret = ftell((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
|
||||
{
|
||||
ZPOS64_T ret;
|
||||
ret = FTELLO_FUNC((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
|
||||
{
|
||||
int fseek_origin=0;
|
||||
long ret;
|
||||
switch (origin)
|
||||
{
|
||||
case ZLIB_FILEFUNC_SEEK_CUR :
|
||||
fseek_origin = SEEK_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END :
|
||||
fseek_origin = SEEK_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET :
|
||||
fseek_origin = SEEK_SET;
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
ret = 0;
|
||||
if (fseek((FILE *)stream, offset, fseek_origin) != 0)
|
||||
ret = -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
|
||||
{
|
||||
int fseek_origin=0;
|
||||
long ret;
|
||||
switch (origin)
|
||||
{
|
||||
case ZLIB_FILEFUNC_SEEK_CUR :
|
||||
fseek_origin = SEEK_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END :
|
||||
fseek_origin = SEEK_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET :
|
||||
fseek_origin = SEEK_SET;
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0)
|
||||
ret = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
|
||||
{
|
||||
int ret;
|
||||
ret = fclose((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
|
||||
{
|
||||
int ret;
|
||||
ret = ferror((FILE *)stream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fill_fopen_filefunc (pzlib_filefunc_def)
|
||||
zlib_filefunc_def* pzlib_filefunc_def;
|
||||
{
|
||||
pzlib_filefunc_def->zopen_file = fopen_file_func;
|
||||
pzlib_filefunc_def->zread_file = fread_file_func;
|
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
|
||||
pzlib_filefunc_def->ztell_file = ftell_file_func;
|
||||
pzlib_filefunc_def->zseek_file = fseek_file_func;
|
||||
pzlib_filefunc_def->zclose_file = fclose_file_func;
|
||||
pzlib_filefunc_def->zerror_file = ferror_file_func;
|
||||
pzlib_filefunc_def->opaque = NULL;
|
||||
}
|
||||
|
||||
void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
|
||||
{
|
||||
pzlib_filefunc_def->zopen64_file = fopen64_file_func;
|
||||
pzlib_filefunc_def->zread_file = fread_file_func;
|
||||
pzlib_filefunc_def->zwrite_file = fwrite_file_func;
|
||||
pzlib_filefunc_def->ztell64_file = ftell64_file_func;
|
||||
pzlib_filefunc_def->zseek64_file = fseek64_file_func;
|
||||
pzlib_filefunc_def->zclose_file = fclose_file_func;
|
||||
pzlib_filefunc_def->zerror_file = ferror_file_func;
|
||||
pzlib_filefunc_def->opaque = NULL;
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/* ioapi.h -- IO base function header for compress/uncompress .zip
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications for Zip64 support
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
Changes
|
||||
|
||||
Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
|
||||
Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
|
||||
More if/def section may be needed to support other platforms
|
||||
Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
|
||||
(but you should use iowin32.c for windows instead)
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _ZLIBIOAPI64_H
|
||||
#define _ZLIBIOAPI64_H
|
||||
|
||||
#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
|
||||
|
||||
// Linux needs this to support file operation on files larger then 4+GB
|
||||
// But might need better if/def to select just the platforms that needs them.
|
||||
|
||||
#ifndef __USE_FILE_OFFSET64
|
||||
#define __USE_FILE_OFFSET64
|
||||
#endif
|
||||
#ifndef __USE_LARGEFILE64
|
||||
#define __USE_LARGEFILE64
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
#ifndef _FILE_OFFSET_BIT
|
||||
#define _FILE_OFFSET_BIT 64
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "zlib.h"
|
||||
|
||||
#if defined(USE_FILE32API)
|
||||
#define fopen64 fopen
|
||||
#define ftello64 ftell
|
||||
#define fseeko64 fseek
|
||||
#else
|
||||
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#define fopen64 fopen
|
||||
#define ftello64 ftello
|
||||
#define fseeko64 fseeko
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#define fopen64 fopen
|
||||
#if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
|
||||
#define ftello64 _ftelli64
|
||||
#define fseeko64 _fseeki64
|
||||
#else // old MSC
|
||||
#define ftello64 ftell
|
||||
#define fseeko64 fseek
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
#ifndef ZPOS64_T
|
||||
#ifdef _WIN32
|
||||
#define ZPOS64_T fpos_t
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#define ZPOS64_T uint64_t
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
#ifdef HAVE_MINIZIP64_CONF_H
|
||||
#include "mz64conf.h"
|
||||
#endif
|
||||
|
||||
/* a type choosen by DEFINE */
|
||||
#ifdef HAVE_64BIT_INT_CUSTOM
|
||||
typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
|
||||
#else
|
||||
#ifdef HAS_STDINT_H
|
||||
#include "stdint.h"
|
||||
typedef uint64_t ZPOS64_T;
|
||||
#else
|
||||
|
||||
/* Maximum unsigned 32-bit value used as placeholder for zip64 */
|
||||
#define MAXU32 0xffffffff
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef unsigned __int64 ZPOS64_T;
|
||||
#else
|
||||
typedef unsigned long long int ZPOS64_T;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef OF
|
||||
#define OF _Z_OF
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define ZLIB_FILEFUNC_SEEK_CUR (1)
|
||||
#define ZLIB_FILEFUNC_SEEK_END (2)
|
||||
#define ZLIB_FILEFUNC_SEEK_SET (0)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_READ (1)
|
||||
#define ZLIB_FILEFUNC_MODE_WRITE (2)
|
||||
#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
|
||||
|
||||
#define ZLIB_FILEFUNC_MODE_EXISTING (4)
|
||||
#define ZLIB_FILEFUNC_MODE_CREATE (8)
|
||||
|
||||
|
||||
#ifndef ZCALLBACK
|
||||
#if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
|
||||
#define ZCALLBACK CALLBACK
|
||||
#else
|
||||
#define ZCALLBACK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
|
||||
typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
|
||||
typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
|
||||
typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
|
||||
|
||||
typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
|
||||
|
||||
|
||||
/* here is the "old" 32 bits structure structure */
|
||||
typedef struct zlib_filefunc_def_s
|
||||
{
|
||||
open_file_func zopen_file;
|
||||
read_file_func zread_file;
|
||||
write_file_func zwrite_file;
|
||||
tell_file_func ztell_file;
|
||||
seek_file_func zseek_file;
|
||||
close_file_func zclose_file;
|
||||
testerror_file_func zerror_file;
|
||||
voidpf opaque;
|
||||
} zlib_filefunc_def;
|
||||
|
||||
typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
|
||||
typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
|
||||
typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
|
||||
|
||||
typedef struct zlib_filefunc64_def_s
|
||||
{
|
||||
open64_file_func zopen64_file;
|
||||
read_file_func zread_file;
|
||||
write_file_func zwrite_file;
|
||||
tell64_file_func ztell64_file;
|
||||
seek64_file_func zseek64_file;
|
||||
close_file_func zclose_file;
|
||||
testerror_file_func zerror_file;
|
||||
voidpf opaque;
|
||||
} zlib_filefunc64_def;
|
||||
|
||||
void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
|
||||
void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
|
||||
|
||||
/* now internal definition, only for zip.c and unzip.h */
|
||||
typedef struct zlib_filefunc64_32_def_s
|
||||
{
|
||||
zlib_filefunc64_def zfile_func64;
|
||||
open_file_func zopen32_file;
|
||||
tell_file_func ztell32_file;
|
||||
seek_file_func zseek32_file;
|
||||
} zlib_filefunc64_32_def;
|
||||
|
||||
|
||||
#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
|
||||
#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
|
||||
//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
|
||||
//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
|
||||
#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
|
||||
#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
|
||||
|
||||
voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
|
||||
long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
|
||||
ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
|
||||
|
||||
void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
|
||||
|
||||
#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
|
||||
#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
|
||||
#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,437 @@
|
|||
/* unzip.h -- IO for uncompress .zip files using zlib
|
||||
Version 1.1, February 14h, 2010
|
||||
part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
|
||||
|
||||
Modifications of Unzip for Zip64
|
||||
Copyright (C) 2007-2008 Even Rouault
|
||||
|
||||
Modifications for Zip64 support on both zip and unzip
|
||||
Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
|
||||
|
||||
For more info read MiniZip_info.txt
|
||||
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
Condition of use and distribution are the same than zlib :
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
---------------------------------------------------------------------------------
|
||||
|
||||
Changes
|
||||
|
||||
See header of unzip64.c
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _unz64_H
|
||||
#define _unz64_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIB_H
|
||||
#include "zlib.h"
|
||||
#endif
|
||||
|
||||
#ifndef _ZLIBIOAPI_H
|
||||
#include "ioapi.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_BZIP2
|
||||
#include "bzlib.h"
|
||||
#endif
|
||||
|
||||
#define Z_BZIP2ED 12
|
||||
|
||||
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
|
||||
/* like the STRICT of WIN32, we define a pointer that cannot be converted
|
||||
from (void*) without cast */
|
||||
typedef struct TagunzFile__ { int unused; } unzFile__;
|
||||
typedef unzFile__ *unzFile;
|
||||
#else
|
||||
typedef voidp unzFile;
|
||||
#endif
|
||||
|
||||
|
||||
#define UNZ_OK (0)
|
||||
#define UNZ_END_OF_LIST_OF_FILE (-100)
|
||||
#define UNZ_ERRNO (Z_ERRNO)
|
||||
#define UNZ_EOF (0)
|
||||
#define UNZ_PARAMERROR (-102)
|
||||
#define UNZ_BADZIPFILE (-103)
|
||||
#define UNZ_INTERNALERROR (-104)
|
||||
#define UNZ_CRCERROR (-105)
|
||||
|
||||
/* tm_unz contain date/time info */
|
||||
typedef struct tm_unz_s
|
||||
{
|
||||
uInt tm_sec; /* seconds after the minute - [0,59] */
|
||||
uInt tm_min; /* minutes after the hour - [0,59] */
|
||||
uInt tm_hour; /* hours since midnight - [0,23] */
|
||||
uInt tm_mday; /* day of the month - [1,31] */
|
||||
uInt tm_mon; /* months since January - [0,11] */
|
||||
uInt tm_year; /* years - [1980..2044] */
|
||||
} tm_unz;
|
||||
|
||||
/* unz_global_info structure contain global data about the ZIPfile
|
||||
These data comes from the end of central dir */
|
||||
typedef struct unz_global_info64_s
|
||||
{
|
||||
ZPOS64_T number_entry; /* total number of entries in
|
||||
the central dir on this disk */
|
||||
uLong size_comment; /* size of the global comment of the zipfile */
|
||||
} unz_global_info64;
|
||||
|
||||
typedef struct unz_global_info_s
|
||||
{
|
||||
uLong number_entry; /* total number of entries in
|
||||
the central dir on this disk */
|
||||
uLong size_comment; /* size of the global comment of the zipfile */
|
||||
} unz_global_info;
|
||||
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_info64_s
|
||||
{
|
||||
uLong version; /* version made by 2 bytes */
|
||||
uLong version_needed; /* version needed to extract 2 bytes */
|
||||
uLong flag; /* general purpose bit flag 2 bytes */
|
||||
uLong compression_method; /* compression method 2 bytes */
|
||||
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
|
||||
uLong crc; /* crc-32 4 bytes */
|
||||
ZPOS64_T compressed_size; /* compressed size 8 bytes */
|
||||
ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
|
||||
uLong size_filename; /* filename length 2 bytes */
|
||||
uLong size_file_extra; /* extra field length 2 bytes */
|
||||
uLong size_file_comment; /* file comment length 2 bytes */
|
||||
|
||||
uLong disk_num_start; /* disk number start 2 bytes */
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */
|
||||
uLong external_fa; /* external file attributes 4 bytes */
|
||||
|
||||
tm_unz tmu_date;
|
||||
} unz_file_info64;
|
||||
|
||||
typedef struct unz_file_info_s
|
||||
{
|
||||
uLong version; /* version made by 2 bytes */
|
||||
uLong version_needed; /* version needed to extract 2 bytes */
|
||||
uLong flag; /* general purpose bit flag 2 bytes */
|
||||
uLong compression_method; /* compression method 2 bytes */
|
||||
uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
|
||||
uLong crc; /* crc-32 4 bytes */
|
||||
uLong compressed_size; /* compressed size 4 bytes */
|
||||
uLong uncompressed_size; /* uncompressed size 4 bytes */
|
||||
uLong size_filename; /* filename length 2 bytes */
|
||||
uLong size_file_extra; /* extra field length 2 bytes */
|
||||
uLong size_file_comment; /* file comment length 2 bytes */
|
||||
|
||||
uLong disk_num_start; /* disk number start 2 bytes */
|
||||
uLong internal_fa; /* internal file attributes 2 bytes */
|
||||
uLong external_fa; /* external file attributes 4 bytes */
|
||||
|
||||
tm_unz tmu_date;
|
||||
} unz_file_info;
|
||||
|
||||
extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
|
||||
const char* fileName2,
|
||||
int iCaseSensitivity));
|
||||
/*
|
||||
Compare two filename (fileName1,fileName2).
|
||||
If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
|
||||
If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
|
||||
or strcasecmp)
|
||||
If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
|
||||
(like 1 on Unix, 2 on Windows)
|
||||
*/
|
||||
|
||||
|
||||
extern unzFile ZEXPORT unzOpen OF((const char *path));
|
||||
extern unzFile ZEXPORT unzOpen64 OF((const void *path));
|
||||
/*
|
||||
Open a Zip file. path contain the full pathname (by example,
|
||||
on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
|
||||
"zlib/zlib113.zip".
|
||||
If the zipfile cannot be opened (file don't exist or in not valid), the
|
||||
return value is NULL.
|
||||
Else, the return value is a unzFile Handle, usable with other function
|
||||
of this unzip package.
|
||||
the "64" function take a const void* pointer, because the path is just the
|
||||
value passed to the open64_file_func callback.
|
||||
Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
|
||||
is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
|
||||
does not describe the reality
|
||||
*/
|
||||
|
||||
|
||||
extern unzFile ZEXPORT unzOpen2 OF((const char *path,
|
||||
zlib_filefunc_def* pzlib_filefunc_def));
|
||||
/*
|
||||
Open a Zip file, like unzOpen, but provide a set of file low level API
|
||||
for read/write the zip file (see ioapi.h)
|
||||
*/
|
||||
|
||||
extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
|
||||
zlib_filefunc64_def* pzlib_filefunc_def));
|
||||
/*
|
||||
Open a Zip file, like unz64Open, but provide a set of file low level API
|
||||
for read/write the zip file (see ioapi.h)
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzClose OF((unzFile file));
|
||||
/*
|
||||
Close a ZipFile opened with unzOpen.
|
||||
If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
|
||||
these files MUST be closed with unzCloseCurrentFile before call unzClose.
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
|
||||
unz_global_info *pglobal_info));
|
||||
|
||||
extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
|
||||
unz_global_info64 *pglobal_info));
|
||||
/*
|
||||
Write info about the ZipFile in the *pglobal_info structure.
|
||||
No preparation of the structure is needed
|
||||
return UNZ_OK if there is no problem. */
|
||||
|
||||
|
||||
extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
|
||||
char *szComment,
|
||||
uLong uSizeBuf));
|
||||
/*
|
||||
Get the global comment string of the ZipFile, in the szComment buffer.
|
||||
uSizeBuf is the size of the szComment buffer.
|
||||
return the number of byte copied or an error code <0
|
||||
*/
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* Unzip package allow you browse the directory of the zipfile */
|
||||
|
||||
extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
|
||||
/*
|
||||
Set the current file of the zipfile to the first file.
|
||||
return UNZ_OK if there is no problem
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzGoToNextFile OF((unzFile file));
|
||||
/*
|
||||
Set the current file of the zipfile to the next file.
|
||||
return UNZ_OK if there is no problem
|
||||
return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzLocateFile OF((unzFile file,
|
||||
const char *szFileName,
|
||||
int iCaseSensitivity));
|
||||
/*
|
||||
Try locate the file szFileName in the zipfile.
|
||||
For the iCaseSensitivity signification, see unzStringFileNameCompare
|
||||
|
||||
return value :
|
||||
UNZ_OK if the file is found. It becomes the current file.
|
||||
UNZ_END_OF_LIST_OF_FILE if the file is not found
|
||||
*/
|
||||
|
||||
|
||||
/* ****************************************** */
|
||||
/* Ryan supplied functions */
|
||||
/* unz_file_info contain information about a file in the zipfile */
|
||||
typedef struct unz_file_pos_s
|
||||
{
|
||||
uLong pos_in_zip_directory; /* offset in zip file directory */
|
||||
uLong num_of_file; /* # of file */
|
||||
} unz_file_pos;
|
||||
|
||||
extern int ZEXPORT unzGetFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
extern int ZEXPORT unzGoToFilePos(
|
||||
unzFile file,
|
||||
unz_file_pos* file_pos);
|
||||
|
||||
typedef struct unz64_file_pos_s
|
||||
{
|
||||
ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
|
||||
ZPOS64_T num_of_file; /* # of file */
|
||||
} unz64_file_pos;
|
||||
|
||||
extern int ZEXPORT unzGetFilePos64(
|
||||
unzFile file,
|
||||
unz64_file_pos* file_pos);
|
||||
|
||||
extern int ZEXPORT unzGoToFilePos64(
|
||||
unzFile file,
|
||||
const unz64_file_pos* file_pos);
|
||||
|
||||
/* ****************************************** */
|
||||
|
||||
extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
|
||||
unz_file_info64 *pfile_info,
|
||||
char *szFileName,
|
||||
uLong fileNameBufferSize,
|
||||
void *extraField,
|
||||
uLong extraFieldBufferSize,
|
||||
char *szComment,
|
||||
uLong commentBufferSize));
|
||||
|
||||
extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
|
||||
unz_file_info *pfile_info,
|
||||
char *szFileName,
|
||||
uLong fileNameBufferSize,
|
||||
void *extraField,
|
||||
uLong extraFieldBufferSize,
|
||||
char *szComment,
|
||||
uLong commentBufferSize));
|
||||
/*
|
||||
Get Info about the current file
|
||||
if pfile_info!=NULL, the *pfile_info structure will contain somes info about
|
||||
the current file
|
||||
if szFileName!=NULL, the filemane string will be copied in szFileName
|
||||
(fileNameBufferSize is the size of the buffer)
|
||||
if extraField!=NULL, the extra field information will be copied in extraField
|
||||
(extraFieldBufferSize is the size of the buffer).
|
||||
This is the Central-header version of the extra field
|
||||
if szComment!=NULL, the comment string of the file will be copied in szComment
|
||||
(commentBufferSize is the size of the buffer)
|
||||
*/
|
||||
|
||||
|
||||
/** Addition for GDAL : START */
|
||||
|
||||
extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
|
||||
|
||||
/** Addition for GDAL : END */
|
||||
|
||||
|
||||
/***************************************************************************/
|
||||
/* for reading the content of the current zipfile, you can open it, read data
|
||||
from it, and close it (you can close it before reading all the file)
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
|
||||
const char* password));
|
||||
/*
|
||||
Open for reading data the current file in the zipfile.
|
||||
password is a crypting password
|
||||
If there is no error, the return value is UNZ_OK.
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
|
||||
int* method,
|
||||
int* level,
|
||||
int raw,
|
||||
const char* password));
|
||||
/*
|
||||
Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
|
||||
if raw==1
|
||||
*method will receive method of compression, *level will receive level of
|
||||
compression
|
||||
note : you can set level parameter as NULL (if you did not want known level,
|
||||
but you CANNOT set method parameter as NULL
|
||||
*/
|
||||
|
||||
|
||||
extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
|
||||
/*
|
||||
Close the file in zip opened with unzOpenCurrentFile
|
||||
Return UNZ_CRCERROR if all the file was read but the CRC is not good
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
|
||||
voidp buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Read bytes from the current file (opened by unzOpenCurrentFile)
|
||||
buf contain buffer where data must be copied
|
||||
len the size of buf.
|
||||
|
||||
return the number of byte copied if somes bytes are copied
|
||||
return 0 if the end of file was reached
|
||||
return <0 with error code if there is an error
|
||||
(UNZ_ERRNO for IO error, or zLib error for uncompress error)
|
||||
*/
|
||||
|
||||
extern z_off_t ZEXPORT unztell OF((unzFile file));
|
||||
|
||||
extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
|
||||
/*
|
||||
Give the current position in uncompressed data
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzeof OF((unzFile file));
|
||||
/*
|
||||
return 1 if the end of file was reached, 0 elsewhere
|
||||
*/
|
||||
|
||||
extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
|
||||
voidp buf,
|
||||
unsigned len));
|
||||
/*
|
||||
Read extra field from the current file (opened by unzOpenCurrentFile)
|
||||
This is the local-header version of the extra field (sometimes, there is
|
||||
more info in the local-header version than in the central-header)
|
||||
|
||||
if buf==NULL, it return the size of the local extra field
|
||||
|
||||
if buf!=NULL, len is the size of the buffer, the extra header is copied in
|
||||
buf.
|
||||
the return value is the number of bytes copied in buf, or (if <0)
|
||||
the error code
|
||||
*/
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/* Get the current file offset */
|
||||
extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
|
||||
extern uLong ZEXPORT unzGetOffset (unzFile file);
|
||||
|
||||
/* Set the current file offset */
|
||||
extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
|
||||
extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _unz64_H */
|
|
@ -0,0 +1,35 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(POPPLER_CFLAGS) \
|
||||
$(WARN_CXXFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libpdfdocument.la
|
||||
|
||||
libpdfdocument_la_SOURCES = \
|
||||
ev-poppler.cc \
|
||||
ev-poppler.h
|
||||
|
||||
libpdfdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libpdfdocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS) \
|
||||
$(POPPLER_LIBS) \
|
||||
$(CAIRO_PDF_LIBS) \
|
||||
$(CAIRO_PS_LIBS)
|
||||
|
||||
backend_in_files = pdfdocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,40 @@
|
|||
/* pdfdocument.h: Implementation of EvDocument for PDF
|
||||
* Copyright (C) 2004, Red Hat, Inc.
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __PDF_DOCUMENT_H__
|
||||
#define __PDF_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PDF_TYPE_DOCUMENT (pdf_document_get_type ())
|
||||
#define PDF_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PDF_TYPE_DOCUMENT, PdfDocument))
|
||||
#define PDF_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PDF_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _PdfDocument PdfDocument;
|
||||
typedef struct _PdfDocumentClass PdfDocumentClass;
|
||||
|
||||
GType pdf_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PDF_DOCUMENT_H__ */
|
|
@ -0,0 +1,5 @@
|
|||
[Atril Backend]
|
||||
Module=pdfdocument
|
||||
Resident=true
|
||||
TypeDescription=PDF Documents
|
||||
MimeType=application/pdf;application/x-bzpdf;application/x-gzpdf;application/x-xzpdf;application/x-ext-pdf;
|
|
@ -0,0 +1,30 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libpixbufdocument.la
|
||||
|
||||
libpixbufdocument_la_SOURCES = \
|
||||
pixbuf-document.c \
|
||||
pixbuf-document.h
|
||||
|
||||
libpixbufdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libpixbufdocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS)
|
||||
|
||||
backend_in_files = pixbufdocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,208 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
|
||||
/*
|
||||
* Copyright (C) 2004, Anders Carlsson <andersca@gnome.org>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#include "pixbuf-document.h"
|
||||
#include "ev-document-thumbnails.h"
|
||||
#include "ev-document-misc.h"
|
||||
#include "ev-file-helpers.h"
|
||||
|
||||
struct _PixbufDocumentClass
|
||||
{
|
||||
EvDocumentClass parent_class;
|
||||
};
|
||||
|
||||
struct _PixbufDocument
|
||||
{
|
||||
EvDocument parent_instance;
|
||||
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
gchar *uri;
|
||||
};
|
||||
|
||||
typedef struct _PixbufDocumentClass PixbufDocumentClass;
|
||||
|
||||
static void pixbuf_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
|
||||
|
||||
EV_BACKEND_REGISTER_WITH_CODE (PixbufDocument, pixbuf_document,
|
||||
{
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
|
||||
pixbuf_document_document_thumbnails_iface_init)
|
||||
});
|
||||
|
||||
static gboolean
|
||||
pixbuf_document_load (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
|
||||
|
||||
gchar *filename;
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
/* FIXME: We could actually load uris */
|
||||
filename = g_filename_from_uri (uri, NULL, error);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_file (filename, error);
|
||||
|
||||
if (!pixbuf)
|
||||
return FALSE;
|
||||
|
||||
pixbuf_document->pixbuf = pixbuf;
|
||||
g_free (pixbuf_document->uri);
|
||||
pixbuf_document->uri = g_strdup (uri);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pixbuf_document_save (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
|
||||
|
||||
return ev_xfer_uri_simple (pixbuf_document->uri, uri, error);
|
||||
}
|
||||
|
||||
static int
|
||||
pixbuf_document_get_n_pages (EvDocument *document)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_document_get_page_size (EvDocument *document,
|
||||
EvPage *page,
|
||||
double *width,
|
||||
double *height)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
|
||||
|
||||
*width = gdk_pixbuf_get_width (pixbuf_document->pixbuf);
|
||||
*height = gdk_pixbuf_get_height (pixbuf_document->pixbuf);
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
pixbuf_document_render (EvDocument *document,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
|
||||
GdkPixbuf *scaled_pixbuf, *rotated_pixbuf;
|
||||
cairo_surface_t *surface;
|
||||
|
||||
scaled_pixbuf = gdk_pixbuf_scale_simple (
|
||||
pixbuf_document->pixbuf,
|
||||
(gdk_pixbuf_get_width (pixbuf_document->pixbuf) * rc->scale) + 0.5,
|
||||
(gdk_pixbuf_get_height (pixbuf_document->pixbuf) * rc->scale) + 0.5,
|
||||
GDK_INTERP_BILINEAR);
|
||||
|
||||
rotated_pixbuf = gdk_pixbuf_rotate_simple (scaled_pixbuf, 360 - rc->rotation);
|
||||
g_object_unref (scaled_pixbuf);
|
||||
|
||||
surface = ev_document_misc_surface_from_pixbuf (rotated_pixbuf);
|
||||
g_object_unref (rotated_pixbuf);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_document_finalize (GObject *object)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (object);
|
||||
|
||||
g_object_unref (pixbuf_document->pixbuf);
|
||||
g_free (pixbuf_document->uri);
|
||||
|
||||
G_OBJECT_CLASS (pixbuf_document_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_document_class_init (PixbufDocumentClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = pixbuf_document_finalize;
|
||||
|
||||
ev_document_class->load = pixbuf_document_load;
|
||||
ev_document_class->save = pixbuf_document_save;
|
||||
ev_document_class->get_n_pages = pixbuf_document_get_n_pages;
|
||||
ev_document_class->get_page_size = pixbuf_document_get_page_size;
|
||||
ev_document_class->render = pixbuf_document_render;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
pixbuf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gboolean border)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
|
||||
GdkPixbuf *pixbuf, *rotated_pixbuf;
|
||||
gint width, height;
|
||||
|
||||
width = (gint) (gdk_pixbuf_get_width (pixbuf_document->pixbuf) * rc->scale);
|
||||
height = (gint) (gdk_pixbuf_get_height (pixbuf_document->pixbuf) * rc->scale);
|
||||
|
||||
pixbuf = gdk_pixbuf_scale_simple (pixbuf_document->pixbuf,
|
||||
width, height,
|
||||
GDK_INTERP_BILINEAR);
|
||||
|
||||
rotated_pixbuf = gdk_pixbuf_rotate_simple (pixbuf, 360 - rc->rotation);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
return rotated_pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
PixbufDocument *pixbuf_document = PIXBUF_DOCUMENT (document);
|
||||
gint p_width = gdk_pixbuf_get_width (pixbuf_document->pixbuf);
|
||||
gint p_height = gdk_pixbuf_get_height (pixbuf_document->pixbuf);
|
||||
|
||||
if (rc->rotation == 90 || rc->rotation == 270) {
|
||||
*width = (gint) (p_height * rc->scale);
|
||||
*height = (gint) (p_width * rc->scale);
|
||||
} else {
|
||||
*width = (gint) (p_width * rc->scale);
|
||||
*height = (gint) (p_height * rc->scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pixbuf_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
|
||||
{
|
||||
iface->get_thumbnail = pixbuf_document_thumbnails_get_thumbnail;
|
||||
iface->get_dimensions = pixbuf_document_thumbnails_get_dimensions;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
pixbuf_document_init (PixbufDocument *pixbuf_document)
|
||||
{
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/* pdfdocument.h: Implementation of EvDocument for pixbufs
|
||||
* Copyright (C) 2004, Anders Carlsson <andersca@gnome.org>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __PIXBUF_DOCUMENT_H__
|
||||
#define __PIXBUF_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PIXBUF_TYPE_DOCUMENT (pixbuf_document_get_type ())
|
||||
#define PIXBUF_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIXBUF_TYPE_DOCUMENT, PixbufDocument))
|
||||
#define PIXBUF_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIXBUF_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _PixbufDocument PixbufDocument;
|
||||
|
||||
GType pixbuf_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PIXBUF_DOCUMENT_H__ */
|
|
@ -0,0 +1,4 @@
|
|||
[Atril Backend]
|
||||
Module=pixbufdocument
|
||||
TypeDescription=Images
|
||||
MimeType=image/*;
|
|
@ -0,0 +1,33 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(SPECTRE_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libpsdocument.la
|
||||
|
||||
libpsdocument_la_SOURCES = \
|
||||
ev-spectre.c \
|
||||
ev-spectre.h
|
||||
|
||||
libpsdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libpsdocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS) \
|
||||
$(SPECTRE_LIBS)
|
||||
|
||||
backend_in_files = psdocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,487 @@
|
|||
/* this file is part of atril, a mate document viewer
|
||||
*
|
||||
* Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
|
||||
*
|
||||
* Atril 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.
|
||||
*
|
||||
* Atril 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.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <stdlib.h>
|
||||
#include <libspectre/spectre.h>
|
||||
|
||||
#include "ev-spectre.h"
|
||||
|
||||
#include "ev-file-exporter.h"
|
||||
#include "ev-document-thumbnails.h"
|
||||
#include "ev-document-misc.h"
|
||||
|
||||
struct _PSDocument {
|
||||
EvDocument object;
|
||||
|
||||
SpectreDocument *doc;
|
||||
SpectreExporter *exporter;
|
||||
};
|
||||
|
||||
struct _PSDocumentClass {
|
||||
EvDocumentClass parent_class;
|
||||
};
|
||||
|
||||
static void ps_document_file_exporter_iface_init (EvFileExporterInterface *iface);
|
||||
static void ps_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
|
||||
|
||||
EV_BACKEND_REGISTER_WITH_CODE (PSDocument, ps_document,
|
||||
{
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
|
||||
ps_document_document_thumbnails_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
|
||||
ps_document_file_exporter_iface_init);
|
||||
});
|
||||
|
||||
/* PSDocument */
|
||||
static void
|
||||
ps_document_init (PSDocument *ps_document)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_dispose (GObject *object)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (object);
|
||||
|
||||
if (ps->doc) {
|
||||
spectre_document_free (ps->doc);
|
||||
ps->doc = NULL;
|
||||
}
|
||||
|
||||
if (ps->exporter) {
|
||||
spectre_exporter_free (ps->exporter);
|
||||
ps->exporter = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (ps_document_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
/* EvDocumentIface */
|
||||
static gboolean
|
||||
ps_document_load (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document);
|
||||
gchar *filename;
|
||||
|
||||
filename = g_filename_from_uri (uri, NULL, error);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
ps->doc = spectre_document_new ();
|
||||
|
||||
spectre_document_load (ps->doc, filename);
|
||||
if (spectre_document_status (ps->doc)) {
|
||||
gchar *filename_dsp;
|
||||
|
||||
filename_dsp = g_filename_display_name (filename);
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
G_FILE_ERROR_FAILED,
|
||||
_("Failed to load document “%s”"),
|
||||
filename_dsp);
|
||||
g_free (filename_dsp);
|
||||
g_free (filename);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ps_document_save (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document);
|
||||
gchar *filename;
|
||||
|
||||
filename = g_filename_from_uri (uri, NULL, error);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
spectre_document_save (ps->doc, filename);
|
||||
if (spectre_document_status (ps->doc)) {
|
||||
gchar *filename_dsp;
|
||||
|
||||
filename_dsp = g_filename_display_name (filename);
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
G_FILE_ERROR_FAILED,
|
||||
_("Failed to save document “%s”"),
|
||||
filename_dsp);
|
||||
g_free (filename_dsp);
|
||||
g_free (filename);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
ps_document_get_n_pages (EvDocument *document)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document);
|
||||
|
||||
return spectre_document_get_n_pages (ps->doc);
|
||||
}
|
||||
|
||||
static EvPage *
|
||||
ps_document_get_page (EvDocument *document,
|
||||
gint index)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document);
|
||||
SpectrePage *ps_page;
|
||||
EvPage *page;
|
||||
|
||||
ps_page = spectre_document_get_page (ps->doc, index);
|
||||
page = ev_page_new (index);
|
||||
page->backend_page = (EvBackendPage)ps_page;
|
||||
page->backend_destroy_func = (EvBackendPageDestroyFunc)spectre_page_free;
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
static gint
|
||||
get_page_rotation (SpectrePage *page)
|
||||
{
|
||||
switch (spectre_page_get_orientation (page)) {
|
||||
default:
|
||||
case SPECTRE_ORIENTATION_PORTRAIT:
|
||||
return 0;
|
||||
case SPECTRE_ORIENTATION_LANDSCAPE:
|
||||
return 90;
|
||||
case SPECTRE_ORIENTATION_REVERSE_PORTRAIT:
|
||||
return 180;
|
||||
case SPECTRE_ORIENTATION_REVERSE_LANDSCAPE:
|
||||
return 270;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_get_page_size (EvDocument *document,
|
||||
EvPage *page,
|
||||
double *width,
|
||||
double *height)
|
||||
{
|
||||
SpectrePage *ps_page;
|
||||
gdouble page_width, page_height;
|
||||
gint pwidth, pheight;
|
||||
gint rotate;
|
||||
|
||||
ps_page = (SpectrePage *)page->backend_page;
|
||||
|
||||
spectre_page_get_size (ps_page, &pwidth, &pheight);
|
||||
|
||||
rotate = get_page_rotation (ps_page);
|
||||
if (rotate == 90 || rotate == 270) {
|
||||
page_height = pwidth;
|
||||
page_width = pheight;
|
||||
} else {
|
||||
page_width = pwidth;
|
||||
page_height = pheight;
|
||||
}
|
||||
|
||||
if (width) {
|
||||
*width = page_width;
|
||||
}
|
||||
|
||||
if (height) {
|
||||
*height = page_height;
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
ps_document_get_page_label (EvDocument *document,
|
||||
EvPage *page)
|
||||
{
|
||||
const gchar *label = spectre_page_get_label ((SpectrePage *)page->backend_page);
|
||||
gchar *utf8;
|
||||
|
||||
if (!label)
|
||||
return NULL;
|
||||
|
||||
if (g_utf8_validate (label, -1, NULL))
|
||||
return g_strdup (label);
|
||||
|
||||
/* Try with latin1 and ASCII encondings */
|
||||
utf8 = g_convert (label, -1, "utf-8", "latin1", NULL, NULL, NULL);
|
||||
if (!utf8)
|
||||
utf8 = g_convert (label, -1, "utf-8", "ASCII", NULL, NULL, NULL);
|
||||
|
||||
return utf8;
|
||||
}
|
||||
|
||||
static EvDocumentInfo *
|
||||
ps_document_get_info (EvDocument *document)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document);
|
||||
EvDocumentInfo *info;
|
||||
const gchar *creator;
|
||||
SpectrePage *ps_page;
|
||||
gint width, height;
|
||||
|
||||
info = g_new0 (EvDocumentInfo, 1);
|
||||
info->fields_mask = EV_DOCUMENT_INFO_TITLE |
|
||||
EV_DOCUMENT_INFO_FORMAT |
|
||||
EV_DOCUMENT_INFO_CREATOR |
|
||||
EV_DOCUMENT_INFO_N_PAGES |
|
||||
EV_DOCUMENT_INFO_PAPER_SIZE;
|
||||
|
||||
creator = spectre_document_get_creator (ps->doc);
|
||||
|
||||
ps_page = spectre_document_get_page (ps->doc, 0);
|
||||
spectre_page_get_size (ps_page, &width, &height);
|
||||
spectre_page_free (ps_page);
|
||||
|
||||
info->title = g_strdup (spectre_document_get_title (ps->doc));
|
||||
info->format = g_strdup (spectre_document_get_format (ps->doc));
|
||||
info->creator = g_strdup (creator ? creator : spectre_document_get_for (ps->doc));
|
||||
info->n_pages = spectre_document_get_n_pages (ps->doc);
|
||||
info->paper_width = width / 72.0f * 25.4f;
|
||||
info->paper_height = height / 72.0f * 25.4f;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ps_document_get_backend_info (EvDocument *document,
|
||||
EvDocumentBackendInfo *info)
|
||||
{
|
||||
info->name = "libspectre";
|
||||
info->version = SPECTRE_VERSION_STRING;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
ps_document_render (EvDocument *document,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
SpectrePage *ps_page;
|
||||
SpectreRenderContext *src;
|
||||
gint width_points;
|
||||
gint height_points;
|
||||
gint width, height;
|
||||
gint swidth, sheight;
|
||||
guchar *data = NULL;
|
||||
gint stride;
|
||||
gint rotation;
|
||||
cairo_surface_t *surface;
|
||||
static const cairo_user_data_key_t key;
|
||||
|
||||
ps_page = (SpectrePage *)rc->page->backend_page;
|
||||
|
||||
spectre_page_get_size (ps_page, &width_points, &height_points);
|
||||
|
||||
width = (gint) ((width_points * rc->scale) + 0.5);
|
||||
height = (gint) ((height_points * rc->scale) + 0.5);
|
||||
rotation = (rc->rotation + get_page_rotation (ps_page)) % 360;
|
||||
|
||||
src = spectre_render_context_new ();
|
||||
spectre_render_context_set_scale (src,
|
||||
(gdouble)width / width_points,
|
||||
(gdouble)height / height_points);
|
||||
spectre_render_context_set_rotation (src, rotation);
|
||||
spectre_page_render (ps_page, src, &data, &stride);
|
||||
spectre_render_context_free (src);
|
||||
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (spectre_page_status (ps_page)) {
|
||||
g_warning ("%s", spectre_status_to_string (spectre_page_status (ps_page)));
|
||||
g_free (data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rotation == 90 || rotation == 270) {
|
||||
swidth = height;
|
||||
sheight = width;
|
||||
} else {
|
||||
swidth = width;
|
||||
sheight = height;
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_RGB24,
|
||||
swidth, sheight,
|
||||
stride);
|
||||
cairo_surface_set_user_data (surface, &key,
|
||||
data, (cairo_destroy_func_t)g_free);
|
||||
return surface;
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_class_init (PSDocumentClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
|
||||
|
||||
object_class->dispose = ps_document_dispose;
|
||||
|
||||
ev_document_class->load = ps_document_load;
|
||||
ev_document_class->save = ps_document_save;
|
||||
ev_document_class->get_n_pages = ps_document_get_n_pages;
|
||||
ev_document_class->get_page = ps_document_get_page;
|
||||
ev_document_class->get_page_size = ps_document_get_page_size;
|
||||
ev_document_class->get_page_label = ps_document_get_page_label;
|
||||
ev_document_class->get_info = ps_document_get_info;
|
||||
ev_document_class->get_backend_info = ps_document_get_backend_info;
|
||||
ev_document_class->render = ps_document_render;
|
||||
}
|
||||
|
||||
/* EvDocumentThumbnailsIface */
|
||||
static GdkPixbuf *
|
||||
ps_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document_thumbnails,
|
||||
EvRenderContext *rc,
|
||||
gboolean border)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document_thumbnails);
|
||||
cairo_surface_t *surface;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
|
||||
surface = ps_document_render (EV_DOCUMENT (ps), rc);
|
||||
if (!surface) {
|
||||
g_warning ("Error rendering thumbnail");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pixbuf = ev_document_misc_pixbuf_from_surface (surface);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
if (border) {
|
||||
GdkPixbuf *border_pixbuf;
|
||||
|
||||
border_pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
pixbuf = border_pixbuf;
|
||||
}
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_thumbnails_get_dimensions (EvDocumentThumbnails *document_thumbnails,
|
||||
EvRenderContext *rc,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (document_thumbnails);
|
||||
gdouble page_width, page_height;
|
||||
|
||||
ps_document_get_page_size (EV_DOCUMENT (ps),
|
||||
rc->page,
|
||||
&page_width, &page_height);
|
||||
|
||||
if (rc->rotation == 90 || rc->rotation == 270) {
|
||||
*width = (gint) (page_height * rc->scale);
|
||||
*height = (gint) (page_width * rc->scale);
|
||||
} else {
|
||||
*width = (gint) (page_width * rc->scale);
|
||||
*height = (gint) (page_height * rc->scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
|
||||
{
|
||||
iface->get_thumbnail = ps_document_thumbnails_get_thumbnail;
|
||||
iface->get_dimensions = ps_document_thumbnails_get_dimensions;
|
||||
}
|
||||
|
||||
/* EvFileExporterIface */
|
||||
static void
|
||||
ps_document_file_exporter_begin (EvFileExporter *exporter,
|
||||
EvFileExporterContext *fc)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (exporter);
|
||||
|
||||
if (ps->exporter)
|
||||
spectre_exporter_free (ps->exporter);
|
||||
|
||||
switch (fc->format) {
|
||||
case EV_FILE_FORMAT_PS:
|
||||
ps->exporter =
|
||||
spectre_exporter_new (ps->doc,
|
||||
SPECTRE_EXPORTER_FORMAT_PS);
|
||||
break;
|
||||
case EV_FILE_FORMAT_PDF:
|
||||
ps->exporter =
|
||||
spectre_exporter_new (ps->doc,
|
||||
SPECTRE_EXPORTER_FORMAT_PDF);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
spectre_exporter_begin (ps->exporter, fc->filename);
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_file_exporter_do_page (EvFileExporter *exporter,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (exporter);
|
||||
|
||||
spectre_exporter_do_page (ps->exporter, rc->page->index);
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_file_exporter_end (EvFileExporter *exporter)
|
||||
{
|
||||
PSDocument *ps = PS_DOCUMENT (exporter);
|
||||
|
||||
spectre_exporter_end (ps->exporter);
|
||||
}
|
||||
|
||||
static EvFileExporterCapabilities
|
||||
ps_document_file_exporter_get_capabilities (EvFileExporter *exporter)
|
||||
{
|
||||
return EV_FILE_EXPORTER_CAN_PAGE_SET |
|
||||
EV_FILE_EXPORTER_CAN_COPIES |
|
||||
EV_FILE_EXPORTER_CAN_COLLATE |
|
||||
EV_FILE_EXPORTER_CAN_REVERSE |
|
||||
EV_FILE_EXPORTER_CAN_GENERATE_PS |
|
||||
EV_FILE_EXPORTER_CAN_GENERATE_PDF;
|
||||
}
|
||||
|
||||
static void
|
||||
ps_document_file_exporter_iface_init (EvFileExporterInterface *iface)
|
||||
{
|
||||
iface->begin = ps_document_file_exporter_begin;
|
||||
iface->do_page = ps_document_file_exporter_do_page;
|
||||
iface->end = ps_document_file_exporter_end;
|
||||
iface->get_capabilities = ps_document_file_exporter_get_capabilities;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Ghostscript widget for GTK/MATE
|
||||
*
|
||||
* Copyright 1998 - 2005 The Free Software Foundation
|
||||
*
|
||||
* Authors: Jaka Mocnik, Federico Mena (Quartic), Szekeres Istvan (Pista)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __PS_DOCUMENT_H__
|
||||
#define __PS_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define PS_TYPE_DOCUMENT (ps_document_get_type())
|
||||
#define PS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PS_TYPE_DOCUMENT, PSDocument))
|
||||
#define PS_DOCUMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PS_TYPE_DOCUMENT, PSDocumentClass))
|
||||
#define PS_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PS_TYPE_DOCUMENT))
|
||||
#define PS_DOCUMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PS_TYPE_DOCUMENT, PSDocumentClass))
|
||||
|
||||
typedef struct _PSDocument PSDocument;
|
||||
typedef struct _PSDocumentClass PSDocumentClass;
|
||||
|
||||
GType ps_document_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __PS_DOCUMENT_H__ */
|
|
@ -0,0 +1,5 @@
|
|||
[Atril Backend]
|
||||
Module=psdocument
|
||||
Resident=true
|
||||
TypeDescription=PostScript Documents
|
||||
MimeType=application/postscript;application/x-bzpostscript;application/x-gzpostscript;image/x-eps;image/x-bzeps;image/x-gzeps
|
|
@ -0,0 +1,33 @@
|
|||
AM_CPPFLAGS = \
|
||||
-I$(top_srcdir) \
|
||||
-I$(top_srcdir)/libdocument \
|
||||
-DMATELOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DATRIL_COMPILATION \
|
||||
$(BACKEND_CFLAGS) \
|
||||
$(WARN_CFLAGS) \
|
||||
$(DISABLE_DEPRECATED)
|
||||
|
||||
backend_LTLIBRARIES = libtiffdocument.la
|
||||
|
||||
libtiffdocument_la_SOURCES = \
|
||||
tiff-document.c \
|
||||
tiff-document.h \
|
||||
tiff2ps.c \
|
||||
tiff2ps.h
|
||||
|
||||
libtiffdocument_la_LDFLAGS = $(BACKEND_LIBTOOL_FLAGS)
|
||||
libtiffdocument_la_LIBADD = \
|
||||
$(top_builddir)/libdocument/libatrildocument.la \
|
||||
$(BACKEND_LIBS) \
|
||||
-ltiff
|
||||
|
||||
backend_in_files = tiffdocument.atril-backend.desktop.in
|
||||
backend_DATA = $(backend_in_files:.atril-backend.desktop.in=.atril-backend)
|
||||
$(backend_DATA): $(backend_in_files)
|
||||
$(AM_V_GEN) $(MSGFMT) --desktop --keyword=TypeDescription --template $< -d $(top_srcdir)/po -o $@
|
||||
|
||||
EXTRA_DIST = $(backend_in_files)
|
||||
|
||||
CLEANFILES = $(backend_DATA)
|
||||
|
||||
-include $(top_srcdir)/git.mk
|
|
@ -0,0 +1,552 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
|
||||
/*
|
||||
* Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
/* FIXME: Should probably buffer calls to libtiff with TIFFSetWarningHandler
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#include "tiffio.h"
|
||||
#include "tiff2ps.h"
|
||||
#include "tiff-document.h"
|
||||
#include "ev-document-misc.h"
|
||||
#include "ev-document-thumbnails.h"
|
||||
#include "ev-file-exporter.h"
|
||||
#include "ev-file-helpers.h"
|
||||
|
||||
struct _TiffDocumentClass
|
||||
{
|
||||
EvDocumentClass parent_class;
|
||||
};
|
||||
|
||||
struct _TiffDocument
|
||||
{
|
||||
EvDocument parent_instance;
|
||||
|
||||
TIFF *tiff;
|
||||
gint n_pages;
|
||||
TIFF2PSContext *ps_export_ctx;
|
||||
|
||||
gchar *uri;
|
||||
};
|
||||
|
||||
typedef struct _TiffDocumentClass TiffDocumentClass;
|
||||
|
||||
static void tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface);
|
||||
static void tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface);
|
||||
|
||||
EV_BACKEND_REGISTER_WITH_CODE (TiffDocument, tiff_document,
|
||||
{
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS,
|
||||
tiff_document_document_thumbnails_iface_init);
|
||||
EV_BACKEND_IMPLEMENT_INTERFACE (EV_TYPE_FILE_EXPORTER,
|
||||
tiff_document_document_file_exporter_iface_init);
|
||||
});
|
||||
|
||||
static TIFFErrorHandler orig_error_handler = NULL;
|
||||
static TIFFErrorHandler orig_warning_handler = NULL;
|
||||
|
||||
static void
|
||||
push_handlers (void)
|
||||
{
|
||||
orig_error_handler = TIFFSetErrorHandler (NULL);
|
||||
orig_warning_handler = TIFFSetWarningHandler (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
pop_handlers (void)
|
||||
{
|
||||
TIFFSetErrorHandler (orig_error_handler);
|
||||
TIFFSetWarningHandler (orig_warning_handler);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tiff_document_load (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
gchar *filename;
|
||||
TIFF *tiff;
|
||||
|
||||
filename = g_filename_from_uri (uri, NULL, error);
|
||||
if (!filename)
|
||||
return FALSE;
|
||||
|
||||
push_handlers ();
|
||||
|
||||
tiff = TIFFOpen (filename, "r");
|
||||
if (tiff) {
|
||||
guint32 w, h;
|
||||
|
||||
/* FIXME: unused data? why bother here */
|
||||
TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &w);
|
||||
TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &h);
|
||||
}
|
||||
|
||||
if (!tiff) {
|
||||
pop_handlers ();
|
||||
|
||||
g_set_error_literal (error,
|
||||
EV_DOCUMENT_ERROR,
|
||||
EV_DOCUMENT_ERROR_INVALID,
|
||||
_("Invalid document"));
|
||||
|
||||
g_free (filename);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
tiff_document->tiff = tiff;
|
||||
g_free (tiff_document->uri);
|
||||
g_free (filename);
|
||||
tiff_document->uri = g_strdup (uri);
|
||||
|
||||
pop_handlers ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
tiff_document_save (EvDocument *document,
|
||||
const char *uri,
|
||||
GError **error)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
|
||||
return ev_xfer_uri_simple (tiff_document->uri, uri, error);
|
||||
}
|
||||
|
||||
static int
|
||||
tiff_document_get_n_pages (EvDocument *document)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
|
||||
g_return_val_if_fail (TIFF_IS_DOCUMENT (document), 0);
|
||||
g_return_val_if_fail (tiff_document->tiff != NULL, 0);
|
||||
|
||||
if (tiff_document->n_pages == -1) {
|
||||
push_handlers ();
|
||||
tiff_document->n_pages = 0;
|
||||
|
||||
do {
|
||||
tiff_document->n_pages ++;
|
||||
}
|
||||
while (TIFFReadDirectory (tiff_document->tiff));
|
||||
pop_handlers ();
|
||||
}
|
||||
|
||||
return tiff_document->n_pages;
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_get_resolution (TiffDocument *tiff_document,
|
||||
gfloat *x_res,
|
||||
gfloat *y_res)
|
||||
{
|
||||
gfloat x = 72.0, y = 72.0;
|
||||
gushort unit;
|
||||
|
||||
if (TIFFGetField (tiff_document->tiff, TIFFTAG_XRESOLUTION, &x) &&
|
||||
TIFFGetField (tiff_document->tiff, TIFFTAG_YRESOLUTION, &y)) {
|
||||
if (TIFFGetFieldDefaulted (tiff_document->tiff, TIFFTAG_RESOLUTIONUNIT, &unit)) {
|
||||
if (unit == RESUNIT_CENTIMETER) {
|
||||
x *= 2.54;
|
||||
y *= 2.54;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*x_res = x;
|
||||
*y_res = y;
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_get_page_size (EvDocument *document,
|
||||
EvPage *page,
|
||||
double *width,
|
||||
double *height)
|
||||
{
|
||||
guint32 w, h;
|
||||
gfloat x_res, y_res;
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
|
||||
g_return_if_fail (TIFF_IS_DOCUMENT (document));
|
||||
g_return_if_fail (tiff_document->tiff != NULL);
|
||||
|
||||
push_handlers ();
|
||||
if (TIFFSetDirectory (tiff_document->tiff, page->index) != 1) {
|
||||
pop_handlers ();
|
||||
return;
|
||||
}
|
||||
|
||||
TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &w);
|
||||
TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &h);
|
||||
tiff_document_get_resolution (tiff_document, &x_res, &y_res);
|
||||
h = h * (x_res / y_res);
|
||||
|
||||
*width = w;
|
||||
*height = h;
|
||||
|
||||
pop_handlers ();
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
tiff_document_render (EvDocument *document,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
int width, height;
|
||||
float x_res, y_res;
|
||||
gint rowstride, bytes;
|
||||
guchar *pixels = NULL;
|
||||
guchar *p;
|
||||
int orientation;
|
||||
cairo_surface_t *surface;
|
||||
cairo_surface_t *rotated_surface;
|
||||
static const cairo_user_data_key_t key;
|
||||
|
||||
g_return_val_if_fail (TIFF_IS_DOCUMENT (document), NULL);
|
||||
g_return_val_if_fail (tiff_document->tiff != NULL, NULL);
|
||||
|
||||
push_handlers ();
|
||||
if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
|
||||
pop_handlers ();
|
||||
g_warning("Failed to select page %d", rc->page->index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
|
||||
pop_handlers ();
|
||||
g_warning("Failed to read image width");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
|
||||
pop_handlers ();
|
||||
g_warning("Failed to read image height");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! TIFFGetField (tiff_document->tiff, TIFFTAG_ORIENTATION, &orientation)) {
|
||||
orientation = ORIENTATION_TOPLEFT;
|
||||
}
|
||||
|
||||
tiff_document_get_resolution (tiff_document, &x_res, &y_res);
|
||||
|
||||
pop_handlers ();
|
||||
|
||||
/* Sanity check the doc */
|
||||
if (width <= 0 || height <= 0) {
|
||||
g_warning("Invalid width or height.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, width);
|
||||
if (rowstride / 4 != width) {
|
||||
g_warning("Overflow while rendering document.");
|
||||
/* overflow, or cairo was changed in an unsupported way */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (height >= INT_MAX / rowstride) {
|
||||
g_warning("Overflow while rendering document.");
|
||||
/* overflow */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bytes = height * rowstride;
|
||||
|
||||
pixels = g_try_malloc (bytes);
|
||||
if (!pixels) {
|
||||
g_warning("Failed to allocate memory for rendering.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!TIFFReadRGBAImageOriented (tiff_document->tiff,
|
||||
width, height,
|
||||
(uint32 *)pixels,
|
||||
orientation, 0)) {
|
||||
g_warning ("Failed to read TIFF image.");
|
||||
g_free (pixels);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surface = cairo_image_surface_create_for_data (pixels,
|
||||
CAIRO_FORMAT_RGB24,
|
||||
width, height,
|
||||
rowstride);
|
||||
cairo_surface_set_user_data (surface, &key,
|
||||
pixels, (cairo_destroy_func_t)g_free);
|
||||
pop_handlers ();
|
||||
|
||||
/* Convert the format returned by libtiff to
|
||||
* what cairo expects
|
||||
*/
|
||||
p = pixels;
|
||||
while (p < pixels + bytes) {
|
||||
guint32 *pixel = (guint32*)p;
|
||||
guint8 r = TIFFGetR(*pixel);
|
||||
guint8 g = TIFFGetG(*pixel);
|
||||
guint8 b = TIFFGetB(*pixel);
|
||||
guint8 a = TIFFGetA(*pixel);
|
||||
|
||||
*pixel = (a << 24) | (r << 16) | (g << 8) | b;
|
||||
|
||||
p += 4;
|
||||
}
|
||||
|
||||
rotated_surface = ev_document_misc_surface_rotate_and_scale (surface,
|
||||
(width * rc->scale) + 0.5,
|
||||
(height * rc->scale * (x_res / y_res)) + 0.5,
|
||||
rc->rotation);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
return rotated_surface;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
tiff_document_render_pixbuf (EvDocument *document,
|
||||
EvRenderContext *rc)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
int width, height;
|
||||
float x_res, y_res;
|
||||
gint rowstride, bytes;
|
||||
guchar *pixels = NULL;
|
||||
GdkPixbuf *pixbuf;
|
||||
GdkPixbuf *scaled_pixbuf;
|
||||
GdkPixbuf *rotated_pixbuf;
|
||||
|
||||
push_handlers ();
|
||||
if (TIFFSetDirectory (tiff_document->tiff, rc->page->index) != 1) {
|
||||
pop_handlers ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGEWIDTH, &width)) {
|
||||
pop_handlers ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! TIFFGetField (tiff_document->tiff, TIFFTAG_IMAGELENGTH, &height)) {
|
||||
pop_handlers ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tiff_document_get_resolution (tiff_document, &x_res, &y_res);
|
||||
|
||||
pop_handlers ();
|
||||
|
||||
/* Sanity check the doc */
|
||||
if (width <= 0 || height <= 0)
|
||||
return NULL;
|
||||
|
||||
|
||||
if (width >= INT_MAX / 4)
|
||||
/* overflow */
|
||||
return NULL;
|
||||
|
||||
rowstride = width * 4;
|
||||
|
||||
if (height >= INT_MAX / rowstride)
|
||||
/* overflow */
|
||||
return NULL;
|
||||
bytes = height * rowstride;
|
||||
|
||||
pixels = g_try_malloc (bytes);
|
||||
if (!pixels)
|
||||
return NULL;
|
||||
|
||||
if (!TIFFReadRGBAImageOriented (tiff_document->tiff,
|
||||
width, height,
|
||||
(uint32 *)pixels,
|
||||
ORIENTATION_TOPLEFT, 0)) {
|
||||
g_free (pixels);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pixbuf = gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, TRUE, 8,
|
||||
width, height, rowstride,
|
||||
(GdkPixbufDestroyNotify) g_free, NULL);
|
||||
pop_handlers ();
|
||||
|
||||
scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf,
|
||||
width * rc->scale,
|
||||
height * rc->scale * (x_res / y_res),
|
||||
GDK_INTERP_BILINEAR);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
rotated_pixbuf = gdk_pixbuf_rotate_simple (scaled_pixbuf, 360 - rc->rotation);
|
||||
g_object_unref (scaled_pixbuf);
|
||||
|
||||
return rotated_pixbuf;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
tiff_document_get_page_label (EvDocument *document,
|
||||
EvPage *page)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (document);
|
||||
static gchar *label;
|
||||
|
||||
if (TIFFGetField (tiff_document->tiff, TIFFTAG_PAGENAME, &label) &&
|
||||
g_utf8_validate (label, -1, NULL)) {
|
||||
return g_strdup (label);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_finalize (GObject *object)
|
||||
{
|
||||
TiffDocument *tiff_document = TIFF_DOCUMENT (object);
|
||||
|
||||
if (tiff_document->tiff)
|
||||
TIFFClose (tiff_document->tiff);
|
||||
if (tiff_document->uri)
|
||||
g_free (tiff_document->uri);
|
||||
|
||||
G_OBJECT_CLASS (tiff_document_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_class_init (TiffDocumentClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
EvDocumentClass *ev_document_class = EV_DOCUMENT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = tiff_document_finalize;
|
||||
|
||||
ev_document_class->load = tiff_document_load;
|
||||
ev_document_class->save = tiff_document_save;
|
||||
ev_document_class->get_n_pages = tiff_document_get_n_pages;
|
||||
ev_document_class->get_page_size = tiff_document_get_page_size;
|
||||
ev_document_class->render = tiff_document_render;
|
||||
ev_document_class->get_page_label = tiff_document_get_page_label;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
tiff_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gboolean border)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
|
||||
pixbuf = tiff_document_render_pixbuf (EV_DOCUMENT (document), rc);
|
||||
|
||||
if (border) {
|
||||
GdkPixbuf *tmp_pixbuf = pixbuf;
|
||||
|
||||
pixbuf = ev_document_misc_get_thumbnail_frame (-1, -1, tmp_pixbuf);
|
||||
g_object_unref (tmp_pixbuf);
|
||||
}
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_thumbnails_get_dimensions (EvDocumentThumbnails *document,
|
||||
EvRenderContext *rc,
|
||||
gint *width,
|
||||
gint *height)
|
||||
{
|
||||
gdouble page_width, page_height;
|
||||
|
||||
tiff_document_get_page_size (EV_DOCUMENT (document),
|
||||
rc->page,
|
||||
&page_width, &page_height);
|
||||
|
||||
if (rc->rotation == 90 || rc->rotation == 270) {
|
||||
*width = (gint) (page_height * rc->scale);
|
||||
*height = (gint) (page_width * rc->scale);
|
||||
} else {
|
||||
*width = (gint) (page_width * rc->scale);
|
||||
*height = (gint) (page_height * rc->scale);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_document_thumbnails_iface_init (EvDocumentThumbnailsInterface *iface)
|
||||
{
|
||||
iface->get_thumbnail = tiff_document_thumbnails_get_thumbnail;
|
||||
iface->get_dimensions = tiff_document_thumbnails_get_dimensions;
|
||||
}
|
||||
|
||||
/* postscript exporter implementation */
|
||||
static void
|
||||
tiff_document_file_exporter_begin (EvFileExporter *exporter,
|
||||
EvFileExporterContext *fc)
|
||||
{
|
||||
TiffDocument *document = TIFF_DOCUMENT (exporter);
|
||||
|
||||
document->ps_export_ctx = tiff2ps_context_new(fc->filename);
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_file_exporter_do_page (EvFileExporter *exporter, EvRenderContext *rc)
|
||||
{
|
||||
TiffDocument *document = TIFF_DOCUMENT (exporter);
|
||||
|
||||
if (document->ps_export_ctx == NULL)
|
||||
return;
|
||||
if (TIFFSetDirectory (document->tiff, rc->page->index) != 1)
|
||||
return;
|
||||
tiff2ps_process_page (document->ps_export_ctx, document->tiff,
|
||||
0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_file_exporter_end (EvFileExporter *exporter)
|
||||
{
|
||||
TiffDocument *document = TIFF_DOCUMENT (exporter);
|
||||
|
||||
if (document->ps_export_ctx == NULL)
|
||||
return;
|
||||
tiff2ps_context_finalize(document->ps_export_ctx);
|
||||
}
|
||||
|
||||
static EvFileExporterCapabilities
|
||||
tiff_document_file_exporter_get_capabilities (EvFileExporter *exporter)
|
||||
{
|
||||
return EV_FILE_EXPORTER_CAN_PAGE_SET |
|
||||
EV_FILE_EXPORTER_CAN_COPIES |
|
||||
EV_FILE_EXPORTER_CAN_COLLATE |
|
||||
EV_FILE_EXPORTER_CAN_REVERSE |
|
||||
EV_FILE_EXPORTER_CAN_GENERATE_PS;
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_document_file_exporter_iface_init (EvFileExporterInterface *iface)
|
||||
{
|
||||
iface->begin = tiff_document_file_exporter_begin;
|
||||
iface->do_page = tiff_document_file_exporter_do_page;
|
||||
iface->end = tiff_document_file_exporter_end;
|
||||
iface->get_capabilities = tiff_document_file_exporter_get_capabilities;
|
||||
}
|
||||
|
||||
static void
|
||||
tiff_document_init (TiffDocument *tiff_document)
|
||||
{
|
||||
tiff_document->n_pages = -1;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
|
||||
/* pdfdocument.h: Implementation of EvDocument for tiffs
|
||||
* Copyright (C) 2005, Jonathan Blandford <jrb@gnome.org>
|
||||
*
|
||||
* 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, 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.
|
||||
*/
|
||||
|
||||
#ifndef __TIFF_DOCUMENT_H__
|
||||
#define __TIFF_DOCUMENT_H__
|
||||
|
||||
#include "ev-document.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TIFF_TYPE_DOCUMENT (tiff_document_get_type ())
|
||||
#define TIFF_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIFF_TYPE_DOCUMENT, TiffDocument))
|
||||
#define TIFF_IS_DOCUMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TIFF_TYPE_DOCUMENT))
|
||||
|
||||
typedef struct _TiffDocument TiffDocument;
|
||||
|
||||
GType tiff_document_get_type (void) G_GNUC_CONST;
|
||||
G_MODULE_EXPORT GType register_atril_backend (GTypeModule *module);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __TIFF_DOCUMENT_H__ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue