auto merge of #724 : webconv/servo/androidport, r=metajack

Works of android port.

Notices.
1. added more native submodules - libpng, libfreetype2, libfontconfig, libexpat (currently, they are on our repo)
2. build directory change : [build directory]/[XXXX] -> [build dir]/[target triples]/[XXXX]
3. added android main
4. uses freeGLUT instead of GLFW on android
4. fixed misc.

Usage: configure --target-triples=arm-linux-androideabi && make
Result: cross-compiled 32-bit so libraries.
This commit is contained in:
bors-servo 2013-08-22 21:00:42 -07:00
commit 3e36dc3e68
30 changed files with 1245 additions and 132 deletions

12
.gitmodules vendored
View file

@ -106,3 +106,15 @@
[submodule "src/support/png/libpng"]
path = src/support/png/libpng
url = https://github.com/mozilla-servo/libpng.git
[submodule "src/platform/android/fontconfig"]
path = src/platform/android/fontconfig
url = http://github.com/webconvforge/fontconfig.git
[submodule "src/platform/android/libexpat"]
path = src/platform/android/libexpat
url = http://github.com/webconvforge/libexpat.git
[submodule "src/platform/android/libfreetype2"]
path = src/platform/android/libfreetype2
url = http://github.com/webconvforge/libfreetype2.git
[submodule "src/support/glut/rust-glut"]
path = src/support/glut/rust-glut
url = http://github.com/mozilla-servo/rust-glut.git

View file

@ -32,7 +32,7 @@ MKFILE_DEPS := config.stamp $(call rwildcard,$(S)mk/,*)
# Enable debug!() etc even without configure --enable-debug
# The evaluation of these prints & their arguments is controlled
# at runtime by the environment variable RUST_LOG.
CFG_RUSTC_FLAGS := $(RUSTFLAGS) --cfg debug
CFG_RUSTC_FLAGS += --cfg debug
ifdef CFG_DISABLE_OPTIMIZE
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
@ -55,6 +55,15 @@ export CFG_LOCAL_RUSTC
export CFG_ENABLE_DEBUG
export RUSTC=$(CFG_RUSTC)
export RUSTFLAGS=$(CFG_RUSTC_FLAGS)
export CC=$(CFG_CC)
export CXX=$(CFG_CXX)
export LD=$(CFG_LD)
export AR=$(CFG_AR)
export RANLIB=$(CFG_RANLIB)
export PATH=$(CFG_PATH)
export CFG_ANDROID_SDK_PATH
export CFG_OSTYPE
export CFG_CPUTYPE
######################################################################
# Re-configuration
@ -83,7 +92,7 @@ $(S)config.stamp : $(S)configure $(S)Makefile.in
ifneq ($(CFG_LOCAL_RUSTC),1)
$(CFG_RUSTC):
@$(call E, building rustc)
$(Q)$(MAKE) -C "$(CFG_BUILD_DIR)src/compiler/rust" CFG_RUSTC_FLAGS="" RUSTFLAGS=""
$(Q)$(MAKE) -C "$(CFG_BUILD_DIR)src/compiler/rust" CFG_RUSTC_FLAGS="" RUSTFLAGS="" CC=gcc CXX=g++ LD=ld AR=ar
clean-rust:
@$(call E, cleaning rustc)
@ -96,7 +105,7 @@ clean-rust:
endif
src/compiler/rust/rust-auto-clean-stamp: $(S)src/compiler/rust-auto-clean-trigger
$(B)/src/compiler/rust/rust-auto-clean-stamp: $(S)src/compiler/rust-auto-clean-trigger
$(Q)$(MAKE) clean-rust
touch $@
@ -126,6 +135,8 @@ endif
# their name already, while others don't.
DONE_$(1) = $$(B)src/$$(PATH_$(1))/lib*.dummy
DEPS_SUBMODULES += $$(PATH_$(1))
DEPS_SUBMODULES += $$(PATH_$(1))/.libs
DEPS_SUBMODULES += $$(PATH_$(1))/src/.libs
endef
# these will get populated.
@ -140,7 +151,7 @@ include $(S)mk/sub.mk
# Define how to make submodule targets
define DEF_SUBMODULE_RULES
ENV_RLDFLAGS_$(1) = $$(foreach dep,$$(DEPS_$(1)),-L $$(B)src/$$(PATH_$$(dep)))
ENV_RLDFLAGS_$(1) = $$(foreach dep,$$(DEPS_$(1)),-L $$(B)src/$$(PATH_$$(dep)) -L $$(B)src/$$(PATH_$$(dep))/.libs -L $$(B)src/$$(PATH_$$(dep))/src/.libs)
# variables that depend on dependency definitions from sub.mk!
ENV_CFLAGS_$(1) = CFLAGS="$$(CFLAGS_$(1))"
@ -164,10 +175,12 @@ $$(DONE_$(1)) : $$(DONE_DEPS_$(1)) $$(ROUGH_DEPS_$(1)) $$(RUSTC_DEP_$(1))
# @$$(call E, $(1) deps= $$(DEPS_$(1)))
# @$$(call E, $(1) done_deps= $$(DONE_DEPS_$(1)))
# @$$(call E, $(1) cflags= $$(ENV_CFLAGS_$(1)))
# @$$(call E, $(1) cxxflags= $$(ENV_CXXFLAGS_$(1)))
# @$$(call E, $(1) rflags= $$(ENV_RFLAGS_$(1)))
$$(Q) \
$$(ENV_CFLAGS_$(1)) \
$$(ENV_CXXFLAGS_$(1)) \
$$(ENV_RFLAGS_$(1)) \
$$(MAKE) -C $$(B)src/$$(PATH_$(1)) && touch $$(DONE_$(1))
@ -232,29 +245,29 @@ include $(S)mk/clean.mk
.DEFAULT_GOAL := all
.PHONY: all
all: src/compiler/rust/rust-auto-clean-stamp servo package
all: $(B)/src/compiler/rust/rust-auto-clean-stamp servo package
# Servo helper libraries
$(DONE_util): $(DEPS_util)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_util) --out-dir src/components/util $< && touch $@
$(Q)$(RUSTC) $(RFLAGS_util) --out-dir $(B)src/components/util $< && touch $@
$(DONE_net): $(DEPS_net)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_net) --out-dir src/components/net $< && touch $@
$(Q)$(RUSTC) $(RFLAGS_net) --out-dir $(B)src/components/net $< && touch $@
$(DONE_msg): $(DEPS_msg)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_msg) --out-dir src/components/msg $< && touch $@
$(Q)$(RUSTC) $(RFLAGS_msg) --out-dir $(B)src/components/msg $< && touch $@
$(DONE_gfx): $(DEPS_gfx)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_gfx) --out-dir src/components/gfx $< && touch $@
$(Q)$(RUSTC) $(RFLAGS_gfx) --out-dir $(B)src/components/gfx $< && touch $@
$(DONE_script): $(DEPS_script)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_script) --out-dir src/components/script $< && touch $@
$(Q)$(RUSTC) $(RFLAGS_script) --out-dir $(B)src/components/script $< && touch $@
BINDINGS_SRC = $(S)/src/components/script/dom/bindings/codegen
@ -289,21 +302,27 @@ $(BINDINGS_SRC)/ParserResults.pkl: $(globalgen_dependencies) \
# Servo binaries
ifneq ($(CFG_OSTYPE),linux-androideabi)
servo: $(DEPS_servo)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_servo) -o $@ $< --bin
else
servo: $(DEPS_servo)
@$(call E, compile: $@)
$(Q)$(RUSTC) $(RFLAGS_servo) -o $@ $< --lib
endif
# Darwin app packaging
ifeq ($(OSTYPE),apple-darwin)
ifeq ($(CFG_OSTYPE),apple-darwin)
package: servo
mkdir -p Servo.app/Contents/MacOS/src/platform/macos/rust-cocoa
mkdir -p Servo.app/Contents/MacOS/src/platform/macos/rust-azure
cp $(S)/Info.plist Servo.app/Contents/
mkdir -p Servo.app/Contents/MacOS/src/support/azure/rust-azure
cp $(S)Info.plist Servo.app/Contents/
cp servo Servo.app/Contents/MacOS/
cp src/platform/macos/rust-cocoa/lib*.dylib Servo.app/Contents/MacOS/src/platform/macos/rust-cocoa/
cp src/platform/macos/rust-azure/lib*.dylib Servo.app/Contents/MacOS/src/platform/macos/rust-azure/
cp $(B)src/platform/macos/rust-cocoa/lib*.dylib Servo.app/Contents/MacOS/src/platform/macos/rust-cocoa/
cp $(B)src/support/azure/rust-azure/lib*.dylib Servo.app/Contents/MacOS/src/support/azure/rust-azure/
else

341
configure vendored
View file

@ -182,6 +182,82 @@ opt() {
fi
}
split_triple() {
local TRIPLE=$1
local ARCH=$2
local VENDOR=$3
local OS=$4
eval $ARCH=$(echo "$TRIPLE" | cut -d'-' -f1)
eval $VENDOR=$(echo "$TRIPLE" | cut -d'-' -f2)
eval $OS=$(echo "$TRIPLE" | cut -d'-' -f3)
if [ $(echo "$TRIPLE" | cut -d'-' -f3) = "androideabi" ]
then
eval $OS="android"
fi
}
os_type() {
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
local OP=$1
local OSTYPE=$(echo "$2" | tr '[:upper:]' '[:lower:]')
local V="${OP}"
case $OSTYPE in
linux)
eval $V=unknown-linux-gnu
;;
freebsd)
eval $V=unknown-freebsd
;;
darwin)
eval $V=apple-darwin
;;
mingw32*)
eval $V=pc-mingw32
;;
android)
eval $V=linux-androideabi
;;
*)
err "unknown OS type: $OSTYPE"
;;
esac
}
cpu_type() {
local OP=$1
local CPUTYPE=$2
local V="${OP}"
case $CPUTYPE in
i386 | i486 | i686 | i786 | x86)
eval $V=i686
;;
xscale | arm)
eval $V=arm
;;
x86_64 | x86-64 | x64 | amd64)
eval $V=x86_64
;;
*)
err "unknown CPU type: $CPUTYPE"
esac
}
msg "looking for configure programs"
need_cmd cmp
need_cmd mkdir
@ -198,70 +274,29 @@ need_cmd sed
msg "inspecting environment"
CFG_OSTYPE=$(uname -s)
CFG_CPUTYPE=$(uname -m)
OSTYPE=$(uname -s)
CPUTYPE=$(uname -m)
if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ]
if [ $OSTYPE = Darwin -a $CPUTYPE = i386 ]
then
# Darwin's `uname -m` lies and always returns i386. We have to use sysctl
# instead.
if sysctl hw.optional.x86_64 | grep -q ': 1'
then
CFG_CPUTYPE=x86_64
CPUTYPE=x86_64
fi
fi
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
os_type CFG_BUILD_OSTYPE ${OSTYPE}
cpu_type CFG_BUILD_CPUTYPE ${CPUTYPE}
case $CFG_OSTYPE in
Linux)
CFG_OSTYPE=unknown-linux-gnu
;;
FreeBSD)
CFG_OSTYPE=unknown-freebsd
;;
Darwin)
CFG_OSTYPE=apple-darwin
;;
MINGW32*)
CFG_OSTYPE=pc-mingw32
;;
*)
err "unknown OS type: $CFG_OSTYPE"
;;
esac
case $CFG_CPUTYPE in
i386 | i486 | i686 | i786 | x86)
CFG_CPUTYPE=i686
;;
xscale | arm)
CFG_CPUTYPE=arm
;;
x86_64 | x86-64 | x64 | amd64)
CFG_CPUTYPE=x86_64
;;
*)
err "unknown CPU type: $CFG_CPUTYPE"
esac
DEFAULT_HOST_TRIPLE="${CFG_CPUTYPE}-${CFG_OSTYPE}"
DEFAULT_TARGET_TRIPLE="${CFG_BUILD_CPUTYPE}-${CFG_BUILD_OSTYPE}"
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
CFG_BUILD_DIR="$(pwd)/"
CFG_BUILD_HOME="$(pwd)/"
CFG_SELF=${CFG_SRC_DIR}$(basename $0)
CFG_CONFIGURE_ARGS="$@"
CFG_PATH=$PATH
OPTIONS=""
HELP=0
@ -287,6 +322,12 @@ opt manage-submodules 1 "let the build manage the git submodules"
opt fast-make 0 "use .gitmodules as timestamp for submodule deps"
opt debug 0 "use debugging symbols"
valopt local-rust-root "" "set prefix for local rust binary"
valopt target-triples "${DEFAULT_TARGET_TRIPLE}" "target triple to be compiled"
valopt android-cross-path "/opt/ndk_standalone" "Android NDK cross compiler path"
valopt android-ndk-path "/opt/android-ndk" "Android NDK path"
valopt android-sdk-path "/opt/android-sdk" "Android SDK path"
valopt android-font-path "/system/fonts" "Android Font path"
valopt android-resource-path "/sdcard/servo" "Android Resource path"
if [ $HELP -eq 1 ]
then
@ -294,18 +335,47 @@ then
exit 0
fi
# Split target triple
split_triple "${CFG_TARGET_TRIPLES}" TARGET_CPUTYPE TARGET_VENDOR TARGET_OSTYPE
# Set target os and cpu type
os_type CFG_OSTYPE ${TARGET_OSTYPE}
cpu_type CFG_CPUTYPE ${TARGET_CPUTYPE}
step_msg "looking for build programs"
case ${TARGET_OSTYPE} in
android)
CFG_PATH="${CFG_ANDROID_CROSS_PATH}/bin":$PATH
export PATH=${CFG_PATH}
probe CFG_CC arm-linux-androideabi-gcc
probe CFG_CXX arm-linux-androideabi-g++
probe CFG_LD arm-linux-androideabi-ld
probe CFG_AR arm-linux-androideabi-ar
probe CFG_RANLIB arm-linux-androideabi-ranlib
CFG_RUSTC_FLAGS="--target=${CFG_TARGET_TRIPLES} --android-cross-path=${CFG_ANDROID_CROSS_PATH}"
;;
*)
CFG_PATH=$PATH
probe CFG_CC gcc
probe CFG_CXX g++
probe CFG_LD ld
probe CFG_AR ar
probe CFG_RANLIB ranlib
CFG_RUSTC_FLAGS=""
;;
esac
probe_need CFG_GIT git
probe_need CFG_PYTHON2 python2 python2.7 python
probe CFG_CLANG clang++
probe CFG_GCC gcc
probe CFG_LD ld
# Spidermonkey requires autoconf 2.13 exactly
probe_need CFG_AUTOCONF213 autoconf213 \
autoconf2.13 \
autoconf-2.13
CFG_BUILD_DIR="${CFG_BUILD_HOME}${CFG_TARGET_TRIPLES}/"
make_dir "${CFG_BUILD_DIR}"
if [ ! -z "$CFG_LOCAL_RUST_ROOT" ]
then
if [ -f ${CFG_LOCAL_RUST_ROOT}/bin/rustc ]
@ -313,6 +383,7 @@ then
LRV=`${CFG_LOCAL_RUST_ROOT}/bin/rustc --version`
step_msg "using rustc at: ${CFG_LOCAL_RUST_ROOT} with version: $LRV"
CFG_RUSTC=${CFG_LOCAL_RUST_ROOT}/bin/rustc
CFG_RUST_HOME=${CFG_LOCAL_RUST_ROOT}
CFG_LOCAL_RUSTC=1
else
err "No rustc found at ${CFG_LOCAL_RUST_ROOT}/bin/rustc"
@ -320,10 +391,11 @@ then
else
step_msg "using in-tree rust compiler"
# The Rust compiler we're going to build
CFG_RUSTC="${CFG_BUILD_DIR}src/compiler/rust/${DEFAULT_HOST_TRIPLE}/stage2/bin/rustc"
CFG_RUSTC="${CFG_BUILD_DIR}src/compiler/rust/${DEFAULT_TARGET_TRIPLE}/stage2/bin/rustc"
CFG_RUST_HOME="${CFG_BUILD_DIR}src/compiler/rust/${DEFAULT_TARGET_TRIPLE}/stage2"
fi
if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ]
if [ -z "$CFG_ENABLE_CLANG" -a -z "$CFG_CC" ]
then
err "either clang or gcc is required"
fi
@ -372,7 +444,11 @@ msg "configuring src/mozjs"
AUTOCONF213_M4_MACROS="$(dirname ${CFG_AUTOCONF213})/../share/$(basename ${CFG_AUTOCONF213})/"
# Run the SpiderMonkey autoconf using autoconf 2.13
(cd ${CFG_SRC_DIR}src/support/spidermonkey/mozjs/js/src && "${CFG_AUTOCONF213}" -l "${AUTOCONF213_M4_MACROS}") || exit $?
if [ $CFG_OSTYPE = "linux-androideabi" ]
then
msg "configuring src/libexpat"
(cd ${CFG_SRC_DIR}src/platform/android/libexpat/expat && sh "buildconf.sh") || exit $?
fi
# Pixman and cairo require some care to autoconf correctly for our in-tree build.
# The normal autogen.sh files mostly just run autoreconfig but we need more fine control
@ -403,8 +479,6 @@ CFG_SUBMODULES="\
support/css/rust-css \
support/css/rust-cssparser \
support/geom/rust-geom \
support/glfw/glfw \
support/glfw/glfw-rs \
support/harfbuzz/rust-harfbuzz \
support/hubbub/libhubbub \
support/hubbub/rust-hubbub \
@ -428,6 +502,8 @@ CFG_SUBMODULES="\
if [ $CFG_OSTYPE = "apple-darwin" ]
then
CFG_SUBMODULES="\
support/glfw/glfw \
support/glfw/glfw-rs \
platform/macos/rust-cocoa \
platform/macos/rust-core-foundation \
platform/macos/rust-core-graphics \
@ -439,12 +515,54 @@ fi
if [ $CFG_OSTYPE = "unknown-linux-gnu" ]
then
CFG_SUBMODULES="\
support/glfw/glfw \
support/glfw/glfw-rs \
platform/linux/rust-fontconfig \
platform/linux/rust-freetype \
platform/linux/rust-xlib \
${CFG_SUBMODULES}"
fi
if [ $CFG_OSTYPE = "linux-androideabi" ]
then
CFG_SUBMODULES="\
support/glut/rust-glut \
platform/android/libexpat \
platform/android/libfreetype2 \
platform/android/fontconfig \
platform/linux/rust-fontconfig \
platform/linux/rust-freetype \
${CFG_SUBMODULES}"
fi
step_msg "writing configuration"
putvar CFG_TARGET_TRIPLES
putvar CFG_CPUTYPE
putvar CFG_OSTYPE
putvar CFG_SRC_DIR
putvar CFG_BUILD_HOME
putvar CFG_BUILD_DIR
putvar CFG_CONFIGURE_ARGS
putvar CFG_SUBMODULES
putvar CFG_DISABLE_MANAGE_SUBMODULES
putvar CFG_RUSTC
putvar CFG_RUSTC_FLAGS
putvar CFG_RUST_HOME
putvar CFG_PATH
putvar CFG_LOCAL_RUSTC
putvar CFG_LOCAL_RUST_ROOT
putvar CFG_ENABLE_DEBUG
msg
copy_if_changed ${CFG_SRC_DIR}Makefile.in ${CFG_BUILD_HOME}Makefile
move_if_changed ${CFG_SRC_DIR}config.tmp ${CFG_SRC_DIR}config.mk
copy_if_changed ${CFG_SRC_DIR}config.mk ${CFG_BUILD_HOME}config.mk
rm -f ${CFG_SRC_DIR}config.tmp
touch ${CFG_SRC_DIR}config.stamp
export CFG_CONFIG_MK="${CFG_BUILD_HOME}config.mk"
step_msg "making build directories"
cd "${CFG_BUILD_DIR}"
@ -484,14 +602,28 @@ done
if [ ${do_reconfigure} -ne 0 ]
then
cd ${CFG_BUILD_DIR}src/compiler/rust
${CFG_SRC_DIR}src/compiler/rust/configure
RUST_CONFIGURE_ARGS=""
if [ $CFG_OSTYPE = "linux-androideabi" ]; then
RUST_CONFIGURE_ARGS="--target-triples=arm-linux-androideabi --android-cross-path=${CFG_ANDROID_CROSS_PATH}"
fi
${CFG_SRC_DIR}src/compiler/rust/configure ${RUST_CONFIGURE_ARGS}
cd ${CFG_BUILD_DIR}
fi
#fontconfig expects to use an installed freetype, but we want to override that behavior to use our version
if [ $CFG_OSTYPE = "linux-androideabi" ]
then
export FREETYPE_CFLAGS="-I${CFG_SRC_DIR}src/platform/android/libfreetype2/include -I${CFG_BUILD_DIR}src/platform/android/libfreetype2/include"
export FREETYPE_LIBS="-L${CFG_BUILD_DIR}src/platform/android/libfreetype2/.libs -lfreetype"
fi
# PIC all the things
export CFLAGS="${CFLAGS} -fPIC"
export LDFLAGS="${CFLAGS} -fPIC"
# cross compile configurations
EXTRA_CONFIGURE_ARGS="CC=${CFG_CC} CXX=${CFG_CXX} LD=${CFG_LD} AR=${CFG_AR} RANLIB=${CFG_RANLIB}"
for i in ${CFG_SUBMODULES}
do
if [ -d ${CFG_BUILD_DIR}src/${i} ]
@ -499,25 +631,69 @@ do
cd ${CFG_BUILD_DIR}src/${i}
fi
CONFIGURE_SCRIPT="${CFG_SRC_DIR}src/${i}/configure"
# needed because Spidermonkey configure is in non-standard location
if [ $i = "support/spidermonkey/mozjs" ]; then
CONFIGURE_SCRIPT="${CFG_SRC_DIR}src/${i}/js/src/configure"
fi
# needed because Azure's configure wants "--enable-skia"
CONFIGURE_ARGS=""
ENV_VARS=""
if [ $i = "support/azure/rust-azure" ]; then
CONFIGURE_ARGS="--enable-skia"
fi
if [ $i = "support/nss/nspr" ]; then
CONFIGURE_ARGS="--enable-64bit"
fi
if [ $i = "support/spidermonkey/mozjs" ]; then
if [ ! -z $CFG_ENABLE_DEBUG ]; then
CONFIGURE_ARGS="--enable-debug"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --enable-debug"
fi
case $i in
support/nss/nspr)
if [ ${CFG_OSTYPE} = "linux-androideabi" ]; then
CONFIGURE_ARGS="${CONFIGURE_ARGS} --target=arm-linux-androideabi"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-android-ndk=${CFG_ANDROID_NDK_PATH}"
else
CONFIGURE_ARGS="${CONFIGURE_ARGS} --enable-64bit"
fi
;;
support/nss/nss)
if [ ${CFG_OSTYPE} = "linux-androideabi" ]; then
CONFIGURE_ARGS="${CONFIGURE_ARGS} --host=arm-linux-androideabi"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --android-ndk-path=${CFG_ANDROID_NDK_PATH}"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --android-api-version=14"
fi
CONFIGURE_ARGS="${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}"
;;
platform/android/libexpat)
CONFIGURE_SCRIPT="${CFG_SRC_DIR}src/${i}/expat/configure"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --host=arm-linux-androideabi"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-sysroot=${CFG_ANDROID_CROSS_PATH}/sysroot"
CONFIGURE_ARGS="${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}"
;;
platform/android/libfreetype2)
CONFIGURE_ARGS="${CONFIGURE_ARGS} --host=arm-linux"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-sysroot=${CFG_ANDROID_CROSS_PATH}/sysroot"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --without-zlib"
CONFIGURE_ARGS="${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}"
;;
platform/android/fontconfig)
CONFIGURE_SCRIPT="${CFG_SRC_DIR}src/${i}/autogen.sh"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --host=arm-linux-androideabi"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-arch=arm"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-expat-includes=${CFG_SRC_DIR}src/platform/android/libexpat/expat/lib"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-expat-lib=${CFG_BUILD_DIR}src/platform/android/libexpat/.libs"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-sysroot=${CFG_ANDROID_CROSS_PATH}/sysroot"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-cache-dir=${CFG_ANDROID_RESOURCE_PATH}/.fccache"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-confdir=${CFG_ANDROID_RESOURCE_PATH}/.fcconfig"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-default-fonts=${CFG_ANDROID_FONT_PATH}"
CONFIGURE_ARGS="${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}"
;;
support/spidermonkey/mozjs)
# needed because Spidermonkey configure is in non-standard location
CONFIGURE_SCRIPT="${CFG_SRC_DIR}src/${i}/js/src/configure"
if [ ${CFG_OSTYPE} = "linux-androideabi" ]; then
CONFIGURE_ARGS="${CONFIGURE_ARGS} --target=arm-linux-androideabi"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-android-ndk=${CFG_ANDROID_NDK_PATH}"
fi
;;
support/azure/rust-azure)
# needed because Azure's configure wants "--enable-skia"
CONFIGURE_ARGS="${CONFIGURE_ARGS} --enable-skia"
;;
*)
;;
esac
if [ -f ${CONFIGURE_SCRIPT} ]
then
@ -525,25 +701,4 @@ do
fi
done
step_msg "writing configuration"
putvar DEFAULT_HOST_TRIPLE
putvar CFG_CPUTYPE
putvar CFG_OSTYPE
putvar CFG_SRC_DIR
putvar CFG_BUILD_DIR
putvar CFG_CONFIGURE_ARGS
putvar CFG_SUBMODULES
putvar CFG_DISABLE_MANAGE_SUBMODULES
putvar CFG_RUSTC
putvar CFG_LOCAL_RUSTC
putvar CFG_ENABLE_DEBUG
msg
copy_if_changed ${CFG_SRC_DIR}Makefile.in ${CFG_BUILD_DIR}Makefile
move_if_changed ${CFG_SRC_DIR}config.tmp ${CFG_SRC_DIR}config.mk
copy_if_changed ${CFG_SRC_DIR}config.mk ${CFG_BUILD_DIR}config.mk
rm -f ${CFG_SRC_DIR}config.tmp
touch ${CFG_SRC_DIR}config.stamp
step_msg "complete"

View file

@ -6,6 +6,7 @@ check-$(1) : $$(DONE_$(1))
$$(Q) \
$$(ENV_CFLAGS_$(1)) \
$$(ENV_CXXFLAGS_$(1)) \
$$(ENV_RFLAGS_$(1)) \
$$(MAKE) -C $$(B)src/$$(PATH_$(1)) check

View file

@ -47,4 +47,4 @@ clean-script:
clean-servo: clean-gfx clean-util clean-net clean-script clean-msg
@$(call E, "cleaning servo")
$(Q)rm -f servo servo-test
$(Q)rm -f servo servo-test libservo*.so

View file

@ -157,3 +157,51 @@ DEPS_rust-layers += \
$(NULL)
endif
ifeq ($(CFG_OSTYPE),linux-androideabi)
DEPS_rust-azure += \
rust-freetype \
rust-fontconfig \
fontconfig \
libfreetype2 \
libexpat \
$(NULL)
# See note at top of file
DEPS_rust-layers += \
rust-freetype \
rust-fontconfig \
$(NULL)
DEPS_rust-fontconfig += \
fontconfig \
rust-freetype \
$(NULL)
DEPS_rust-freetype += \
libfreetype2 \
$(NULL)
DEPS_fontconfig += \
libexpat \
libfreetype2 \
$(NULL)
CFLAGS_fontconfig += \
"-I$(S)src/platform/android/libexpat/expat/lib" \
"-I$(S)src/platform/android/libfreetype2/include" \
$(NULL)
endif
DEPS_skia += \
libfreetype2 \
$(NULL)
CXXFLAGS_skia += \
-I$(S)src/platform/android/libfreetype2/include \
$(NULL)
NATIVE_BUILD += \
libfreetype2 \
libexpat \
fontconfig \
$(NULL)

View file

@ -353,6 +353,7 @@ impl Font {
}
#[cfg(target_os="linux")]
#[cfg(target_os="android")]
fn create_azure_font(&self) -> ScaledFont {
let freetype_font = self.handle.face;
let size = self.style.pt_size as AzFloat;

View file

@ -20,9 +20,9 @@ extern mod servo_msg (name = "msg");
// shapers. For now, however, this is a hard dependency.
extern mod harfbuzz;
// Linux-specific library dependencies
#[cfg(target_os="linux")] extern mod fontconfig;
#[cfg(target_os="linux")] extern mod freetype;
// Linux and Android-specific library dependencies
#[cfg(target_os="linux")] #[cfg(target_os="android")] extern mod fontconfig;
#[cfg(target_os="linux")] #[cfg(target_os="android")] extern mod freetype;
// Mac OS-specific library dependencies
#[cfg(target_os="macos")] extern mod core_foundation;

View file

@ -0,0 +1,331 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern mod freetype;
use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle, FontWeight100};
use font::{FontWeight200, FontWeight300, FontWeight400, FontWeight500, FontWeight600};
use font::{FontWeight700, FontWeight800, FontWeight900};
use geometry::Au;
use geometry;
use platform::font_context::FontContextHandle;
use text::glyph::GlyphIndex;
use text::util::{float_to_fixed, fixed_to_float};
use freetype::freetype::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::{FT_Load_Glyph, FT_Set_Char_Size};
use freetype::freetype::{FT_New_Face, FT_Get_Sfnt_Table};
use freetype::freetype::{FT_New_Memory_Face, FT_Done_Face};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
use freetype::freetype::{FT_STYLE_FLAG_ITALIC, FT_STYLE_FLAG_BOLD};
use freetype::freetype::{FT_SizeRec, FT_UInt, FT_Size_Metrics};
use freetype::freetype::{ft_sfnt_os2};
use freetype::tt_os2::TT_OS2;
use std::cast;
use std::ptr;
use std::str;
fn float_to_fixed_ft(f: float) -> i32 {
float_to_fixed(6, f)
}
fn fixed_to_float_ft(f: i32) -> float {
fixed_to_float(6, f)
}
pub struct FontTable {
bogus: ()
}
impl FontTableMethods for FontTable {
fn with_buffer(&self, _blk: &fn(*u8, uint)) {
fail!()
}
}
enum FontSource {
FontSourceMem(~[u8]),
FontSourceFile(~str)
}
pub struct FontHandle {
// The font binary. This must stay valid for the lifetime of the font,
// if the font is created using FT_Memory_Face.
source: FontSource,
face: FT_Face,
handle: FontContextHandle
}
#[unsafe_destructor]
impl Drop for FontHandle {
fn drop(&self) {
assert!(self.face.is_not_null());
unsafe {
if !FT_Done_Face(self.face).succeeded() {
fail!(~"FT_Done_Face failed");
}
}
}
}
impl FontHandleMethods for FontHandle {
fn new_from_buffer(fctx: &FontContextHandle,
buf: ~[u8],
style: &SpecifiedFontStyle)
-> Result<FontHandle, ()> {
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
let face_result = do buf.as_imm_buf |bytes: *u8, len: uint| {
create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
};
// TODO: this could be more simply written as result::chain
// and moving buf into the struct ctor, but cant' move out of
// captured binding.
return match face_result {
Ok(face) => {
let handle = FontHandle {
face: face,
source: FontSourceMem(buf),
handle: *fctx
};
Ok(handle)
}
Err(()) => Err(())
};
fn create_face_from_buffer(lib: FT_Library,
cbuf: *u8, cbuflen: uint, pt_size: float)
-> Result<FT_Face, ()> {
unsafe {
let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long;
let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
face_index, ptr::to_mut_unsafe_ptr(&mut face));
if !result.succeeded() || face.is_null() {
return Err(());
}
if FontHandle::set_char_size(face, pt_size).is_ok() {
Ok(face)
} else {
Err(())
}
}
}
}
// an identifier usable by FontContextHandle to recreate this FontHandle.
fn face_identifier(&self) -> ~str {
/* FT_Get_Postscript_Name seems like a better choice here, but it
doesn't give usable results for fontconfig when deserializing. */
unsafe { str::raw::from_c_str((*self.face).family_name) }
}
fn family_name(&self) -> ~str {
unsafe { str::raw::from_c_str((*self.face).family_name) }
}
fn face_name(&self) -> ~str {
unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
}
fn is_italic(&self) -> bool {
unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
}
fn boldness(&self) -> CSSFontWeight {
let default_weight = FontWeight400;
if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
default_weight
} else {
unsafe {
let os2 = FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *TT_OS2;
let valid = os2.is_not_null() && (*os2).version != 0xffff;
if valid {
let weight =(*os2).usWeightClass;
match weight {
1 | 100..199 => FontWeight100,
2 | 200..299 => FontWeight200,
3 | 300..399 => FontWeight300,
4 | 400..499 => FontWeight400,
5 | 500..599 => FontWeight500,
6 | 600..699 => FontWeight600,
7 | 700..799 => FontWeight700,
8 | 800..899 => FontWeight800,
9 | 900..999 => FontWeight900,
_ => default_weight
}
} else {
default_weight
}
}
}
}
fn clone_with_style(&self,
fctx: &FontContextHandle,
style: &UsedFontStyle) -> Result<FontHandle, ()> {
match self.source {
FontSourceMem(ref buf) => {
FontHandleMethods::new_from_buffer(fctx, buf.clone(), style)
}
FontSourceFile(ref file) => {
FontHandle::new_from_file(fctx, (*file).clone(), style)
}
}
}
fn glyph_index(&self,
codepoint: char) -> Option<GlyphIndex> {
assert!(self.face.is_not_null());
unsafe {
let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
return if idx != 0 as FT_UInt {
Some(idx as GlyphIndex)
} else {
debug!("Invalid codepoint: %?", codepoint);
None
};
}
}
fn glyph_h_advance(&self,
glyph: GlyphIndex) -> Option<FractionalPixel> {
assert!(self.face.is_not_null());
unsafe {
let res = FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
if res.succeeded() {
let void_glyph = (*self.face).glyph;
let slot: FT_GlyphSlot = cast::transmute(void_glyph);
assert!(slot.is_not_null());
debug!("metrics: %?", (*slot).metrics);
let advance = (*slot).metrics.horiAdvance;
debug!("h_advance for %? is %?", glyph, advance);
let advance = advance as i32;
return Some(fixed_to_float_ft(advance) as FractionalPixel);
} else {
debug!("Unable to load glyph %?. reason: %?", glyph, res);
return None;
}
}
}
fn get_metrics(&self) -> FontMetrics {
/* TODO(Issue #76): complete me */
let face = self.get_face_rec();
let underline_size = self.font_units_to_au(face.underline_thickness as float);
let underline_offset = self.font_units_to_au(face.underline_position as float);
let em_size = self.font_units_to_au(face.units_per_EM as float);
let ascent = self.font_units_to_au(face.ascender as float);
let descent = self.font_units_to_au(face.descender as float);
let max_advance = self.font_units_to_au(face.max_advance_width as float);
return FontMetrics {
underline_size: underline_size,
underline_offset: underline_offset,
leading: geometry::from_pt(0.0), //FIXME
x_height: geometry::from_pt(0.0), //FIXME
em_size: em_size,
ascent: ascent,
descent: -descent, // linux font's seem to use the opposite sign from mac
max_advance: max_advance
}
}
fn get_table_for_tag(&self, _: FontTableTag) -> Option<FontTable> {
None
}
}
impl<'self> FontHandle {
fn set_char_size(face: FT_Face, pt_size: float) -> Result<(), ()>{
let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
let h_dpi = 72;
let v_dpi = 72;
unsafe {
let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
if result.succeeded() { Ok(()) } else { Err(()) }
}
}
pub fn new_from_file(fctx: &FontContextHandle, file: ~str,
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
unsafe {
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long;
do file.to_c_str().with_ref |file_str| {
FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_mut_unsafe_ptr(&mut face));
}
if face.is_null() {
return Err(());
}
if FontHandle::set_char_size(face, style.pt_size).is_ok() {
Ok(FontHandle {
source: FontSourceFile(file),
face: face,
handle: *fctx
})
} else {
Err(())
}
}
}
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
-> Result<FontHandle, ()> {
unsafe {
let ft_ctx: FT_Library = fctx.ctx.ctx;
if ft_ctx.is_null() { return Err(()); }
let mut face: FT_Face = ptr::null();
let face_index = 0 as FT_Long;
do file.to_c_str().with_ref |file_str| {
FT_New_Face(ft_ctx, file_str,
face_index, ptr::to_mut_unsafe_ptr(&mut face));
}
if face.is_null() {
return Err(());
}
Ok(FontHandle {
source: FontSourceFile(file),
face: face,
handle: *fctx
})
}
}
fn get_face_rec(&'self self) -> &'self FT_FaceRec {
unsafe {
&(*self.face)
}
}
fn font_units_to_au(&self, value: float) -> Au {
let face = self.get_face_rec();
// face.size is a *c_void in the bindings, presumably to avoid
// recursive structural types
let size: &FT_SizeRec = unsafe { cast::transmute(&(*face.size)) };
let metrics: &FT_Size_Metrics = &(*size).metrics;
let em_size = face.units_per_EM as float;
let x_scale = (metrics.x_ppem as float) / em_size as float;
// If this isn't true then we're scaling one of the axes wrong
assert!(metrics.x_ppem == metrics.y_ppem);
return geometry::from_frac_px(value * x_scale);
}
}

View file

@ -0,0 +1,60 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use font::UsedFontStyle;
use platform::font::FontHandle;
use font_context::FontContextHandleMethods;
use platform::font_list::path_from_identifier;
use freetype::freetype::{FTErrorMethods, FT_Library};
use freetype::freetype::{FT_Done_FreeType, FT_Init_FreeType};
use std::ptr;
struct FreeTypeLibraryHandle {
ctx: FT_Library,
}
impl Drop for FreeTypeLibraryHandle {
fn drop(&self) {
assert!(self.ctx.is_not_null());
unsafe {
FT_Done_FreeType(self.ctx);
}
}
}
pub struct FontContextHandle {
ctx: @FreeTypeLibraryHandle,
}
impl FontContextHandle {
pub fn new() -> FontContextHandle {
unsafe {
let ctx: FT_Library = ptr::null();
let result = FT_Init_FreeType(ptr::to_unsafe_ptr(&ctx));
if !result.succeeded() { fail!(); }
FontContextHandle {
ctx: @FreeTypeLibraryHandle { ctx: ctx },
}
}
}
}
impl FontContextHandleMethods for FontContextHandle {
fn clone(&self) -> FontContextHandle {
FontContextHandle { ctx: self.ctx }
}
fn create_font_from_identifier(&self, name: ~str, style: UsedFontStyle)
-> Result<FontHandle, ()> {
debug!("Creating font handle for %s", name);
do path_from_identifier(name, &style).chain |file_name| {
debug!("Opening font face %s", file_name);
FontHandle::new_from_file(self, file_name, &style)
}
}
}

View file

@ -0,0 +1,205 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern mod freetype;
extern mod fontconfig;
use fontconfig::fontconfig::{
FcChar8, FcResultMatch, FcSetSystem, FcPattern,
FcResultNoMatch, FcMatchPattern, FC_SLANT_ITALIC, FC_WEIGHT_BOLD
};
use fontconfig::fontconfig::{
FcConfigGetCurrent, FcConfigGetFonts, FcPatternGetString,
FcPatternDestroy, FcFontSetDestroy, FcConfigSubstitute,
FcDefaultSubstitute, FcPatternCreate, FcPatternAddString, FcPatternAddInteger,
FcFontMatch, FcFontSetList, FcObjectSetCreate, FcObjectSetDestroy,
FcObjectSetAdd, FcPatternGetInteger
};
use font::{FontHandleMethods, UsedFontStyle};
use font_context::FontContextHandleMethods;
use font_list::{FontEntry, FontFamily, FontFamilyMap};
use platform::font::FontHandle;
use platform::font_context::FontContextHandle;
use std::hashmap::HashMap;
use std::libc;
use std::libc::{c_int, c_char};
use std::ptr;
use std::str;
pub struct FontListHandle {
fctx: FontContextHandle,
}
impl FontListHandle {
pub fn new(fctx: &FontContextHandle) -> FontListHandle {
FontListHandle { fctx: fctx.clone() }
}
pub fn get_available_families(&self) -> FontFamilyMap {
let mut family_map : FontFamilyMap = HashMap::new();
unsafe {
let config = FcConfigGetCurrent();
let fontSet = FcConfigGetFonts(config, FcSetSystem);
for i in range(0, (*fontSet).nfont as int) {
let font = (*fontSet).fonts.offset(i);
let family: *FcChar8 = ptr::null();
let mut v: c_int = 0;
do "family".to_c_str().with_ref |FC_FAMILY| {
while FcPatternGetString(*font, FC_FAMILY, v, &family) == FcResultMatch {
let family_name = str::raw::from_c_str(family as *c_char);
debug!("Creating new FontFamily for family: %s", family_name);
let new_family = @mut FontFamily::new(family_name);
family_map.insert(family_name, new_family);
v += 1;
}
}
}
}
return family_map;
}
pub fn load_variations_for_family(&self, family: @mut FontFamily) {
debug!("getting variations for %?", family);
unsafe {
let config = FcConfigGetCurrent();
let font_set = FcConfigGetFonts(config, FcSetSystem);
let font_set_array_ptr = ptr::to_unsafe_ptr(&font_set);
let pattern = FcPatternCreate();
assert!(pattern.is_not_null());
do "family".to_c_str().with_ref |FC_FAMILY| {
do family.family_name.to_c_str().with_ref |family_name| {
let ok = FcPatternAddString(pattern, FC_FAMILY, family_name as *FcChar8);
assert!(ok != 0);
}
}
let object_set = FcObjectSetCreate();
assert!(object_set.is_not_null());
do "file".to_c_str().with_ref |FC_FILE| {
FcObjectSetAdd(object_set, FC_FILE);
}
do "index".to_c_str().with_ref |FC_INDEX| {
FcObjectSetAdd(object_set, FC_INDEX);
}
let matches = FcFontSetList(config, font_set_array_ptr, 1, pattern, object_set);
debug!("found %? variations", (*matches).nfont);
for i in range(0, (*matches).nfont as int) {
let font = (*matches).fonts.offset(i);
let file = do "file".to_c_str().with_ref |FC_FILE| {
let file: *FcChar8 = ptr::null();
if FcPatternGetString(*font, FC_FILE, 0, &file) == FcResultMatch {
str::raw::from_c_str(file as *libc::c_char)
} else {
fail!();
}
};
let index = do "index".to_c_str().with_ref |FC_INDEX| {
let index: libc::c_int = 0;
if FcPatternGetInteger(*font, FC_INDEX, 0, &index) == FcResultMatch {
index
} else {
fail!();
}
};
debug!("variation file: %?", file);
debug!("variation index: %?", index);
let font_handle = FontHandle::new_from_file_unstyled(&self.fctx,
file);
let font_handle = font_handle.unwrap();
debug!("Creating new FontEntry for face: %s", font_handle.face_name());
let entry = @FontEntry::new(font_handle);
family.entries.push(entry);
}
FcFontSetDestroy(matches);
FcPatternDestroy(pattern);
FcObjectSetDestroy(object_set);
}
}
pub fn get_last_resort_font_families() -> ~[~str] {
~[~"Roboto"]
}
}
struct AutoPattern {
pattern: *FcPattern
}
impl Drop for AutoPattern {
fn drop(&self) {
unsafe {
FcPatternDestroy(self.pattern);
}
}
}
pub fn path_from_identifier(name: ~str, style: &UsedFontStyle) -> Result<~str, ()> {
unsafe {
let config = FcConfigGetCurrent();
let wrapper = AutoPattern { pattern: FcPatternCreate() };
let pattern = wrapper.pattern;
let res = do "family".to_c_str().with_ref |FC_FAMILY| {
do name.to_c_str().with_ref |family| {
FcPatternAddString(pattern, FC_FAMILY, family as *FcChar8)
}
};
if res != 1 {
debug!("adding family to pattern failed");
return Err(());
}
if style.italic {
let res = do "slant".to_c_str().with_ref |FC_SLANT| {
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC)
};
if res != 1 {
debug!("adding slant to pattern failed");
return Err(());
}
}
if style.weight.is_bold() {
let res = do "weight".to_c_str().with_ref |FC_WEIGHT| {
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD)
};
if res != 1 {
debug!("adding weight to pattern failed");
return Err(());
}
}
if FcConfigSubstitute(config, pattern, FcMatchPattern) != 1 {
debug!("substitution failed");
return Err(());
}
FcDefaultSubstitute(pattern);
let result = FcResultNoMatch;
let result_wrapper = AutoPattern { pattern: FcFontMatch(config, pattern, &result) };
let result_pattern = result_wrapper.pattern;
if result != FcResultMatch && result_pattern.is_null() {
debug!("obtaining match to pattern failed");
return Err(());
}
let file: *FcChar8 = ptr::null();
let res = do "file".to_c_str().with_ref |FC_FILE| {
FcPatternGetString(result_pattern, FC_FILE, 0, &file)
};
if res != FcResultMatch {
debug!("getting filename for font failed");
return Err(());
}
Ok(str::raw::from_c_str(file as *c_char))
}
}

View file

@ -4,6 +4,7 @@
#[cfg(target_os="linux")] pub use platform::linux::{font, font_context, font_list};
#[cfg(target_os="macos")] pub use platform::macos::{font, font_context, font_list};
#[cfg(target_os="android")] pub use platform::android::{font, font_context, font_list};
#[cfg(target_os="linux")]
pub mod linux {
@ -19,3 +20,9 @@ pub mod macos {
pub mod font_list;
}
#[cfg(target_os="android")]
pub mod android {
pub mod font;
pub mod font_context;
pub mod font_list;
}

View file

@ -14,6 +14,8 @@ use std::util::replace;
use gfx::render_task::BufferRequest;
use servo_msg::compositor_msg::Tile;
static HEADER: &'static str = "<!DOCTYPE html><html>";
/// Parent to all quadtree nodes. Stores variables needed at all levels. All method calls
/// at this level are in pixel coordinates.
pub struct Quadtree<T> {
@ -298,7 +300,6 @@ impl<T: Tile> Quadtree<T> {
/// Generate html to visualize the tree. For debugging purposes only.
pub fn get_html(&self) -> ~str {
static HEADER: &'static str = "<!DOCTYPE html><html>";
fmt!("%s<body>%s</body></html>", HEADER, self.root.get_html())
}

View file

@ -0,0 +1,247 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A windowing implementation using GLUT.
use windowing::{ApplicationMethods, WindowEvent, WindowMethods};
use windowing::{IdleWindowEvent, ResizeWindowEvent, LoadUrlWindowEvent, MouseWindowEventClass};
use windowing::{ScrollWindowEvent, ZoomWindowEvent, NavigationWindowEvent, FinishedWindowEvent};
use windowing::{QuitWindowEvent, MouseWindowClickEvent, MouseWindowMouseDownEvent, MouseWindowMouseUpEvent};
use windowing::{Forward, Back};
use alert::{Alert, AlertMethods};
use std::libc::c_int;
use geom::point::Point2D;
use geom::size::Size2D;
use servo_msg::compositor_msg::{IdleRenderState, RenderState, RenderingRenderState};
use servo_msg::compositor_msg::{FinishedLoading, Blank, Loading, PerformingLayout, ReadyState};
use glut::glut::{ACTIVE_CTRL, ACTIVE_SHIFT, DOUBLE, HAVE_PRECISE_MOUSE_WHEEL, WindowHeight};
use glut::glut::WindowWidth;
use glut::glut;
static THROBBER: [char, ..8] = [ '⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷' ];
/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;
impl ApplicationMethods for Application {
fn new() -> Application {
glut::init();
glut::init_display_mode(DOUBLE);
Application
}
}
impl Drop for Application {
fn drop(&self) {
}
}
/// The type of a window.
pub struct Window {
glut_window: glut::Window,
event_queue: @mut ~[WindowEvent],
drag_origin: Point2D<c_int>,
mouse_down_button: @mut c_int,
mouse_down_point: @mut Point2D<c_int>,
ready_state: ReadyState,
render_state: RenderState,
throbber_frame: u8,
}
impl WindowMethods<Application> for Window {
/// Creates a new window.
fn new(_: &Application) -> @mut Window {
// Create the GLUT window.
unsafe { glut::glutInitWindowSize(800, 600); }
let glut_window = glut::create_window(~"Servo");
// Create our window object.
let window = @mut Window {
glut_window: glut_window,
event_queue: @mut ~[],
drag_origin: Point2D(0 as c_int, 0),
mouse_down_button: @mut 0,
mouse_down_point: @mut Point2D(0 as c_int, 0),
ready_state: Blank,
render_state: IdleRenderState,
throbber_frame: 0,
};
let event_queue = window.event_queue;
// Register event handlers.
do glut::reshape_func(window.glut_window) |width, height| {
event_queue.push(ResizeWindowEvent(width as uint, height as uint))
}
do glut::keyboard_func |key, _, _| {
window.handle_key(key)
}
do glut::mouse_func |button, state, x, y| {
if button < 3 {
window.handle_mouse(button, state, x, y);
}
else {
match button {
3 => {
event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
},
4 => {
event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
},
_ => {}
}
}
}
window
}
/// Returns the size of the window.
fn size(&self) -> Size2D<f32> {
Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
}
/// Presents the window to the screen (perhaps by page flipping).
fn present(&mut self) {
glut::swap_buffers();
}
fn recv(@mut self) -> WindowEvent {
if !self.event_queue.is_empty() {
return self.event_queue.shift()
}
glut::check_loop();
if !self.event_queue.is_empty() {
self.event_queue.shift()
} else {
IdleWindowEvent
}
}
/// Sets the ready state.
fn set_ready_state(@mut self, ready_state: ReadyState) {
self.ready_state = ready_state;
//FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
//self.update_window_title()
}
/// Sets the render state.
fn set_render_state(@mut self, render_state: RenderState) {
if self.ready_state == FinishedLoading &&
self.render_state == RenderingRenderState &&
render_state == IdleRenderState {
// page loaded
self.event_queue.push(FinishedWindowEvent);
}
self.render_state = render_state;
//FIXME: set_window_title causes crash with Android version of freeGLUT. Temporarily blocked.
//self.update_window_title()
}
fn hidpi_factor(@mut self) -> f32 {
//FIXME: Do nothing in GLUT now.
0f32
}
}
impl Window {
/// Helper function to set the window title in accordance with the ready state.
fn update_window_title(&self) {
let throbber = THROBBER[self.throbber_frame];
match self.ready_state {
Blank => {
glut::set_window_title(self.glut_window, fmt!("Blank"))
}
Loading => {
glut::set_window_title(self.glut_window, fmt!("%c Loading . Servo", throbber))
}
PerformingLayout => {
glut::set_window_title(self.glut_window, fmt!("%c Performing Layout . Servo", throbber))
}
FinishedLoading => {
match self.render_state {
RenderingRenderState => {
glut::set_window_title(self.glut_window, fmt!("%c Rendering . Servo", throbber))
}
IdleRenderState => glut::set_window_title(self.glut_window, "Servo"),
}
}
}
}
/// Helper function to handle keyboard events.
fn handle_key(&self, key: u8) {
debug!("got key: %?", key);
let modifiers = glut::get_modifiers();
match key {
42 => self.load_url(),
43 => self.event_queue.push(ZoomWindowEvent(1.1)),
45 => self.event_queue.push(ZoomWindowEvent(0.909090909)),
56 => self.event_queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))),
50 => self.event_queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))),
127 => {
if (modifiers & ACTIVE_SHIFT) != 0 {
self.event_queue.push(NavigationWindowEvent(Forward));
}
else {
self.event_queue.push(NavigationWindowEvent(Back));
}
}
_ => {}
}
}
/// Helper function to handle a click
fn handle_mouse(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
// FIXME(tkuehn): max pixel dist should be based on pixel density
let max_pixel_dist = 10f;
let event = match state {
glut::MOUSE_DOWN => {
*self.mouse_down_point = Point2D(x, y);
*self.mouse_down_button = button;
MouseWindowMouseDownEvent(button as uint, Point2D(x as f32, y as f32))
}
glut::MOUSE_UP => {
if *self.mouse_down_button == button {
let pixel_dist = *self.mouse_down_point - Point2D(x, y);
let pixel_dist = ((pixel_dist.x * pixel_dist.x +
pixel_dist.y * pixel_dist.y) as float).sqrt();
if pixel_dist < max_pixel_dist {
let click_event = MouseWindowClickEvent(button as uint,
Point2D(x as f32, y as f32));
self.event_queue.push(MouseWindowEventClass(click_event));
}
}
MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
}
_ => fail!("I cannot recognize the type of mouse action that occured. :-(")
};
self.event_queue.push(MouseWindowEventClass(event));
}
/// Helper function to pop up an alert box prompting the user to load a URL.
fn load_url(&self) {
let mut alert: Alert = AlertMethods::new("Navigate to:");
alert.add_prompt();
alert.run();
let value = alert.prompt_value();
if "" == value { // To avoid crashing on Linux.
self.event_queue.push(LoadUrlWindowEvent(~"http://purple.com/"))
} else {
self.event_queue.push(LoadUrlWindowEvent(value))
}
}
}

View file

@ -4,13 +4,17 @@
//! Platform-specific functionality for Servo.
#[cfg(not(shared_gl_windowing))]
#[cfg(not(shared_gl_windowing), target_os="android")]
pub use platform::common::glut_windowing::{Application, Window};
#[cfg(not(shared_gl_windowing), not(target_os="android"))]
pub use platform::common::glfw_windowing::{Application, Window};
#[cfg(shared_gl_windowing)]
pub use platform::common::shared_gl_windowing::{Application, Window};
pub mod common {
#[cfg(not(shared_gl_windowing))]
#[cfg(not(shared_gl_windowing), target_os="android")]
pub mod glut_windowing;
#[cfg(not(shared_gl_windowing), not(target_os="android"))]
pub mod glfw_windowing;
#[cfg(shared_gl_windowing)]
pub mod shared_gl_windowing;

View file

@ -15,8 +15,11 @@ extern mod alert;
extern mod azure;
extern mod geom;
extern mod gfx (name = "gfx");
#[cfg(not(target_os="android"))]
extern mod glfw;
//extern mod http_client;
#[cfg(target_os="android")]
extern mod glut;
extern mod js;
extern mod layers;
extern mod newcss (name = "css");
@ -101,9 +104,24 @@ pub mod util;
#[cfg(not(test))]
#[start]
fn start(argc: int, argv: **u8, crate_map: *u8) -> int {
#[cfg(target_os="linux")]
#[cfg(target_os="macos")]
fn getopts() -> Opts {
opts::from_cmdline_args(os::args())
}
#[cfg(target_os="android")]
fn getopts() -> Opts {
let mut args:~[~str] = ~[];
args.push(~"servo");
let servo_url = os::getenv(~"SERVO_URL");
match servo_url {
Some(s) => { args.push(s); },
None => { fail!("No url input"); }
}
opts::from_cmdline_args(args)
}
do std::rt::start_on_main_thread(argc, argv, crate_map) {
let opts = opts::from_cmdline_args(os::args());
run(opts)
run(getopts())
}
}

View file

@ -1563,7 +1563,7 @@ for (uint32_t i = 0; i < length; ++i) {
raise TypeError("We don't support nullable enumerated return types "
"yet")
return ("""assert!((%(result)s as uint) < %(strings)s.len());
let %(resultStr)s: *JSString = JS_NewStringCopyN(cx, ptr::to_unsafe_ptr(&%(strings)s[%(result)s as u32].value[0]) as *i8, %(strings)s[%(result)s as u32].length as u64);
let %(resultStr)s: *JSString = JS_NewStringCopyN(cx, ptr::to_unsafe_ptr(&%(strings)s[%(result)s as u32].value[0]) as *i8, %(strings)s[%(result)s as u32].length as libc::size_t);
if %(resultStr)s.is_null() {
return 0;
}

View file

@ -70,7 +70,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
unsafe {
let name = str::raw::from_c_str(className);
let nchars = "[object ]".len() + name.len();
let chars: *mut jschar = cast::transmute(JS_malloc(cx, (nchars + 1) as u64 * (size_of::<jschar>() as u64)));
let chars: *mut jschar = cast::transmute(JS_malloc(cx, (nchars + 1) as libc::size_t * (size_of::<jschar>() as libc::size_t)));
if chars.is_null() {
return ptr::null();
}
@ -80,7 +80,7 @@ pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
*chars.offset(i as int) = c as jschar;
}
*chars.offset(nchars as int) = 0;
let jsstr = JS_NewUCString(cx, cast::transmute(chars), nchars as u64);
let jsstr = JS_NewUCString(cx, cast::transmute(chars), nchars as libc::size_t);
if jsstr.is_null() {
JS_free(cx, cast::transmute(chars));
}

View file

@ -37,8 +37,8 @@ use js::{JSPROP_SETTER, JSVAL_VOID, JSVAL_TRUE, JSVAL_FALSE};
use js::{JS_THIS_OBJECT, JSFUN_CONSTRUCTOR, JS_CALLEE, JSPROP_READONLY};
use js;
static TOSTRING_CLASS_RESERVED_SLOT: u64 = 0;
static TOSTRING_NAME_RESERVED_SLOT: u64 = 1;
static TOSTRING_CLASS_RESERVED_SLOT: libc::size_t = 0;
static TOSTRING_NAME_RESERVED_SLOT: libc::size_t = 1;
struct GlobalStaticData {
proxy_handlers: HashMap<uint, *libc::c_void>,

@ -0,0 +1 @@
Subproject commit d0c6dd720f90e2e8f8d8a103754195096531b531

@ -0,0 +1 @@
Subproject commit e74cfc256285a94b84c5b019714e922d37d0a286

@ -0,0 +1 @@
Subproject commit 3030c434349f39dd16d330b07f3ec6db917ea882

@ -1 +1 @@
Subproject commit c3a603bb641539bb2b7f3c159fd8ea3de045db8f
Subproject commit 3f4841a48534b167284ea04b0c2b5952fef936e7

@ -0,0 +1 @@
Subproject commit 24939d67ce465e3a44bb4adac56534c833478daf

@ -1 +1 @@
Subproject commit dfcdbc7562edb58672438f59ccfa8687cdd47e31
Subproject commit c0f176ddc0157b768d689bd1e78f56006b4db488

@ -1 +1 @@
Subproject commit 10a11900d78783655d500121d0afb2810785c022
Subproject commit c2feb563c8434319f60b2e9134e250d7bc1fe27f

@ -1 +1 @@
Subproject commit da248d3f5b3ed6d9e804c543563be8e34baf1673
Subproject commit 720128629f3395e8836e64887d2c105d94603746

@ -1 +1 @@
Subproject commit 0824ca2895668b6ac1751871d7360bc484afb930
Subproject commit 4a9d0c799d12b10cd313b07a7ed6380698429e01

@ -1 +1 @@
Subproject commit bd06cd169cf68de03438f6ab9ab87bc62243774e
Subproject commit e677e2586128acfbae7517a4916e7ea826ab3206

@ -1 +1 @@
Subproject commit f889ab32a6fc249b2a8667a7c7c1e5c24d5daf7c
Subproject commit db2cd9398c25f4d061d536e3cb53a0a3005ccb87