Import Upstream version 1.24.0

This commit is contained in:
openKylinBot 2022-05-14 03:23:01 +08:00
commit c2026d8250
735 changed files with 520308 additions and 0 deletions

9
.github/FUNDING.yml vendored Normal file
View File

@ -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/

19
.github/issue_template.md vendored Normal file
View File

@ -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

231
.travis.yml Normal file
View File

@ -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

16
.tx/config Normal file
View File

@ -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

14
AUTHORS Normal file
View File

@ -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

340
COPYING Normal file
View File

@ -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.

2
ChangeLog Normal file
View File

@ -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.

90
Makefile.am Normal file
View File

@ -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

610
NEWS Normal file
View File

@ -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 widgets 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.

29
README Normal file
View File

@ -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/ ]

63
atril-document.h Normal file
View File

@ -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 */

12
atril-document.pc.in Normal file
View File

@ -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}

35
atril-view.h Normal file
View File

@ -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 */

11
atril-view.pc.in Normal file
View File

@ -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}

1829
atril.pot Normal file

File diff suppressed because it is too large Load Diff

30
autogen.sh Executable file
View File

@ -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

44
backend/Makefile.am Normal file
View File

@ -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

1
backend/backend.symbols Normal file
View File

@ -0,0 +1 @@
register_atril_backend

View File

@ -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

View File

@ -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__ */

View File

@ -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;

38
backend/djvu/Makefile.am Normal file
View File

@ -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

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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__ */

456
backend/djvu/djvu-links.c Normal file
View File

@ -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;
}

37
backend/djvu/djvu-links.h Normal file
View File

@ -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__ */

View File

@ -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);
}

View File

@ -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__ */

View File

@ -0,0 +1,4 @@
[Atril Backend]
Module=djvudocument
TypeDescription=DjVu Documents
MimeType=image/vnd.djvu;image/vnd.djvu+multipage

45
backend/dvi/Makefile.am Normal file
View File

@ -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

372
backend/dvi/cairo-device.c Normal file
View File

@ -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;
}

View File

@ -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 */

601
backend/dvi/dvi-document.c Normal file
View File

@ -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;
}

View File

@ -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__ */

View File

@ -0,0 +1,4 @@
[Atril Backend]
Module=dvidocument
TypeDescription=DVI Documents
MimeType=application/x-dvi;application/x-bzdvi;application/x-gzdvi

57
backend/dvi/fonts.c Normal file
View File

@ -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;
}

6
backend/dvi/fonts.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef MDVI_FONTS_REGISTRATION_H
#define MDVI_FONTS_REGISTRATION_H
void mdvi_register_fonts (void);
#endif /* MDVI_FONTS_REGISTRATION_H */

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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;
}

519
backend/dvi/mdvi-lib/font.c Normal file
View File

@ -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

View File

@ -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 */

View File

@ -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;
}

395
backend/dvi/mdvi-lib/gf.c Normal file
View File

@ -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;
}

224
backend/dvi/mdvi-lib/hash.c Normal file
View File

@ -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 */
}

View File

@ -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

120
backend/dvi/mdvi-lib/list.c Normal file
View File

@ -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;
}

625
backend/dvi/mdvi-lib/mdvi.h Normal file
View File

@ -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 */

View File

@ -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 */

View File

@ -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);
}

View File

@ -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

580
backend/dvi/mdvi-lib/pk.c Normal file
View File

@ -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;
}

View File

@ -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 */

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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));
}

View File

@ -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 */

630
backend/dvi/mdvi-lib/t1.c Normal file
View File

@ -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 */

214
backend/dvi/mdvi-lib/tfm.c Normal file
View File

@ -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;
}

View File

@ -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);
}

495
backend/dvi/mdvi-lib/tt.c Normal file
View File

@ -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 */

550
backend/dvi/mdvi-lib/util.c Normal file
View File

@ -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);
}

247
backend/dvi/mdvi-lib/vf.c Normal file
View File

@ -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);
}

38
backend/epub/Makefile.am Normal file
View File

@ -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

1831
backend/epub/epub-document.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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__ */

View File

@ -0,0 +1,4 @@
[Atril Backend]
Module=epubdocument
TypeDescription=epub Documents
MimeType=application/epub+zip;

View File

@ -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

View File

@ -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;
}

View File

@ -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

2125
backend/epub/minizip/unzip.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 */

35
backend/pdf/Makefile.am Normal file
View File

@ -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

3338
backend/pdf/ev-poppler.cc Normal file

File diff suppressed because it is too large Load Diff

40
backend/pdf/ev-poppler.h Normal file
View File

@ -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__ */

View File

@ -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;

View File

@ -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

View File

@ -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)
{
}

View File

@ -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__ */

View File

@ -0,0 +1,4 @@
[Atril Backend]
Module=pixbufdocument
TypeDescription=Images
MimeType=image/*;

33
backend/ps/Makefile.am Normal file
View File

@ -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

487
backend/ps/ev-spectre.c Normal file
View File

@ -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;
}

46
backend/ps/ev-spectre.h Normal file
View File

@ -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__ */

View File

@ -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

33
backend/tiff/Makefile.am Normal file
View File

@ -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

View File

@ -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;
}

View File

@ -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