summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile488
-rw-r--r--Makefile.macros249
-rw-r--r--content/fetch.c50
-rw-r--r--content/fetch.h5
-rw-r--r--content/fetchers/curl.c1
-rw-r--r--content/handlers/css/hints.c47
-rw-r--r--content/handlers/html/box.h4
-rw-r--r--content/handlers/html/box_construct.c67
-rw-r--r--content/handlers/html/box_manipulate.c1
-rw-r--r--content/handlers/html/layout.c418
-rw-r--r--content/hlcache.c14
-rw-r--r--content/llcache.c186
-rw-r--r--desktop/browser_history.c11
-rw-r--r--desktop/browser_history.h11
-rw-r--r--desktop/local_history.c1
-rw-r--r--desktop/local_history_private.h38
-rw-r--r--desktop/netsurf.c6
-rw-r--r--docs/development.md6
-rw-r--r--docs/implementing-new-frontend.md413
-rw-r--r--docs/integration-testing.md9
-rw-r--r--frontends/Makefile.hts122
-rw-r--r--frontends/amiga/Makefile.tools21
-rw-r--r--frontends/amiga/iff_dr2d.c4
-rwxr-xr-xfrontends/amiga/utf8.c15
-rw-r--r--frontends/atari/Makefile.tools19
-rw-r--r--frontends/beos/Makefile.tools14
-rw-r--r--frontends/framebuffer/Makefile.tools15
-rw-r--r--frontends/gtk/Makefile10
-rw-r--r--frontends/gtk/Makefile.tools16
-rw-r--r--frontends/gtk/corewindow.c1
-rw-r--r--frontends/gtk/gui.c1347
-rw-r--r--frontends/gtk/misc.c190
-rw-r--r--frontends/gtk/misc.h24
-rw-r--r--frontends/gtk/window.c17
-rw-r--r--frontends/monkey/Makefile.tools15
-rw-r--r--frontends/monkey/main.c17
-rw-r--r--frontends/riscos/Makefile.tools52
-rw-r--r--frontends/riscos/buffer.c2
-rw-r--r--frontends/riscos/buffer.h2
-rw-r--r--frontends/riscos/corewindow.c23
-rw-r--r--frontends/riscos/filetype.c2
-rw-r--r--frontends/riscos/filetype.h3
-rw-r--r--frontends/riscos/global_history.c3
-rw-r--r--frontends/riscos/gui.c4
-rw-r--r--frontends/riscos/gui.h1
-rw-r--r--frontends/riscos/plotters.c38
-rw-r--r--frontends/riscos/window.c106
-rw-r--r--frontends/windows/Makefile.tools19
-rw-r--r--include/netsurf/bitmap.h4
-rw-r--r--include/netsurf/fetch.h8
-rw-r--r--resources/default.css4
-rw-r--r--test/corestrings.c2
-rwxr-xr-xtest/monkey_driver.py15
-rw-r--r--tools/convert_font.c6
-rw-r--r--utils/corestringlist.h2
55 files changed, 2666 insertions, 1502 deletions
diff --git a/Makefile b/Makefile
index d8e3b1664..ac38b50ea 100644
--- a/Makefile
+++ b/Makefile
@@ -12,8 +12,7 @@
#
# Look at Makefile.config for configuration options.
#
-# Tested on unix platforms (building for GTK and cross-compiling for RO) and
-# on RO (building for RO).
+# Best results obtained building on unix platforms cross compiling for others
#
# To clean, invoke as above, with the 'clean' target
#
@@ -26,100 +25,8 @@
all: all-program
-# Determine host type
-# NOTE: HOST determination on RISC OS could fail because of missing bug fixes
-# in UnixLib which only got addressed in UnixLib 5 / GCCSDK 4.
-# When you don't have 'uname' available, you will see:
-# File 'uname' not found
-# When you do and using a 'uname' compiled with a buggy UnixLib, you
-# will see the following printed on screen:
-# RISC OS
-# In both cases HOST make variable is empty and we recover from that by
-# assuming we're building on RISC OS.
-# In case you don't see anything printed (including the warning), you
-# have an up-to-date RISC OS build system. ;-)
-HOST := $(shell uname -s)
-
-# Sanitise host
-# TODO: Ideally, we want the equivalent of s/[^A-Za-z0-9]/_/g here
-HOST := $(subst .,_,$(subst -,_,$(subst /,_,$(HOST))))
-
-ifeq ($(HOST),)
- HOST := riscos
- $(warning Build platform determination failed but that's a known problem for RISC OS so we're assuming a native RISC OS build.)
-else
- ifeq ($(HOST),RISC OS)
- # Fixup uname -s returning "RISC OS"
- HOST := riscos
- endif
-endif
-ifeq ($(HOST),riscos)
- # Build happening on RO platform, default target is RO backend
- ifeq ($(TARGET),)
- TARGET := riscos
- endif
-endif
-
-ifeq ($(HOST),BeOS)
- HOST := beos
-endif
-ifeq ($(HOST),Haiku)
- # Haiku implements the BeOS API
- HOST := beos
-endif
-ifeq ($(HOST),beos)
- # Build happening on BeOS platform, default target is BeOS backend
- ifeq ($(TARGET),)
- TARGET := beos
- endif
- ifeq ($(TARGET),haiku)
- override TARGET := beos
- endif
-endif
-
-ifeq ($(HOST),AmigaOS)
- HOST := amiga
- ifeq ($(TARGET),)
- TARGET := amiga
- endif
-endif
-
-ifeq ($(HOST),FreeMiNT)
- HOST := mint
-endif
-ifeq ($(HOST),mint)
- ifeq ($(TARGET),)
- TARGET := atari
- endif
-endif
-
-ifeq ($(findstring MINGW,$(HOST)),MINGW)
- # MSYS' uname reports the likes of "MINGW32_NT-6.0"
- HOST := windows
-endif
-ifeq ($(HOST),windows)
- ifeq ($(TARGET),)
- TARGET := windows
- endif
-endif
-
-# Default target is GTK backend
-ifeq ($(TARGET),)
- TARGET := gtk3
-endif
-
-# valid values for the TARGET
-VLDTARGET := riscos gtk2 gtk3 beos amiga amigaos3 framebuffer windows atari monkey
+# default values for base variables
-# Check for valid TARGET
-ifeq ($(filter $(VLDTARGET),$(TARGET)),)
- $(error Unknown TARGET "$(TARGET)", Must be one of $(VLDTARGET))
-endif
-
-# ensure empty values for base variables
-
-# Sub target for build
-SUBTARGET=
# Resources executable target depends upon
RESOURCES=
# Messages executable target depends on
@@ -153,169 +60,11 @@ BUILD_CFLAGS = -g -W -Wall -Wundef -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wmissing-declarations -Wuninitialized \
-Wno-unused-parameter
-ifeq ($(TARGET),riscos)
- ifeq ($(HOST),riscos)
- # Build for RO on RO
- GCCSDK_INSTALL_ENV := <NSLibs$$Dir>
- CCRES := ccres
- TPLEXT :=
- MAKERUN := makerun
- SQUEEZE := squeeze
- RUNEXT :=
- CC := gcc
- CXX := g++
- EXEEXT :=
- PKG_CONFIG :=
- else
- # Cross-build for RO (either using GCCSDK 3.4.6 - AOF,
- # either using GCCSDK 4 - ELF)
- ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
- ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/env),)
- GCCSDK_INSTALL_ENV := /opt/netsurf/arm-unknown-riscos/env
- else
- GCCSDK_INSTALL_ENV := /home/riscos/env
- endif
- endif
-
- ifeq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
- ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/cross/bin),)
- GCCSDK_INSTALL_CROSSBIN := /opt/netsurf/arm-unknown-riscos/cross/bin
- else
- GCCSDK_INSTALL_CROSSBIN := /home/riscos/cross/bin
- endif
- endif
-
- CCRES := $(GCCSDK_INSTALL_CROSSBIN)/ccres
- TPLEXT := ,fec
- MAKERUN := $(GCCSDK_INSTALL_CROSSBIN)/makerun
- SQUEEZE := $(GCCSDK_INSTALL_CROSSBIN)/squeeze
- RUNEXT := ,feb
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- ifneq (,$(findstring arm-unknown-riscos-gcc,$(CC)))
- SUBTARGET := -elf
- EXEEXT := ,e1f
- ELF2AIF := $(GCCSDK_INSTALL_CROSSBIN)/elf2aif
- else
- SUBTARGET := -aof
- EXEEXT := ,ff8
- endif
- CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
- PKG_CONFIG := $(GCCSDK_INSTALL_ENV)/ro-pkg-config
- endif
-else
- ifeq ($(TARGET),beos)
- # Building for BeOS/Haiku
- #ifeq ($(HOST),beos)
- # Build for BeOS on BeOS
- GCCSDK_INSTALL_ENV := /boot/develop
- CC := gcc
- CXX := g++
- EXEEXT :=
- PKG_CONFIG := pkg-config
- #endif
- else
- ifeq ($(TARGET),windows)
- ifneq ($(HOST),windows)
- # Set Mingw defaults
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/i686-w64-mingw32/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/i686-w64-mingw32/cross/bin
-
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- WINDRES := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*windres)
-
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- else
- # Building on Windows
- CC := gcc
- PKG_CONFIG :=
- endif
- else
- ifeq ($(findstring amiga,$(TARGET)),amiga)
- ifeq ($(findstring amiga,$(HOST)),amiga)
- PKG_CONFIG := pkg-config
- else
- ifeq ($(TARGET),amigaos3)
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-unknown-amigaos/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-unknown-amigaos/cross/bin
-
- SUBTARGET = os3
- else
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/ppc-amigaos/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/ppc-amigaos/cross/bin
- endif
-
- override TARGET := amiga
-
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
-
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
- else
- ifeq ($(TARGET),atari)
- ifeq ($(HOST),atari)
- PKG_CONFIG := pkg-config
- else
- ifeq ($(HOST),mint)
- PKG_CONFIG := pkg-config
- else
- GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-atari-mint/env
- GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-atari-mint/cross/bin
-
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
-
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
- endif
- else
- ifeq ($(TARGET),monkey)
- ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
- PKG_CONFIG := pkg-config
- else
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
-
- ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
- endif
- else
- ifeq ($(TARGET),framebuffer)
- ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
- PKG_CONFIG := pkg-config
- else
- PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
- endif
-
- ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
- CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
- CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
- endif
-
- else
- # All native targets
-
- # use native package config
- PKG_CONFIG := pkg-config
-
- # gtk target processing
- ifeq ($(TARGET),gtk3)
- override TARGET := gtk
- override NETSURF_GTK_MAJOR := 3
- SUBTARGET = $(NETSURF_GTK_MAJOR)
- else
- ifeq ($(TARGET),gtk2)
- override TARGET := gtk
- override NETSURF_GTK_MAJOR := 2
- SUBTARGET = $(NETSURF_GTK_MAJOR)
- endif
- endif
- endif
- endif
- endif
- endif
- endif
- endif
-endif
+# compute HOST, TARGET and SUBTARGET
+include frontends/Makefile.hts
+
+# target specific tool overrides
+include frontends/$(TARGET)/Makefile.tools
# compiler versioning to adjust warning flags
CC_VERSION := $(shell $(CC) -dumpfullversion -dumpversion)
@@ -340,138 +89,8 @@ TOOLROOT := $(OBJROOT)/tools
CFLAGS_ENV := $(CFLAGS)
CXXFLAGS_ENV := $(CXXFLAGS)
-# A macro that conditionaly adds flags to the build when a feature is enabled.
-#
-# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
-# 2: Parameters to add to CFLAGS
-# 3: Parameters to add to LDFLAGS
-# 4: Human-readable name for the feature
-define feature_enabled
- ifeq ($$(NETSURF_USE_$(1)),YES)
- CFLAGS += $(2)
- CXXFLAGS += $(2)
- LDFLAGS += $(3)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(4) enabled (NETSURF_USE_$(1) := YES))
- endif
- else ifeq ($$(NETSURF_USE_$(1)),NO)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(4) disabled (NETSURF_USE_$(1) := NO))
- endif
- else
- $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
- $$(error NETSURF_USE_$(1) must be YES or NO)
- endif
-endef
-
-# A macro that conditionaly adds flags to the build with a uniform display.
-#
-# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
-# 2: Human-readable name for the feature
-# 3: Parameters to add to CFLAGS when enabled
-# 4: Parameters to add to LDFLAGS when enabled
-# 5: Parameters to add to CFLAGS when disabled
-# 6: Parameters to add to LDFLAGS when disabled
-define feature_switch
- ifeq ($$(NETSURF_USE_$(1)),YES)
- CFLAGS += $(3)
- CXXFLAGS += $(3)
- LDFLAGS += $(4)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(2) enabled (NETSURF_USE_$(1) := YES))
- endif
- else ifeq ($$(NETSURF_USE_$(1)),NO)
- CFLAGS += $(5)
- CXXFLAGS += $(5)
- LDFLAGS += $(6)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(2) disabled (NETSURF_USE_$(1) := NO))
- endif
- else
- $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
- $$(error NETSURF_USE_$(1) must be YES or NO)
- endif
-endef
-
-# Extend flags with appropriate values from pkg-config for enabled features
-#
-# 1: pkg-config required modules for feature
-# 2: Human-readable name for the feature
-define pkg_config_find_and_add
- ifeq ($$(PKG_CONFIG),)
- $$(error pkg-config is required to auto-detect feature availability)
- endif
-
- PKG_CONFIG_$(1)_EXISTS := $$(shell $$(PKG_CONFIG) --exists $(1) && echo yes)
-
- ifeq ($$(PKG_CONFIG_$(1)_EXISTS),yes)
- CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
- CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
- LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(1))
- ifneq ($(MAKECMDGOALS),clean)
- $$(info PKG.CNFG: $(2) ($(1)) enabled)
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info PKG.CNFG: $(2) ($(1)) failed)
- $$(error Unable to find library for: $(2) ($(1)))
- endif
- endif
-endef
-
-# Extend flags with appropriate values from pkg-config for enabled features
-#
-# 1: Feature name (ie, NETSURF_USE_RSVG -> RSVG)
-# 2: pkg-config required modules for feature
-# 3: Human-readable name for the feature
-define pkg_config_find_and_add_enabled
- ifeq ($$(PKG_CONFIG),)
- $$(error pkg-config is required to auto-detect feature availability)
- endif
-
- NETSURF_FEATURE_$(1)_AVAILABLE := $$(shell $$(PKG_CONFIG) --exists $(2) && echo yes)
- NETSURF_FEATURE_$(1)_CFLAGS ?= -DWITH_$(1)
-
- ifeq ($$(NETSURF_USE_$(1)),YES)
- ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
- CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) enabled (NETSURF_USE_$(1) := YES))
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) failed (NETSURF_USE_$(1) := YES))
- $$(error Unable to find library for: $(3) ($(2)))
- endif
- endif
- else ifeq ($$(NETSURF_USE_$(1)),AUTO)
- ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
- CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
- LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) auto-enabled (NETSURF_USE_$(1) := AUTO))
- NETSURF_USE_$(1) := YES
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) auto-disabled (NETSURF_USE_$(1) := AUTO))
- NETSURF_USE_$(1) := NO
- endif
- endif
- else ifeq ($$(NETSURF_USE_$(1)),NO)
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) disabled (NETSURF_USE_$(1) := NO))
- endif
- else
- ifneq ($(MAKECMDGOALS),clean)
- $$(info M.CONFIG: $(3) ($(2)) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
- $$(error NETSURF_USE_$(1) must be YES, NO, or AUTO)
- endif
- endif
-endef
+# library and feature building macros
+include Makefile.macros
# ----------------------------------------------------------------------------
# General flag setup
@@ -681,20 +300,6 @@ S_COMMON := \
# Message targets
# ----------------------------------------------------------------------------
-# Message splitting rule generation macro
-# 1 = Language
-define split_messages
-
-$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages $$(TOOLROOT)/split-messages
- $$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
- $$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
- $$(Q)$$(RM) $$@
- $$(Q)$$(TOOLROOT)/split-messages -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ -z $$<
-
-CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
-MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
-
-endef
# generate the message file rules
$(eval $(foreach LANG,$(MESSAGES_LANGUAGES), \
@@ -745,7 +350,7 @@ ifeq ($(TARGET),beos)
$(Q)$(BEOS_SETVER) $(EXETARGET) \
-app $(VERSION_MAJ) $(VERSION_MIN) 0 d 0 \
-short "NetSurf $(VERSION_FULL)" \
- -long "NetSurf $(VERSION_FULL) © 2003 - 2016 The NetSurf Developers"
+ -long "NetSurf $(VERSION_FULL) © 2003 - 2021 The NetSurf Developers"
$(VQ)echo " MIMESET: $(EXETARGET)"
$(Q)$(BEOS_MIMESET) $(EXETARGET)
endif
@@ -769,79 +374,6 @@ all-program: $(EXETARGET) $(POSTEXES)
.SUFFIXES:
DEPFILES :=
-# Now some macros which build the make system
-
-# 1 = Source file
-# 2 = dep filename, no prefix
-# 3 = obj filename, no prefix
-define dependency_generate_c
-DEPFILES += $(2)
-
-endef
-
-# 1 = Source file
-# 2 = dep filename, no prefix
-# 3 = obj filename, no prefix
-define dependency_generate_s
-DEPFILES += $(2)
-
-endef
-
-# 1 = Source file
-# 2 = obj filename, no prefix
-# 3 = dep filename, no prefix
-ifeq ($(CC_MAJOR),2)
-# simpler deps tracking for gcc2...
-define compile_target_c
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo " DEP: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(CC) $$(IFLAGS) $$(CFLAGS) -MM \
- $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
- > $$(DEPROOT)/$(3)
- $$(VQ)echo " COMPILE: $(1)"
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
-else
-define compile_target_c
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo " COMPILE: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) \
- -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
- -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
-endif
-
-define compile_target_cpp
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo " DEP: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(CC) $$(IFLAGS) $$(CXXFLAGS) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) -MM \
- $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
- > $$(DEPROOT)/$(3)
- $$(VQ)echo " COMPILE: $(1)"
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CXX) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) $$(IFLAGS) $$(CXXFLAGS) $(CXXFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
-
-# 1 = Source file
-# 2 = obj filename, no prefix
-# 3 = dep filename, no prefix
-define compile_target_s
-$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
- $$(VQ)echo "ASSEMBLE: $(1)"
- $$(Q)$$(RM) $$(DEPROOT)/$(3)
- $$(Q)$$(RM) $$(OBJROOT)/$(2)
- $$(Q)$$(CC) $$(ASFLAGS) -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
- -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
-
-endef
# Rules to construct dep lines for each object...
$(eval $(foreach SOURCE,$(filter %.c,$(SOURCES)), \
diff --git a/Makefile.macros b/Makefile.macros
new file mode 100644
index 000000000..9421acfa2
--- /dev/null
+++ b/Makefile.macros
@@ -0,0 +1,249 @@
+# -*- mode: makefile-gmake -*-
+##
+## Netsurf library and feature macros
+##
+
+# A macro that conditionaly adds flags to the build when a feature is enabled.
+#
+# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
+# 2: Parameters to add to CFLAGS
+# 3: Parameters to add to LDFLAGS
+# 4: Human-readable name for the feature
+define feature_enabled
+ ifeq ($$(NETSURF_USE_$(1)),YES)
+ CFLAGS += $(2)
+ CXXFLAGS += $(2)
+ LDFLAGS += $(3)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(4) enabled (NETSURF_USE_$(1) := YES))
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),NO)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(4) disabled (NETSURF_USE_$(1) := NO))
+ endif
+ else
+ $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
+ $$(error NETSURF_USE_$(1) must be YES or NO)
+ endif
+endef
+
+
+# A macro that conditionaly adds flags to the build with a uniform display.
+#
+# 1: Feature name (ie, NETSURF_USE_BMP -> BMP)
+# 2: Human-readable name for the feature
+# 3: Parameters to add to CFLAGS when enabled
+# 4: Parameters to add to LDFLAGS when enabled
+# 5: Parameters to add to CFLAGS when disabled
+# 6: Parameters to add to LDFLAGS when disabled
+define feature_switch
+ ifeq ($$(NETSURF_USE_$(1)),YES)
+ CFLAGS += $(3)
+ CXXFLAGS += $(3)
+ LDFLAGS += $(4)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(2) enabled (NETSURF_USE_$(1) := YES))
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),NO)
+ CFLAGS += $(5)
+ CXXFLAGS += $(5)
+ LDFLAGS += $(6)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(2) disabled (NETSURF_USE_$(1) := NO))
+ endif
+ else
+ $$(info M.CONFIG: $(4) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
+ $$(error NETSURF_USE_$(1) must be YES or NO)
+ endif
+endef
+
+
+# Extend flags with appropriate values from pkg-config for enabled features
+#
+# 1: pkg-config required modules for feature
+# 2: Human-readable name for the feature
+define pkg_config_find_and_add
+ ifeq ($$(PKG_CONFIG),)
+ $$(error pkg-config is required to auto-detect feature availability)
+ endif
+
+ PKG_CONFIG_$(1)_EXISTS := $$(shell $$(PKG_CONFIG) --exists $(1) && echo yes)
+
+ ifeq ($$(PKG_CONFIG_$(1)_EXISTS),yes)
+ CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
+ CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(1))
+ LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(1))
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info PKG.CNFG: $(2) ($(1)) enabled)
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info PKG.CNFG: $(2) ($(1)) failed)
+ $$(error Unable to find library for: $(2) ($(1)))
+ endif
+ endif
+endef
+
+
+# Extend flags with appropriate values from pkg-config for enabled features
+#
+# 1: Feature name (ie, NETSURF_USE_RSVG -> RSVG)
+# 2: pkg-config required modules for feature
+# 3: Human-readable name for the feature
+define pkg_config_find_and_add_enabled
+ ifeq ($$(PKG_CONFIG),)
+ $$(error pkg-config is required to auto-detect feature availability)
+ endif
+
+ NETSURF_FEATURE_$(1)_AVAILABLE := $$(shell $$(PKG_CONFIG) --exists $(2) && echo yes)
+ NETSURF_FEATURE_$(1)_CFLAGS ?= -DWITH_$(1)
+
+ ifeq ($$(NETSURF_USE_$(1)),YES)
+ ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
+ CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) enabled (NETSURF_USE_$(1) := YES))
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) failed (NETSURF_USE_$(1) := YES))
+ $$(error Unable to find library for: $(3) ($(2)))
+ endif
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),AUTO)
+ ifeq ($$(NETSURF_FEATURE_$(1)_AVAILABLE),yes)
+ CFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ CXXFLAGS += $$(shell $$(PKG_CONFIG) --cflags $(2)) $$(NETSURF_FEATURE_$(1)_CFLAGS)
+ LDFLAGS += $$(shell $$(PKG_CONFIG) --libs $(2)) $$(NETSURF_FEATURE_$(1)_LDFLAGS)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) auto-enabled (NETSURF_USE_$(1) := AUTO))
+ NETSURF_USE_$(1) := YES
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) auto-disabled (NETSURF_USE_$(1) := AUTO))
+ NETSURF_USE_$(1) := NO
+ endif
+ endif
+ else ifeq ($$(NETSURF_USE_$(1)),NO)
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) disabled (NETSURF_USE_$(1) := NO))
+ endif
+ else
+ ifneq ($(MAKECMDGOALS),clean)
+ $$(info M.CONFIG: $(3) ($(2)) error (NETSURF_USE_$(1) := $$(NETSURF_USE_$(1))))
+ $$(error NETSURF_USE_$(1) must be YES, NO, or AUTO)
+ endif
+ endif
+endef
+
+
+# Message splitting rule generation macro
+#
+# 1 = Language
+define split_messages
+
+$$(MESSAGES_TARGET)/$(1)/Messages: resources/FatMessages $$(TOOLROOT)/split-messages
+ $$(VQ)echo "MSGSPLIT: Language: $(1) Filter: $$(MESSAGES_FILTER)"
+ $$(Q)$$(MKDIR) -p $$(MESSAGES_TARGET)/$(1)
+ $$(Q)$$(RM) $$@
+ $$(Q)$$(TOOLROOT)/split-messages -l $(1) -p $$(MESSAGES_FILTER) -f messages -o $$@ -z $$<
+
+CLEAN_MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
+MESSAGES += $$(MESSAGES_TARGET)/$(1)/Messages
+
+endef
+
+
+# Now some macros which build the make system
+
+# Extend dependancy files for c source files
+#
+# 1 = Source file
+# 2 = dep filename, no prefix
+# 3 = obj filename, no prefix
+define dependency_generate_c
+DEPFILES += $(2)
+
+endef
+
+
+# Extend dependancy files for s source files
+#
+# 1 = Source file
+# 2 = dep filename, no prefix
+# 3 = obj filename, no prefix
+define dependency_generate_s
+DEPFILES += $(2)
+
+endef
+
+
+# Rule generator to compile c files
+#
+# 1 = Source file
+# 2 = obj filename, no prefix
+# 3 = dep filename, no prefix
+ifeq ($(CC_MAJOR),2)
+# simpler deps tracking for gcc2...
+define compile_target_c
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo " DEP: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(CC) $$(IFLAGS) $$(CFLAGS) -MM \
+ $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
+ > $$(DEPROOT)/$(3)
+ $$(VQ)echo " COMPILE: $(1)"
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
+else
+define compile_target_c
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo " COMPILE: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CC) $$(COMMON_WARNFLAGS) $$(CWARNFLAGS) $$(IFLAGS) $$(CFLAGS) $(CFLAGS_ENV) \
+ -MMD -MP -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
+ -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
+endif
+
+
+# Rule generator to compile cpp files
+#
+# 1 = Source file
+# 2 = obj filename, no prefix
+# 3 = dep filename, no prefix
+define compile_target_cpp
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo " DEP: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(CC) $$(IFLAGS) $$(CXXFLAGS) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) -MM \
+ $(1) | sed 's,^.*:,$$(DEPROOT)/$(3) $$(OBJROOT)/$(2):,' \
+ > $$(DEPROOT)/$(3)
+ $$(VQ)echo " COMPILE: $(1)"
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CXX) $$(COMMON_WARNFLAGS) $$(CXXWARNFLAGS) $$(IFLAGS) $$(CXXFLAGS) $(CXXFLAGS_ENV) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
+
+
+# Rule generator to compile s files
+#
+# 1 = Source file
+# 2 = obj filename, no prefix
+# 3 = dep filename, no prefix
+define compile_target_s
+$$(OBJROOT)/$(2): $(1) $$(OBJROOT)/created $$(DEPROOT)/created
+ $$(VQ)echo "ASSEMBLE: $(1)"
+ $$(Q)$$(RM) $$(DEPROOT)/$(3)
+ $$(Q)$$(RM) $$(OBJROOT)/$(2)
+ $$(Q)$$(CC) $$(ASFLAGS) -MMD -MT '$$(DEPROOT)/$(3) $$(OBJROOT)/$(2)' \
+ -MF $$(DEPROOT)/$(3) -o $$(OBJROOT)/$(2) -c $(1)
+
+endef
diff --git a/content/fetch.c b/content/fetch.c
index 533f75e87..1fcc3f996 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -90,7 +90,6 @@ struct fetch {
fetch_callback callback;/**< Callback function. */
nsurl *url; /**< URL. */
nsurl *referer; /**< Referer URL. */
- bool send_referer; /**< Valid to send the referer */
bool verifiable; /**< Transaction is verifiable */
void *p; /**< Private data for callback. */
lwc_string *host; /**< Host part of URL, interned */
@@ -461,7 +460,6 @@ fetch_start(nsurl *url,
{
struct fetch *fetch;
lwc_string *scheme;
- bool match;
fetch = calloc(1, sizeof (*fetch));
if (fetch == NULL) {
@@ -474,8 +472,8 @@ fetch_start(nsurl *url,
/* try and obtain a fetcher for this scheme */
fetch->fetcherd = get_fetcher_for_scheme(scheme);
+ lwc_string_unref(scheme);
if (fetch->fetcherd == -1) {
- lwc_string_unref(scheme);
free(fetch);
return NSERROR_NO_FETCH_HANDLER;
}
@@ -490,48 +488,9 @@ fetch_start(nsurl *url,
fetch->host = nsurl_get_component(url, NSURL_HOST);
if (referer != NULL) {
- lwc_string *ref_scheme;
fetch->referer = nsurl_ref(referer);
-
- ref_scheme = nsurl_get_component(referer, NSURL_SCHEME);
- /* Not a problem if referer has no scheme */
-
- /* Determine whether to send the Referer header */
- if (nsoption_bool(send_referer) && ref_scheme != NULL) {
- /* User permits us to send the header
- * Only send it if:
- * 1) The fetch and referer schemes match
- * or 2) The fetch is https and the referer is http
- *
- * This ensures that referer information is only sent
- * across schemes in the special case of an https
- * request from a page served over http. The inverse
- * (https -> http) should not send the referer (15.1.3)
- */
- bool match1;
- bool match2;
- if (lwc_string_isequal(scheme, ref_scheme,
- &match) != lwc_error_ok) {
- match = false;
- }
- if (lwc_string_isequal(scheme, corestring_lwc_https,
- &match1) != lwc_error_ok) {
- match1 = false;
- }
- if (lwc_string_isequal(ref_scheme, corestring_lwc_http,
- &match2) != lwc_error_ok) {
- match2= false;
- }
- if (match == true || (match1 == true && match2 == true))
- fetch->send_referer = true;
- }
- if (ref_scheme != NULL)
- lwc_string_unref(ref_scheme);
}
- /* these aren't needed past here */
- lwc_string_unref(scheme);
-
/* try and set up the fetch */
fetch->fetcher_handle = fetchers[fetch->fetcherd].ops.setup(fetch, url,
only_2xx, downgrade_tls,
@@ -839,13 +798,6 @@ void fetch_set_http_code(struct fetch *fetch, long http_code)
fetch->http_code = http_code;
}
-/* exported interface documented in content/fetch.h */
-const char *fetch_get_referer_to_send(struct fetch *fetch)
-{
- if (fetch->send_referer)
- return nsurl_access(fetch->referer);
- return NULL;
-}
/* exported interface documented in content/fetch.h */
void fetch_set_cookie(struct fetch *fetch, const char *data)
diff --git a/content/fetch.h b/content/fetch.h
index fdb3bfbd8..843fec96e 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -230,11 +230,6 @@ void fetch_free(struct fetch *f);
void fetch_set_http_code(struct fetch *fetch, long http_code);
/**
- * get the referer from the fetch
- */
-const char *fetch_get_referer_to_send(struct fetch *fetch);
-
-/**
* set cookie data on a fetch
*/
void fetch_set_cookie(struct fetch *fetch, const char *data);
diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c
index f9cafae69..d36f44c09 100644
--- a/content/fetchers/curl.c
+++ b/content/fetchers/curl.c
@@ -889,7 +889,6 @@ static CURLcode fetch_curl_set_options(struct curl_fetch_info *f)
SETOPT(CURLOPT_WRITEDATA, f);
SETOPT(CURLOPT_WRITEHEADER, f);
SETOPT(CURLOPT_PROGRESSDATA, f);
- SETOPT(CURLOPT_REFERER, fetch_get_referer_to_send(f->fetch_handle));
SETOPT(CURLOPT_HTTPHEADER, f->headers);
if (f->post_urlenc) {
SETOPT(CURLOPT_HTTPPOST, NULL);
diff --git a/content/handlers/css/hints.c b/content/handlers/css/hints.c
index 9748030b7..defeae10a 100644
--- a/content/handlers/css/hints.c
+++ b/content/handlers/css/hints.c
@@ -1579,6 +1579,50 @@ static void css_hint_white_space_nowrap(
}
}
+static void css_hint_list(
+ nscss_select_ctx *ctx,
+ dom_node *node)
+{
+ struct css_hint *hint = &(hint_ctx.hints[hint_ctx.len]);
+ dom_exception err;
+ dom_string *attr;
+
+ err = dom_element_get_attribute(node, corestring_dom_type, &attr);
+ if (err == DOM_NO_ERR && attr != NULL) {
+ const char *attr_str = dom_string_data(attr);
+ size_t attr_len = dom_string_byte_length(attr);
+ enum css_list_style_type_e type = CSS_LIST_STYLE_TYPE_INHERIT;
+
+ if (attr_len == 1) {
+ switch (attr_str[0]) {
+ case 'a':
+ type = CSS_LIST_STYLE_TYPE_LOWER_ALPHA;
+ break;
+ case 'A':
+ type = CSS_LIST_STYLE_TYPE_UPPER_ALPHA;
+ break;
+ case 'i':
+ type = CSS_LIST_STYLE_TYPE_LOWER_ROMAN;
+ break;
+ case 'I':
+ type = CSS_LIST_STYLE_TYPE_UPPER_ROMAN;
+ break;
+ case '1':
+ type = CSS_LIST_STYLE_TYPE_DECIMAL;
+ break;
+ }
+ }
+
+ if (type != CSS_LIST_STYLE_TYPE_INHERIT) {
+ hint->prop = CSS_PROP_LIST_STYLE_TYPE;
+ hint->status = type;
+ css_hint_advance(&hint);
+ }
+
+ dom_string_unref(attr);
+ }
+}
+
/* Exported function, documeted in css/hints.h */
css_error node_presentational_hint(void *pw, void *node,
@@ -1671,6 +1715,9 @@ css_error node_presentational_hint(void *pw, void *node,
case DOM_HTML_ELEMENT_TYPE_CANVAS:
css_hint_height_width_canvas(pw, node);
break;
+ case DOM_HTML_ELEMENT_TYPE_OL:
+ css_hint_list(pw, node);
+ break;
default:
break;
}
diff --git a/content/handlers/html/box.h b/content/handlers/html/box.h
index d0df73568..1059556e6 100644
--- a/content/handlers/html/box.h
+++ b/content/handlers/html/box.h
@@ -404,6 +404,10 @@ struct box {
*/
struct column *col;
+ /**
+ * List item value.
+ */
+ int list_value;
/**
* List marker box if this is a list-item, or NULL.
diff --git a/content/handlers/html/box_construct.c b/content/handlers/html/box_construct.c
index e2eaf8ca6..7bfc35e44 100644
--- a/content/handlers/html/box_construct.c
+++ b/content/handlers/html/box_construct.c
@@ -366,6 +366,7 @@ box_construct_marker(struct box *box,
{
lwc_string *image_uri;
struct box *marker;
+ enum css_list_style_type_e list_style_type;
marker = box_create(NULL, box->style, false, NULL, NULL, title,
NULL, ctx->bctx);
@@ -374,81 +375,33 @@ box_construct_marker(struct box *box,
marker->type = BOX_BLOCK;
+ list_style_type = css_computed_list_style_type(box->style);
+
/** \todo marker content (list-style-type) */
- switch (css_computed_list_style_type(box->style)) {
+ switch (list_style_type) {
case CSS_LIST_STYLE_TYPE_DISC:
/* 2022 BULLET */
marker->text = (char *) "\342\200\242";
marker->length = 3;
break;
+
case CSS_LIST_STYLE_TYPE_CIRCLE:
/* 25CB WHITE CIRCLE */
marker->text = (char *) "\342\227\213";
marker->length = 3;
break;
+
case CSS_LIST_STYLE_TYPE_SQUARE:
/* 25AA BLACK SMALL SQUARE */
marker->text = (char *) "\342\226\252";
marker->length = 3;
break;
- case CSS_LIST_STYLE_TYPE_DECIMAL:
- case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
- case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
- case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
- case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
- default:
- if (parent->last) {
- struct box *last = parent->last;
-
- /* Drill down into last child of parent
- * to find the list marker (if any)
- *
- * Floated list boxes end up as:
- *
- * parent
- * BOX_INLINE_CONTAINER
- * BOX_FLOAT_{LEFT,RIGHT}
- * BOX_BLOCK <-- list box
- * ...
- */
- while (last != NULL && last->list_marker == NULL) {
- struct box *last_inner = last;
-
- while (last_inner != NULL) {
- if (last_inner->list_marker != NULL)
- break;
- if (last_inner->type ==
- BOX_INLINE_CONTAINER ||
- last_inner->type ==
- BOX_FLOAT_LEFT ||
- last_inner->type ==
- BOX_FLOAT_RIGHT) {
- last_inner = last_inner->last;
- } else {
- last_inner = NULL;
- }
- }
- if (last_inner != NULL) {
- last = last_inner;
- } else {
- last = last->prev;
- }
- }
- if (last && last->list_marker) {
- marker->rows = last->list_marker->rows + 1;
- }
- }
-
- marker->text = talloc_array(ctx->bctx, char, 20);
- if (marker->text == NULL)
- return false;
-
- snprintf(marker->text, 20, "%u.", marker->rows);
- marker->length = strlen(marker->text);
- break;
+ default:
+ /* Numerical list counters get handled in layout. */
+ /* Fall through. */
case CSS_LIST_STYLE_TYPE_NONE:
- marker->text = 0;
+ marker->text = NULL;
marker->length = 0;
break;
}
diff --git a/content/handlers/html/box_manipulate.c b/content/handlers/html/box_manipulate.c
index d23091b7c..8073a7fd1 100644
--- a/content/handlers/html/box_manipulate.c
+++ b/content/handlers/html/box_manipulate.c
@@ -143,6 +143,7 @@ box_create(css_select_results *styles,
box->float_container = NULL;
box->next_float = NULL;
box->cached_place_below_level = 0;
+ box->list_value = 1;
box->list_marker = NULL;
box->col = NULL;
box->gadget = NULL;
diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c
index ddf1d1632..c8c0127ad 100644
--- a/content/handlers/html/layout.c
+++ b/content/handlers/html/layout.c
@@ -47,6 +47,7 @@
#include "utils/talloc.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
+#include "utils/corestrings.h"
#include "utils/nsurl.h"
#include "netsurf/inttypes.h"
#include "netsurf/content.h"
@@ -4410,36 +4411,426 @@ layout_block_context(struct box *block,
return true;
}
+/**
+ * Get a dom node's element tag type.
+ *
+ * \param[in] node Node to get tag type of.
+ * \param[in] type Returns element tag type on success.
+ * \return true if on success, false otherwise.
+ */
+static bool
+layout__get_element_tag(
+ const dom_node *node,
+ dom_html_element_type *type)
+{
+ dom_html_element_type element_type;
+ dom_node_type node_type;
+ dom_exception exc;
+
+ exc = dom_node_get_node_type(node, &node_type);
+ if (exc != DOM_NO_ERR ||
+ node_type != DOM_ELEMENT_NODE) {
+ return false;
+ }
+
+ exc = dom_html_element_get_tag_type(node, &element_type);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ *type = element_type;
+ return true;
+}
+
+
+/**
+ * Check a node's tag type.
+ *
+ * \param[in] node Node to check tag type of.
+ * \param[in] type Tag type to test for.
+ * \return true if if node has given type, false otherwise.
+ */
+static inline bool
+layout__check_element_type(
+ const dom_node *node,
+ dom_html_element_type type)
+{
+ dom_html_element_type element_type;
+
+ if (!layout__get_element_tag(node, &element_type)) {
+ return false;
+ }
+
+ return element_type == type;
+}
+
+
+/**
+ * Helper to get attribute value from a LI node.
+ *
+ * \param[in] li_node DOM node for the LI element;
+ * \param[out] value_out Returns the value on success.
+ * \return true if node has value, otherwise false.
+ */
+static bool
+layout__get_li_value(dom_node *li_node, dom_long *value_out)
+{
+ dom_exception exc;
+ dom_long value;
+ bool has_value;
+
+ /** \todo
+ * dom_html_li_element_get_value() is rubbish and we can't tell
+ * a lack of value attribute or invalid value from a perfectly
+ * valid '-1'.
+ *
+ * This helps for the common case of no value. However we should
+ * fix libdom to have some kind of sane interface to get numerical
+ * attributes.
+ */
+ exc = dom_element_has_attribute(li_node,
+ corestring_dom_value,
+ &has_value);
+ if (exc != DOM_NO_ERR || has_value == false) {
+ return false;
+ }
+
+ exc = dom_html_li_element_get_value(
+ (dom_html_li_element *)li_node,
+ &value);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ *value_out = value;
+ return true;
+}
+
+
+/**
+ * Helper to get start attribute value from a OL node.
+ *
+ * \param[in] ol_node DOM node for the OL element;
+ * \param[out] start_out Returns the value on success.
+ * \return true if node has value, otherwise false.
+ */
+static bool
+layout__get_ol_start(dom_node *ol_node, dom_long *start_out)
+{
+ dom_exception exc;
+ dom_long start;
+ bool has_start;
+
+ /** \todo
+ * see layout__get_li_value().
+ */
+ exc = dom_element_has_attribute(ol_node,
+ corestring_dom_start,
+ &has_start);
+ if (exc != DOM_NO_ERR || has_start == false) {
+ return false;
+ }
+
+ exc = dom_html_olist_element_get_start(
+ (dom_html_olist_element *)ol_node,
+ &start);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ *start_out = start;
+ return true;
+}
+
+
+/**
+ * Helper to get reversed attribute value from a OL node.
+ *
+ * \param[in] ol_node DOM node for the OL element;
+ * \return true if node has reversed, otherwise false.
+ */
+static bool
+layout__get_ol_reversed(dom_node *ol_node)
+{
+ dom_exception exc;
+ bool has_reversed;
+
+ exc = dom_element_has_attribute(ol_node,
+ corestring_dom_reversed,
+ &has_reversed);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ return has_reversed;
+}
+
+
+/**
+ * Get the number of list items for a list owner.
+ *
+ * \param[in] list_owner DOM node to count list items for.
+ * \param[in] count_out Returns list item count on success.
+ * \return true on success, otherwise false.
+ */
+static bool
+layout__get_list_item_count(
+ dom_node *list_owner, int *count_out)
+{
+ dom_html_element_type tag_type;
+ dom_exception exc;
+ dom_node *child;
+ int count;
+
+ if (list_owner == NULL) {
+ return false;
+ }
+
+ if (!layout__get_element_tag(list_owner, &tag_type)) {
+ return false;
+ }
+
+ if (tag_type != DOM_HTML_ELEMENT_TYPE_OL &&
+ tag_type != DOM_HTML_ELEMENT_TYPE_UL) {
+ return false;
+ }
+
+ exc = dom_node_get_first_child(list_owner, &child);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ count = 0;
+ while (child != NULL) {
+ dom_node *temp_node;
+
+ if (layout__check_element_type(child,
+ DOM_HTML_ELEMENT_TYPE_LI)) {
+ struct box *child_box;
+ if (dom_node_get_user_data(child,
+ corestring_dom___ns_key_box_node_data,
+ &child_box) != DOM_NO_ERR) {
+ dom_node_unref(child);
+ return false;
+ }
+
+ if (child_box != NULL &&
+ child_box->list_marker != NULL) {
+ count++;
+ }
+ }
+
+ exc = dom_node_get_next_sibling(child, &temp_node);
+ dom_node_unref(child);
+ if (exc != DOM_NO_ERR) {
+ return false;
+ }
+
+ child = temp_node;
+ }
+
+ *count_out = count;
+ return true;
+}
+
+
+/**
+ * Handle list item counting, if this is a list owner box.
+ *
+ * \param[in] box Box to do list item counting for.
+ */
+static void
+layout__ordered_list_count(
+ struct box *box)
+{
+ dom_html_element_type tag_type;
+ dom_exception exc;
+ dom_node *child;
+ int step = 1;
+ int next;
+
+ if (box->node == NULL) {
+ return;
+ }
+
+ if (!layout__get_element_tag(box->node, &tag_type)) {
+ return;
+ }
+
+ if (tag_type != DOM_HTML_ELEMENT_TYPE_OL &&
+ tag_type != DOM_HTML_ELEMENT_TYPE_UL) {
+ return;
+ }
+
+ next = 1;
+ if (tag_type == DOM_HTML_ELEMENT_TYPE_OL) {
+ bool have_start = layout__get_ol_start(box->node, &next);
+ bool have_reversed = layout__get_ol_reversed(box->node);
+
+ if (have_reversed) {
+ step = -1;
+ }
+
+ if (!have_start && have_reversed) {
+ layout__get_list_item_count(box->node, &next);
+ }
+ }
+
+ exc = dom_node_get_first_child(box->node, &child);
+ if (exc != DOM_NO_ERR) {
+ return;
+ }
+
+ while (child != NULL) {
+ dom_node *temp_node;
+
+ if (layout__check_element_type(child,
+ DOM_HTML_ELEMENT_TYPE_LI)) {
+ struct box *child_box;
+
+ if (dom_node_get_user_data(child,
+ corestring_dom___ns_key_box_node_data,
+ &child_box) != DOM_NO_ERR) {
+ dom_node_unref(child);
+ return;
+ }
+
+ if (child_box != NULL &&
+ child_box->list_marker != NULL) {
+ dom_long value;
+ struct box *marker = child_box->list_marker;
+ if (layout__get_li_value(child, &value)) {
+ marker->list_value = value;
+ next = marker->list_value;
+ } else {
+ marker->list_value = next;
+ }
+ next += step;
+ }
+ }
+
+ exc = dom_node_get_next_sibling(child, &temp_node);
+ dom_node_unref(child);
+ if (exc != DOM_NO_ERR) {
+ return;
+ }
+
+ child = temp_node;
+ }
+}
+
+/**
+ * Set up the marker text for a numerical list item.
+ *
+ * \param[in] content The HTML content.
+ * \param[in] box The list item's main box.
+ */
+static void
+layout__set_numerical_marker_text(
+ const html_content *content,
+ struct box *box)
+{
+ struct box *marker = box->list_marker;
+ size_t counter_len;
+ css_error css_res;
+ enum {
+ /**
+ * initial length of a list marker buffer
+ *
+ * enough for 9,999,999,999,999,999,999 in decimal
+ * or five characters for 4-byte UTF-8.
+ */
+ LIST_MARKER_SIZE = 20,
+ };
+
+ marker->text = talloc_array(content->bctx, char, LIST_MARKER_SIZE);
+ if (marker->text == NULL) {
+ return;
+ }
+
+ css_res = css_computed_format_list_style(box->style, marker->list_value,
+ marker->text, LIST_MARKER_SIZE, &counter_len);
+ if (css_res == CSS_OK) {
+ if (counter_len > LIST_MARKER_SIZE) {
+ /* Use computed size as marker did not fit in
+ * default allocation. */
+ marker->text = talloc_realloc(content->bctx,
+ marker->text,
+ char,
+ counter_len);
+ if (marker->text == NULL) {
+ return;
+ }
+ css_computed_format_list_style(box->style,
+ marker->list_value, marker->text,
+ counter_len, &counter_len);
+ }
+ marker->length = counter_len;
+ }
+}
+
+/**
+ * Find out if box's style represents a numerical list style type.
+ *
+ * \param[in] b Box with style to test.
+ * \return true if box has numerical list style type, false otherwise.
+ */
+static bool
+layout__list_item_is_numerical(
+ const struct box *b)
+{
+ enum css_list_style_type_e t = css_computed_list_style_type(b->style);
+
+ switch (t) {
+ case CSS_LIST_STYLE_TYPE_DISC: /* Fall through. */
+ case CSS_LIST_STYLE_TYPE_CIRCLE: /* Fall through. */
+ case CSS_LIST_STYLE_TYPE_SQUARE: /* Fall through. */
+ case CSS_LIST_STYLE_TYPE_NONE:
+ return false;
+
+ default:
+ return true;
+ }
+}
/**
* Layout list markers.
*/
static void
-layout_lists(struct box *box,
- const struct gui_layout_table *font_func,
- const nscss_len_ctx *len_ctx)
+layout_lists(const html_content *content, struct box *box)
{
struct box *child;
- struct box *marker;
- plot_font_style_t fstyle;
+
+ layout__ordered_list_count(box);
for (child = box->children; child; child = child->next) {
if (child->list_marker) {
- marker = child->list_marker;
+ struct box *marker = child->list_marker;
+
+ if (layout__list_item_is_numerical(child)) {
+ if (marker->text == NULL) {
+ layout__set_numerical_marker_text(
+ content, child);
+ }
+ }
if (marker->object) {
marker->width =
content_get_width(marker->object);
marker->x = -marker->width;
marker->height =
content_get_height(marker->object);
- marker->y = (line_height(len_ctx,
+ marker->y = (line_height(
+ &content->len_ctx,
marker->style) -
marker->height) / 2;
} else if (marker->text) {
if (marker->width == UNKNOWN_WIDTH) {
- font_plot_style_from_css(len_ctx,
- marker->style, &fstyle);
- font_func->width(&fstyle,
+ plot_font_style_t fstyle;
+ font_plot_style_from_css(
+ &content->len_ctx,
+ marker->style,
+ &fstyle);
+ content->font_func->width(&fstyle,
marker->text,
marker->length,
&marker->width);
@@ -4447,7 +4838,8 @@ layout_lists(struct box *box,
}
marker->x = -marker->width;
marker->y = 0;
- marker->height = line_height(len_ctx,
+ marker->height = line_height(
+ &content->len_ctx,
marker->style);
} else {
marker->x = 0;
@@ -4458,7 +4850,7 @@ layout_lists(struct box *box,
/* Gap between marker and content */
marker->x -= 4;
}
- layout_lists(child, font_func, len_ctx);
+ layout_lists(content, child);
}
}
@@ -5436,7 +5828,7 @@ bool layout_document(html_content *content, int width, int height)
doc->children->margin[BOTTOM]);
}
- layout_lists(doc, font_func, &content->len_ctx);
+ layout_lists(content, doc);
layout_position_absolute(doc, doc, 0, 0, content);
layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
diff --git a/content/hlcache.c b/content/hlcache.c
index 2e15edd56..d860015a5 100644
--- a/content/hlcache.c
+++ b/content/hlcache.c
@@ -673,11 +673,15 @@ void hlcache_finalise(void)
}
/* See hlcache.h for documentation */
-nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags,
- nsurl *referer, llcache_post_data *post,
- hlcache_handle_callback cb, void *pw,
- hlcache_child_context *child,
- content_type accepted_types, hlcache_handle **result)
+nserror
+hlcache_handle_retrieve(nsurl *url,
+ uint32_t flags,
+ nsurl *referer,
+ llcache_post_data *post,
+ hlcache_handle_callback cb, void *pw,
+ hlcache_child_context *child,
+ content_type accepted_types,
+ hlcache_handle **result)
{
hlcache_retrieval_ctx *ctx;
nserror error;
diff --git a/content/llcache.c b/content/llcache.c
index c1ddea54c..81e08383c 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -47,6 +47,7 @@
#include "utils/utils.h"
#include "utils/time.h"
#include "utils/http.h"
+#include "utils/nsoption.h"
#include "netsurf/misc.h"
#include "desktop/gui_internal.h"
@@ -807,6 +808,87 @@ static nserror llcache_fetch_process_header(llcache_object *object,
}
/**
+ * construct a Referer header appropriate for the request
+ *
+ * \param url The url being navigated to
+ * \param referer The referring url
+ * \param header_out A pointer to receive the header. The buffer must
+ * be freed by the caller.
+ * \return NSERROR_OK and \a header_out updated on success else error code
+ */
+static nserror get_referer_header(nsurl *url, nsurl *referer, char **header_out)
+{
+ nserror res = NSERROR_INVALID;
+ lwc_string *ref_scheme;
+ lwc_string *scheme;
+ bool match;
+ bool match1;
+ bool match2;
+ char *header;
+
+ /* Determine whether to send the Referer header */
+ if (!nsoption_bool(send_referer)) {
+ return NSERROR_INVALID;
+ }
+
+ scheme = nsurl_get_component(url, NSURL_SCHEME);
+ if (scheme == NULL) {
+ return NSERROR_BAD_URL;
+ }
+
+ ref_scheme = nsurl_get_component(referer, NSURL_SCHEME);
+ if (ref_scheme == NULL) {
+ /* referer has no scheme so no header */
+ lwc_string_unref(scheme);
+ return NSERROR_INVALID;
+ }
+
+ /* User permits us to send the header
+ * Only send it if:
+ * 1) The fetch and referer schemes match
+ * or 2) The fetch is https and the referer is http
+ *
+ * This ensures that referer information is only sent
+ * across schemes in the special case of an https
+ * request from a page served over http. The inverse
+ * (https -> http) should not send the referer (15.1.3)
+ */
+ if (lwc_string_isequal(scheme, ref_scheme,
+ &match) != lwc_error_ok) {
+ match = false;
+ }
+ if (lwc_string_isequal(scheme, corestring_lwc_https,
+ &match1) != lwc_error_ok) {
+ match1 = false;
+ }
+ if (lwc_string_isequal(ref_scheme, corestring_lwc_http,
+ &match2) != lwc_error_ok) {
+ match2 = false;
+ }
+ if (match == true || (match1 == true && match2 == true)) {
+ const size_t len = SLEN("Referer: ") +
+ nsurl_length(referer) + 1;
+
+ header = malloc(len);
+ if (header == NULL) {
+ res = NSERROR_NOMEM;
+ } else {
+ snprintf(header, len, "Referer: %s",
+ nsurl_access(referer));
+
+ *header_out = header;
+ res = NSERROR_OK;
+ }
+ }
+
+
+ lwc_string_unref(scheme);
+ lwc_string_unref(ref_scheme);
+
+ return res;
+}
+
+/**
* (Re)fetch an object
*
* Sets up headers and attempts to start an actual fetch from the
@@ -834,12 +916,13 @@ static nserror llcache_object_refetch(llcache_object *object)
}
}
- /* Generate cache-control headers */
- headers = malloc(3 * sizeof(char *));
+ /* Generate headers */
+ headers = malloc(4 * sizeof(char *));
if (headers == NULL) {
return NSERROR_NOMEM;
}
+ /* cache-control header for etag */
if (object->cache.etag != NULL) {
const size_t len = SLEN("If-None-Match: ") +
strlen(object->cache.etag) + 1;
@@ -856,6 +939,7 @@ static nserror llcache_object_refetch(llcache_object *object)
header_idx++;
}
+ /* cache-control header for modification time */
if (object->cache.last_modified != 0) {
/* Maximum length of an RFC 1123 date is 29 bytes */
const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
@@ -873,6 +957,15 @@ static nserror llcache_object_refetch(llcache_object *object)
header_idx++;
}
+
+ /* Referer header */
+ if (object->fetch.referer != NULL) {
+ if (get_referer_header(object->url,
+ object->fetch.referer,
+ &headers[header_idx]) == NSERROR_OK) {
+ header_idx++;
+ }
+ }
headers[header_idx] = NULL;
/* Reset cache control data */
@@ -3571,6 +3664,46 @@ total_object_size(llcache_object *object)
return tot;
}
+/**
+ * Catch up the cache users with state changes from fetchers.
+ *
+ * \param ignored We ignore this because all our state comes from llcache.
+ */
+static void llcache_catch_up_all_users(void *ignored)
+{
+ llcache_object *object;
+
+ /* Assume after this we'll be all caught up. If any user of a handle
+ * defers then we'll invalidate all_caught_up and reschedule via
+ * llcache_users_not_caught_up()
+ */
+ llcache->all_caught_up = true;
+
+ /* Catch new users up with state of objects */
+ for (object = llcache->cached_objects; object != NULL;
+ object = object->next) {
+ llcache_object_notify_users(object);
+ }
+
+ for (object = llcache->uncached_objects; object != NULL;
+ object = object->next) {
+ llcache_object_notify_users(object);
+ }
+}
+
+/**
+ * Ask for ::llcache_catch_up_all_users to be scheduled ASAP to pump the
+ * user state machines.
+ */
+static void llcache_users_not_caught_up(void)
+{
+ if (llcache->all_caught_up) {
+ llcache->all_caught_up = false;
+ guit->misc->schedule(0, llcache_catch_up_all_users, NULL);
+ }
+}
+
+
/******************************************************************************
* Public API *
******************************************************************************/
@@ -3843,51 +3976,16 @@ void llcache_finalise(void)
llcache = NULL;
}
-/**
- * Catch up the cache users with state changes from fetchers.
- *
- * \param ignored We ignore this because all our state comes from llcache.
- */
-static void llcache_catch_up_all_users(void *ignored)
-{
- llcache_object *object;
-
- /* Assume after this we'll be all caught up. If any user of a handle
- * defers then we'll invalidate all_caught_up and reschedule via
- * llcache_users_not_caught_up()
- */
- llcache->all_caught_up = true;
-
- /* Catch new users up with state of objects */
- for (object = llcache->cached_objects; object != NULL;
- object = object->next) {
- llcache_object_notify_users(object);
- }
-
- for (object = llcache->uncached_objects; object != NULL;
- object = object->next) {
- llcache_object_notify_users(object);
- }
-}
-
-/**
- * Ask for ::llcache_catch_up_all_users to be scheduled ASAP to pump the
- * user state machines.
- */
-static void llcache_users_not_caught_up(void)
-{
- if (llcache->all_caught_up) {
- llcache->all_caught_up = false;
- guit->misc->schedule(0, llcache_catch_up_all_users, NULL);
- }
-}
/* Exported interface documented in content/llcache.h */
-nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
- nsurl *referer, const llcache_post_data *post,
- llcache_handle_callback cb, void *pw,
- llcache_handle **result)
+nserror
+llcache_handle_retrieve(nsurl *url,
+ uint32_t flags,
+ nsurl *referer,
+ const llcache_post_data *post,
+ llcache_handle_callback cb, void *pw,
+ llcache_handle **result)
{
nserror error;
llcache_object_user *user;
diff --git a/desktop/browser_history.c b/desktop/browser_history.c
index 5b44670c1..2fbc80f89 100644
--- a/desktop/browser_history.c
+++ b/desktop/browser_history.c
@@ -41,6 +41,7 @@
#include "desktop/gui_internal.h"
#include "desktop/browser_private.h"
+#include "desktop/local_history_private.h"
#include "desktop/browser_history.h"
/**
@@ -434,9 +435,7 @@ nserror browser_window_history_update(struct browser_window *bw,
history = bw->history;
- if (!history ||
- !history->current ||
- !history->current->page.bitmap) {
+ if ((history == NULL) || (history->current == NULL)) {
return NSERROR_INVALID;
}
@@ -455,7 +454,7 @@ nserror browser_window_history_update(struct browser_window *bw,
guit->bitmap->render(history->current->page.bitmap, content);
}
- if (bw->window != NULL &&
+ if ((bw->window != NULL) &&
guit->window->get_scroll(bw->window, &sx, &sy)) {
int content_height = content_get_height(content);
int content_width = content_get_width(content);
@@ -489,9 +488,7 @@ browser_window_history_get_scroll(struct browser_window *bw,
history = bw->history;
- if (!history ||
- !history->current ||
- !history->current->page.bitmap) {
+ if ((history== NULL) || (history->current == NULL)) {
return NSERROR_INVALID;
}
diff --git a/desktop/browser_history.h b/desktop/browser_history.h
index 06041ebf4..9b6f1fd42 100644
--- a/desktop/browser_history.h
+++ b/desktop/browser_history.h
@@ -35,17 +35,6 @@
#include "utils/errors.h"
-#include "content/handlers/css/utils.h"
-
-#define LOCAL_HISTORY_WIDTH \
- (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(116))))
-#define LOCAL_HISTORY_HEIGHT \
- (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(100))))
-#define LOCAL_HISTORY_RIGHT_MARGIN \
- (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(50))))
-#define LOCAL_HISTORY_BOTTOM_MARGIN \
- (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(30))))
-
struct browser_window;
struct history_entry;
struct bitmap;
diff --git a/desktop/local_history.c b/desktop/local_history.c
index 412e893f5..5227c97e1 100644
--- a/desktop/local_history.c
+++ b/desktop/local_history.c
@@ -41,6 +41,7 @@
#include "desktop/system_colour.h"
#include "desktop/browser_private.h"
#include "desktop/browser_history.h"
+#include "desktop/local_history_private.h"
#include "desktop/local_history.h"
/**
diff --git a/desktop/local_history_private.h b/desktop/local_history_private.h
new file mode 100644
index 000000000..0b745629d
--- /dev/null
+++ b/desktop/local_history_private.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Interface to browser history private operations
+ */
+
+#ifndef NETSURF_DESKTOP_BROWSER_HISTORY_PRIVATE_H
+#define NETSURF_DESKTOP_BROWSER_HISTORY_PRIVATE_H
+
+#include "content/handlers/css/utils.h"
+
+#define LOCAL_HISTORY_WIDTH \
+ (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(116))))
+#define LOCAL_HISTORY_HEIGHT \
+ (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(100))))
+#define LOCAL_HISTORY_RIGHT_MARGIN \
+ (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(50))))
+#define LOCAL_HISTORY_BOTTOM_MARGIN \
+ (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(30))))
+
+#endif
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 6cc3a118f..fd838b80b 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -155,10 +155,10 @@ nserror netsurf_init(const char *store_path)
hlcache_parameters.llcache.fetch_attempts = nsoption_uint(max_retried_fetches);
/* image cache is 25% of total memory cache size */
- image_cache_parameters.limit = (hlcache_parameters.llcache.limit * 25) / 100;
+ image_cache_parameters.limit = hlcache_parameters.llcache.limit / 4;
/* image cache hysteresis is 20% of the image cache size */
- image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100;
+ image_cache_parameters.hysteresis = image_cache_parameters.limit / 5;
/* account for image cache use from total */
hlcache_parameters.llcache.limit -= image_cache_parameters.limit;
@@ -167,7 +167,7 @@ nserror netsurf_init(const char *store_path)
hlcache_parameters.llcache.store.limit = nsoption_uint(disc_cache_size);
/* set backing store hysterissi to 20% */
- hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;;
+ hlcache_parameters.llcache.store.hysteresis = hlcache_parameters.llcache.store.limit / 5;
/* set the path to the backing store */
hlcache_parameters.llcache.store.path =
diff --git a/docs/development.md b/docs/development.md
index 5a8d1aa86..3f08b5496 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -69,6 +69,12 @@ NetSurf [integration tests](docs/integration-testing.md) use the
monkey frontend to operate the browser as a whole. These tests open
windows, navigate to websites and render contents as a user might.
+# New frontend development
+
+[Implementing a new frotend](docs/implementing-new-frontend.md) for a
+toolkit can be challenging and this guide provides an overview and
+worked example.
+
# Documented API
The NetSurf code makes use of Doxygen for code documentation.
diff --git a/docs/implementing-new-frontend.md b/docs/implementing-new-frontend.md
new file mode 100644
index 000000000..4bda47af0
--- /dev/null
+++ b/docs/implementing-new-frontend.md
@@ -0,0 +1,413 @@
+Implementing a new frontend
+===========================
+
+[TOC]
+
+# Introduction
+
+NetSurf is divided into a series of frontends which provide a user
+interface around common core functionality.
+
+Each frontend is a distinct implementation for a specific GUI toolkit.
+
+The existing frontends are covered in the [user
+interface](docs/user-interface.md) documentation.
+
+Note implementing a new frontend implies using a toolkit distinct from
+one of those already implemented and is distinct from porting NetSurf
+to a new operating system platform.
+
+It is recommend, in the strongest terms, that if the prospective
+developer is porting to both a new platform and toolkit that they
+*start* by getting the [monkey](docs/using-monkey.md) frontend
+building and passing at least the basic integration tests on their
+platform.
+
+Experience has shown that attempting to port to a platform and
+implement a toolkit at the same time generally results in failure to
+achieve either goal.
+
+NetSurf is built using GNU make and frontends are expected to
+integrate with this buildsystem.
+
+Implementation languages have historically been limited to C, C++ and
+objective C. However any language that can call C functions and
+*importantly* be called back from C code ought to be usable. For
+example there have been experiments with JAVA using JNI but no current
+frontend is implemented using it.
+
+# Implementation complexity
+
+An absolutely minimal "proof of concept" frontend implementation (like
+the FLTK frontend that will be used as an example) is around 1,000
+lines of C code. Basic functionality like the windows frontend is
+around 7,000 lines. A complete fully functional frontend such as the
+one for GTK is closer to 15,000 lines.
+
+It should be noted the majority of the minimal implementation can
+simply be copied and the names changed as appropriate from an existing
+example. The actual amount of new code that needs to be provided is
+very small.
+
+NetSurf provides a great deal of generic functionality for things like
+cookie, bookmark, history windows which require only minimal frontend
+support with the [core window API](docs/core-window-interface.md).
+
+A frontend developer is free to implement any and all of this generic
+functionality thelselves in a manner more integrated into a toolkit.
+
+# Implementation
+
+A frontend is generally named for the toolkit it is implementing (i.e
+gtk for the GTK+ toolkit). It is advisable to be as specific as
+possible e.g. the frontend for the windows operating system should
+have been named win32 allowing for an impementation using a differnt
+toolkit (e.g mfc)
+
+All the files needed for the frontend are contained in a single
+sub-directory in the NetSurf source tree e.g. `frontends/fltk`
+
+The only file outside this directory that much be changed is the
+`frontends/Makefile.hts` where a new entry must be added to the valid
+targets list.
+
+## Build system
+
+A frontend must provide three GNU Makefile fragments (these will be
+included from the core Makefile):
+
+ - `Makefile` - This is used to extend CFLAGS, CXXFLAGS and LDFLAGS variables as required. The executable target is set with EXETARGET and the browser source files are listed in the SOURCES variable
+ - `Makefile.defaults` - allows setting frontend specific makefile variables and overriding of the default core build variables.
+ - `Makefile.tools` - allows setting up frontend specific build tooling (as a minimum a tool for the package configuration in PKG_CONFIG)
+
+Source code modules can be named as the devloper desires within the
+frontend directory and should be added to the SOURCES variable as
+desired.
+
+## Program entry
+
+Generally the entry point from the OS is the `main()` function and
+several frontends have a `main.cpp` where some have used `gui.c`.
+
+The usual shape for the `main()` function is a six step process:
+ 1. The frontends operation tables are registered with NetSurf
+ 2. The toolkit specific initialisation is performed (which may involve calling NetSurf provided utility functions for support operations like logging, message translations etc.)
+ 3. Initialise the NetSurf core. After this point all browser functionality is available and registered operations can be called.
+ 4. Perform toolkiit setup, usually opening the initial browsing window (perhaps according to user preferences)
+ 5. Run the toolkits main loop while ensuring the Netsurf scheduled operations are also run at teh apropriate time.
+ 6. Finalisation on completion.
+
+## NetSurf operations tables
+
+The frontend will generally call netsurf interfaces to get a desired
+behaviour e.g. `browser_window_create()` to create a new browsing
+context (the `browser_window_` prefix is historical and does not
+necessarily create a window e.g. on gtk it is more likely to open a
+tab in an existing window). To achive the desired operation some
+operations need to be performed by the frontend under control of
+NetSurf, these operations are listed in tables.
+
+The operation tables should be registered with the NetSurf core as one
+of the first operations of the frontend code. The functions in these
+tables (and the tables themselves) must remain valid until
+`netsurf_exit()` is called.
+
+There are (currently) twelve sets of operation tables held in separate
+structures. Only five of these are mandantory (misc, window, fetch,
+bitmap and layout).
+
+In this context mandantory means the tables must be non NULL and do
+not have a suitable default. Each of the mandantory sets contain
+function pointers to implement operations.
+
+### misc operation table
+
+The only mandantory operation in this table is schedule.
+
+When schedule is called the frontend must arrange for the passed
+callback to be called with the context parameter after a number of
+miliseconds.
+
+This callback is typicaly driven through the toolkits event loop and
+it is important such callbacks are not attempted from an operation.
+
+### window operation table
+
+The window operations (poorly named as already mentioned) are where
+the frontend is called to actually manipulate widgets in the
+toolkit. This is mediated through a `gui_window` context pointer which
+is typed as a structure.
+
+This context pointer is passed to all window operations and is
+generally assumed to contain at least a reference to the underlying
+`browser_window` which is provided in the initial create operation to
+allow subsequent use of various core functionality.
+
+The mandantory window operations are:
+ - create - create a new browsing context widget in the frontend toolkit
+ - destroy - destoy a previously created `gui_window`
+ - invalidate - mark an area of the browsing context viewport as requiring redraw (note no redraw should be attempted from here)
+ - get_scroll - get the scroll offsets from the toolkit drawing widget
+ - set_scroll - set the scroll offsets on the toolkit drawing widget
+ - get_dimensions - get the dimensions of the toolkit drawing widget
+ - event - deal with various window events from netsurf which have no additional parameters
+
+
+### fetch operation table
+
+The fetch operations allow the built in scheme fetchers (file, about, resource) to obtain additional information necessary to complete their operation.
+
+The two mandantory operations are:
+ - `filetype` - allows the file scheme to obtain a mime type from a file path e.g. `a.file.name.png` would result in `image/png`
+ - `get_resource_url` - maps resource scheme paths to URL e.g. `resource:default.css` to `file:///usr/share/netsurf/default.css`
+
+### bitmap operation table
+
+The bitmap table and all of its operations are mandantory only because
+the empty defaults have not been included as it is assumed a browser
+will want to display images.
+
+All operations may be provided by stubs that return the failure codes
+until full implementations are made.
+
+### layout operation table
+
+The layout table is used to layout text. All operations are given
+strings to manipulate encoded in UTF-8. There are three mandantory
+operations:
+ - `width` - Calculate the width of a string.
+ - `position` - Find the position in a string where an x coordinate falls.
+ - `split` - Find where to split a string to make it fit a width.
+
+# Worked Example
+
+Rather than attempt to describe every aspect of an implementation we
+will rather work from an actual minimal example for the FLTK toolkit.
+
+This is availble as a single commit (`git show 28ecbf82ed3024f51be4c87928fd91bacfc15cbc`) in the NetSurf source repository. Alternatively it can be [viewed in a web browser](https://git.netsurf-browser.org/netsurf.git/commit/?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc).
+
+This represents the absolute minimum implementation to get a browser
+window on screen (and be able to click visible links). It is
+implemented in C++ as that is the FLTK implementation language but an
+equivalent implementation in other languages should be obvious.
+
+## Building
+
+The [frontends/Makefile.hts](https://git.netsurf-browser.org/netsurf.git/diff/frontends/Makefile.hts?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc)
+had the fltk target added to the VLDTARGET variable. This allows
+NetSurf to be built for this frontend with `make TARGET=fltk`
+
+As previously described the three GNU Make files are added:
+
+[Makefile](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/Makefile?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc)
+this shows how the flags are extended to add the fltk headers and
+library. Additionaly the list of sources are built here, as teh
+comment suggests it is important the SOURCES variable is not expanded
+here so the S_FRONTEND variable is used to allow expansion at teh
+correct time in the build process.
+
+[Makefile.defaults](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/Makefile.defaults?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc)
+has the default setting to control the build parameters and file locations. These can be overriden by the `Makefile.config` at compile time.
+
+[Makefile.tools](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/Makefile.tools?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc)
+allows the configuration of additional tools necessary to build for the target as a minimum pkg-config is usually required to find libraries.
+
+## Program entry
+
+In our example program entry is the classical `main()` in the [main.cpp](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/main.cpp?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc) module.
+
+This implements the six stage process outlined previously.
+
+### Operations table registration
+
+The `netsurf_table` structure is initialised and passed to
+`netsurf_register()`. It should be noted that the approach taken here
+and in most frontends is to have a source module for each operation
+table. The header for each module exposes just the pointer to the
+indivial operation set, this allows for all the operation functions to
+be static to their module and hence helps reduce global symbol usage.
+
+### Frontend specific initialisation
+
+Her it is implemented in `nsfltk_init()` this function performs all
+the operations specific to the frontend which must be initialised
+before netsurf itself. In some toolkits this would require calling the
+toolkit initialisation (e.g. `gtk_init()`).
+
+It is nessesary to initialise netsurf logging and user options at this
+point. A more fully featured implementation would also initialise the
+message translation system here.
+
+### Netsurf initialisation
+
+This is simply the call to `netsurf_init()` from this point the
+browser is fully operational and operations can and will be called.
+
+### Frontend specific startup
+
+Although the browser is running it has not yet been told to open a
+window or navigate to a page. Here `nsfltk_start()` examines the
+command line and environment to determine the initial page to navigate
+to and calls `browser_window_create()` with the url, this will cause
+the browser to open a new browsing context and start the navigation.
+
+A frontend may choose to implement more complex logic here but the
+example here is a good start.
+
+### Toolkit run loop
+
+The function `nsfltk_run()` runs the toolkit event loop. In this case it is using the generic scheduleing in the [misc.cpp](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/misc.cpp?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc) module to ensure callbacks get made at the apropriate time.
+
+There is a `nsfltk_done` boolean global checked here so when all the
+browser windows are closed the program will exit.
+
+A more fully featured port might use the toolkits scheduling rather
+than open coding a solution with a linked list as is done
+here.
+
+A futher optimisation would be to obtain the set of file descriptors
+being used (with `fetch_fdset()`) for active fetches allowing for
+activity based fetch progress instead of the fallback polling method.
+
+### finalisation
+
+This simply finalises the browser stopping all activity and cleaning
+up any resource usage. After the call to `netsurf_exit()` no more
+operation calls will be made and all caches used by the core will be
+flushed.
+
+If user option chnages are to be made persistant `nsoption_finalise()`
+should be called.
+
+The finalisation of logging will ensure that any output buffers are
+flushed.
+
+## The window operation table
+
+Amongst all the boilerplate of the default implementation the only novel code is in the window operation table in the [window.cpp](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/window.cpp?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc) module.
+
+### `nsfltk_window_create`
+
+The create operation instansiates a new `NS_Window` object and
+references it in the gui_window structure which it returns to the
+caller. Technically we could simply return the `NS_Window` object as
+the gui_window pointer but this implementation is avoiding the cast.
+
+Secondly `Fl_Double_Window` is subclassed as `NS_Widget`. The sublass
+allows the close callback to be accessed so the global `nsfltk_done`
+boolean can be set during the destructor method.
+
+The NS_Window creates an instance of `NS_Widget` in its constructor, a
+more extensive implementation would add other window furniture here
+(scroll bars, url bar, navigation elements, etc.)
+
+The implementation subclasses `Fl_Widget` implementing the draw
+method to render the browsing context and the handle method to handle
+mouse events to allow teh user to click.
+
+The `NS_Widget::handle()` method simply translates the mouse press
+event from widget coordinates to netsurf canvas cooridinates and maps
+teh mouse button state. The core is informed of these events using
+`browser_window_mouse_click()`
+
+The `NS_Widget::draw` method similarly translates the fltk toolkits
+clip rectangle, builds a plotting context and calls
+`browser_window_redraw()` which will use the plotting operations in
+the plotting context to render the browsing context within the area
+specified. One thing to note here is the translation between the
+coordinates of the render area and the internal page canvas given as
+the second and third parameters to the draw call. When scrolling is
+required this is achived by altering these offsets.
+
+
+### `nsfltk_window_invalidate()`
+
+This simply calls the damage method on the `Fl_Widget` class with the
+appropriate coordinate translation.
+
+### `nsfltk_window_get_dimensions()`
+
+This obtains the fltk widget width and height and returns them.
+
+## The plotting interface
+
+When the `NS_Widget::draw` method was discussed it was noted that a
+plotting context is built containing an operation table. That table is
+implemented in [plotters.cpp](https://git.netsurf-browser.org/netsurf.git/diff/frontends/fltk/plotters.cpp?h=vince/fltk&id=28ecbf82ed3024f51be4c87928fd91bacfc15cbc)
+
+The implementation here is as minimal as can be, only line, rectangle
+and text have any implementation at all and even that simply sets a
+colour and performs the appropriate fltk draw function (`fl_line`,
+`fl_rect` and `fl_draw` respectively)
+
+# Worked Example next steps
+
+The previous section outlined the absolute minimum
+implementation. Here we can exmaine some next steps taken to extend
+the frontend.
+
+## Improving the user interface
+
+The example discussion is based on a commit (`git show bc546388ce428be5cfa37cecb174d549c7b30320`) in the NetSurf source repository. Alternatively it can be [viewed in a web browser](https://git.netsurf-browser.org/netsurf.git/commit/?h=vince/fltk&id=bc546388ce428be5cfa37cecb174d549c7b30320).
+
+This changes a single module `window.cpp` where the `NS_Window`,
+`NS_Widget` and `NS_URLBar` classes are used to create a basic
+browsing interface.
+
+The static window operation functions are moved inside the `NS_Window`
+class and the `gui_window` structure is used to obtain an instance
+allowing normal methods to be called to implement functionality. This
+is purely to make the C++ code more idiomatic and obviously would be
+handled differently in other languages.
+
+The `NS_Window` constructor builds additional widgets to just the
+browser drawing widget. It creates:
+ - a URL bar widget containing some navigation buttons and a widget to show the current url
+ - a vertical scrollbar
+ - a horizontal scrollbar
+ - a status text widget
+
+The scrollbar widgets fltk callbacks (called when user interacts with
+the scrollbar) call a method on the `NS_Widget` allowing it to track
+the current scroll offsets which are subsequently used in the drawing
+and user input handling methods.
+
+## Improving rendering
+
+Up to this point the rendering has been minimal and the text in a
+single face and size with incorrect width measurement. There was no
+proper handling of plotting styles and colours.
+
+## Implementing bitmap rendering
+
+There was no bitmap rendering so no pretty pictures.
+
+## Implementing the user messages API
+
+This immediately allows the browser to use the existing language
+translations for many internal strings.
+
+## Implementing a user settings dialog
+
+Implementing a way for the user to change configuration options
+without having to edit a configuration file greatly improves the
+perceived functionality.
+
+## Implementing corewindow
+
+The [core window interface](docs/core-window-interface.md) allows a
+frontend to use inbuilt rendering for several interfaces gaining a
+great deal of functionality for very litte code. This one interface
+set gives a cookie viewer,a local and global history viewer and a
+hotlist(bookmarks) viewer.
+
+# Conclusion
+
+Hopefully this breif overview and worked example should give the
+prospectinve frontend developer enough information to understand how
+to get started implementing a new frontend toolkit for NetSurf.
+
+As can be seen there is actualy very little novel code necessary to
+get started though I should mention that the move from "minimal" to
+"full" implementation is a large undertaking and it would be wise to
+talk with the NetSurf developers if undertaking such work.
diff --git a/docs/integration-testing.md b/docs/integration-testing.md
index da93343d2..03b41308a 100644
--- a/docs/integration-testing.md
+++ b/docs/integration-testing.md
@@ -400,9 +400,14 @@ The window to be rendered is identified with the `window` key, the
value of this must be a previously created window identifier or an
assert will occur.
+The `area` key allows control of the area to be redraw. The parameters are on two forms:
+
+ * A sequence of four numbers in the form `x0 y0 x1 y1`
+ * The keyword extent which attempt to plot the entire extent of the canvas
+
An optional list of checks may be specified with the `checks` key. If
any check is not satisfied an assert will occur and the test will
-fail.
+fail. Multiple checks can be specified and all most pass successfully.
The checks available are:
@@ -416,8 +421,10 @@ The checks available are:
- action: plot-check
window: win1
+ area: extent
checks:
- text-contains: NetSurf
+ - text-contains: Browser
- text-not-contains: Chrome
- bitmap-count: 1
diff --git a/frontends/Makefile.hts b/frontends/Makefile.hts
new file mode 100644
index 000000000..b5af240f1
--- /dev/null
+++ b/frontends/Makefile.hts
@@ -0,0 +1,122 @@
+# -*- mode: makefile-gmake -*-
+##
+## determine the HOST TARGET and SUBTARGET
+##
+
+# Determine host type
+# NOTE: HOST determination on RISC OS could fail because of missing bug fixes
+# in UnixLib which only got addressed in UnixLib 5 / GCCSDK 4.
+# When you don't have 'uname' available, you will see:
+# File 'uname' not found
+# When you do and using a 'uname' compiled with a buggy UnixLib, you
+# will see the following printed on screen:
+# RISC OS
+# In both cases HOST make variable is empty and we recover from that by
+# assuming we're building on RISC OS.
+# In case you don't see anything printed (including the warning), you
+# have an up-to-date RISC OS build system. ;-)
+HOST := $(shell uname -s)
+
+# Sanitise host
+# TODO: Ideally, we want the equivalent of s/[^A-Za-z0-9]/_/g here
+HOST := $(subst .,_,$(subst -,_,$(subst /,_,$(HOST))))
+
+ifeq ($(HOST),)
+ HOST := riscos
+ $(warning Build platform determination failed but that's a known problem for RISC OS so we're assuming a native RISC OS build.)
+else
+ ifeq ($(HOST),RISC OS)
+ # Fixup uname -s returning "RISC OS"
+ HOST := riscos
+ endif
+endif
+ifeq ($(HOST),riscos)
+ # Build happening on RO platform, default target is RO backend
+ ifeq ($(TARGET),)
+ TARGET := riscos
+ endif
+endif
+
+ifeq ($(HOST),BeOS)
+ HOST := beos
+endif
+ifeq ($(HOST),Haiku)
+ # Haiku implements the BeOS API
+ HOST := beos
+endif
+ifeq ($(HOST),beos)
+ # Build happening on BeOS platform, default target is BeOS backend
+ ifeq ($(TARGET),)
+ TARGET := beos
+ endif
+ ifeq ($(TARGET),haiku)
+ override TARGET := beos
+ endif
+endif
+
+ifeq ($(HOST),AmigaOS)
+ HOST := amiga
+ ifeq ($(TARGET),)
+ TARGET := amiga
+ endif
+endif
+
+ifeq ($(HOST),FreeMiNT)
+ HOST := mint
+endif
+ifeq ($(HOST),mint)
+ ifeq ($(TARGET),)
+ TARGET := atari
+ endif
+endif
+
+ifeq ($(findstring MINGW,$(HOST)),MINGW)
+ # MSYS' uname reports the likes of "MINGW32_NT-6.0"
+ HOST := windows
+endif
+ifeq ($(HOST),windows)
+ ifeq ($(TARGET),)
+ TARGET := windows
+ endif
+endif
+
+# Setup (sub)targets
+
+# empty default sub target
+SUBTARGET=
+
+# Default target is GTK 3 backend
+ifeq ($(TARGET),)
+ override TARGET := gtk
+ SUBTARGET = 3
+else
+ ifeq ($(TARGET),gtk)
+ # unspecified gtk is gtk3
+ SUBTARGET = 3
+ else
+ ifeq ($(TARGET),gtk3)
+ # gtk3 is gtk target with subtarget of 3
+ override TARGET := gtk
+ SUBTARGET = 3
+ else
+ ifeq ($(TARGET),gtk2)
+ # gtk2 is gtk target with subtarget of 2
+ override TARGET := gtk
+ SUBTARGET = 2
+ else
+ ifeq ($(TARGET),amigaos3)
+ override TARGET := amiga
+ SUBTARGET = os3
+ endif
+ endif
+ endif
+ endif
+endif
+
+# valid values for the TARGET
+VLDTARGET := amiga atari beos framebuffer gtk monkey riscos windows
+
+# Check for valid TARGET
+ifeq ($(filter $(VLDTARGET),$(TARGET)),)
+ $(error Unknown TARGET "$(TARGET)", Must be one of $(VLDTARGET))
+endif
diff --git a/frontends/amiga/Makefile.tools b/frontends/amiga/Makefile.tools
new file mode 100644
index 000000000..c16928783
--- /dev/null
+++ b/frontends/amiga/Makefile.tools
@@ -0,0 +1,21 @@
+# -*- mode: makefile-gmake -*-
+##
+## amiga target tool setup
+##
+
+ifeq ($(findstring amiga,$(HOST)),amiga)
+ # building for amiga on amiga
+ PKG_CONFIG := pkg-config
+else
+ ifeq ($(SUBTARGET),os3)
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-unknown-amigaos/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-unknown-amigaos/cross/bin
+ else
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/ppc-amigaos/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/ppc-amigaos/cross/bin
+ endif
+
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+endif
diff --git a/frontends/amiga/iff_dr2d.c b/frontends/amiga/iff_dr2d.c
index 5de1463f0..624b501ff 100644
--- a/frontends/amiga/iff_dr2d.c
+++ b/frontends/amiga/iff_dr2d.c
@@ -120,6 +120,7 @@ bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
if(!(PushChunk(iffh,0,ID_NAME,IFFSIZE_UNKNOWN)))
{
WriteChunkBytes(iffh,url,strlen(url));
+ WriteChunkBytes(iffh,"\0",1);
PopChunk(iffh);
}
@@ -185,6 +186,7 @@ bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
attr->DashPattern = 1;
attr->EdgeValue = findcolour(diagram->shape[i].stroke);
}
+
attr->EdgeThick = (float) diagram->shape[i].stroke_width;
if(!(PushChunk(iffh,0,ID_ATTR,IFFSIZE_UNKNOWN)))
@@ -281,7 +283,7 @@ bool ami_svg_to_dr2d(struct IFFHandle *iffh, const char *buffer,
if(!(PushChunk(iffh, 0, ID_FONS, IFFSIZE_UNKNOWN)))
{
WriteChunkBytes(iffh, fons, sizeof(struct fons_struct));
- WriteChunkBytes(iffh, "Topaz\0", 6);
+ WriteChunkBytes(iffh, "Helvetica\0", 10);
PopChunk(iffh);
}
free(fons);
diff --git a/frontends/amiga/utf8.c b/frontends/amiga/utf8.c
index af5af126b..fabb1e24c 100755
--- a/frontends/amiga/utf8.c
+++ b/frontends/amiga/utf8.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2020 Chris Young <chris@unsatisfactorysoftware.co.uk>
+ * Copyright 2008-2021 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -35,11 +35,11 @@
static nserror ami_utf8_codesets(const char *string, size_t len, char **result, bool to_local)
{
char *out;
- ULONG utf8_tag, local_tag;
+ ULONG utf8_tag = CSA_SourceCodeset, local_tag = CSA_DestCodeset, len_tag = CSA_SourceLen;
static struct codeset *utf8_cs = NULL;
static struct codeset *local_cs = NULL;
- if(local_cs == NULL) CodesetsFind(NULL,
+ if(local_cs == NULL) local_cs = CodesetsFind(NULL,
#ifdef __amigaos4__
CSA_MIBenum, nsoption_int(local_codeset),
#else
@@ -47,20 +47,19 @@ static nserror ami_utf8_codesets(const char *string, size_t len, char **result,
#endif
TAG_DONE);
- if(utf8_cs == NULL) CodesetsFind(NULL,
+ if(utf8_cs == NULL) utf8_cs = CodesetsFind(NULL,
CSA_MIBenum, CS_MIBENUM_UTF_8,
TAG_DONE);
if(to_local == false) {
local_tag = CSA_SourceCodeset;
utf8_tag = CSA_DestCodeset;
- } else {
- utf8_tag = CSA_SourceCodeset;
- local_tag = CSA_DestCodeset;
}
+ if(len == 0) len_tag = TAG_IGNORE;
+
out = CodesetsConvertStr(CSA_Source, string,
- CSA_SourceLen, len,
+ len_tag, len,
#ifdef __amigaos4__
local_tag, local_cs,
#endif
diff --git a/frontends/atari/Makefile.tools b/frontends/atari/Makefile.tools
new file mode 100644
index 000000000..971ab21be
--- /dev/null
+++ b/frontends/atari/Makefile.tools
@@ -0,0 +1,19 @@
+# -*- mode: makefile-gmake -*-
+##
+## atari target tool setup
+##
+
+ifeq ($(HOST),atari)
+ PKG_CONFIG := pkg-config
+else
+ ifeq ($(HOST),mint)
+ PKG_CONFIG := pkg-config
+ else
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/m68k-atari-mint/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/m68k-atari-mint/cross/bin
+
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+ endif
+endif \ No newline at end of file
diff --git a/frontends/beos/Makefile.tools b/frontends/beos/Makefile.tools
new file mode 100644
index 000000000..0324a2825
--- /dev/null
+++ b/frontends/beos/Makefile.tools
@@ -0,0 +1,14 @@
+# -*- mode: makefile-gmake -*-
+##
+## BeOS target tool setup
+##
+
+# Building for BeOS/Haiku
+#ifeq ($(HOST),beos)
+ # Build for BeOS on BeOS
+ GCCSDK_INSTALL_ENV := /boot/develop
+ CC := gcc
+ CXX := g++
+ EXEEXT :=
+ PKG_CONFIG := pkg-config
+#endif
diff --git a/frontends/framebuffer/Makefile.tools b/frontends/framebuffer/Makefile.tools
new file mode 100644
index 000000000..80623b164
--- /dev/null
+++ b/frontends/framebuffer/Makefile.tools
@@ -0,0 +1,15 @@
+# -*- mode: makefile-gmake -*-
+##
+## tool setup for the framebuffer target
+##
+
+ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
+ PKG_CONFIG := pkg-config
+else
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+endif
+
+ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
+endif
diff --git a/frontends/gtk/Makefile b/frontends/gtk/Makefile
index 3bf3ea063..4f3fd5f52 100644
--- a/frontends/gtk/Makefile
+++ b/frontends/gtk/Makefile
@@ -166,11 +166,11 @@ endif
# ----------------------------------------------------------------------------
# S_FRONTEND are sources purely for the GTK frontend
-S_FRONTEND := gui.c schedule.c layout_pango.c bitmap.c plotters.c \
- scaffolding.c gdk.c completion.c throbber.c accelerator.c \
- selection.c window.c fetch.c download.c menu.c print.c \
- search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \
- viewsource.c preferences.c about.c resources.c corewindow.c \
+S_FRONTEND := gui.c misc.c schedule.c layout_pango.c bitmap.c plotters.c \
+ scaffolding.c gdk.c completion.c throbber.c accelerator.c \
+ selection.c window.c fetch.c download.c menu.c print.c \
+ search.c tabs.c toolbar.c gettext.c compat.c viewdata.c \
+ viewsource.c preferences.c about.c resources.c corewindow.c \
local_history.c global_history.c cookies.c hotlist.c page_info.c
# This is the final source build list
diff --git a/frontends/gtk/Makefile.tools b/frontends/gtk/Makefile.tools
new file mode 100644
index 000000000..5331dcc71
--- /dev/null
+++ b/frontends/gtk/Makefile.tools
@@ -0,0 +1,16 @@
+# -*- mode: makefile-gmake -*-
+##
+## tool setup for the gtk target
+##
+
+# use native package config
+PKG_CONFIG := pkg-config
+
+# gtk target processing
+ifeq ($(SUBTARGET),3)
+ override NETSURF_GTK_MAJOR := 3
+endif
+
+ifeq ($(SUBTARGET),2)
+ override NETSURF_GTK_MAJOR := 2
+endif
diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c
index b3568c602..baa4cf155 100644
--- a/frontends/gtk/corewindow.c
+++ b/frontends/gtk/corewindow.c
@@ -87,6 +87,7 @@ static browser_mouse_state nsgtk_cw_gdkbutton_to_nsstate(GdkEventButton *event)
}
if (event->state & GDK_MOD1_MASK) {
+ /* usually alt */
ms |= BROWSER_MOUSE_MOD_3;
}
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index e5006d954..a826b053a 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -43,12 +43,10 @@
#include "netsurf/cookie_db.h"
#include "netsurf/browser.h"
#include "netsurf/browser_window.h"
-#include "netsurf/misc.h"
#include "netsurf/netsurf.h"
#include "content/fetch.h"
#include "content/backing_store.h"
#include "desktop/save_complete.h"
-#include "desktop/save_pdf.h"
#include "desktop/searchweb.h"
#include "desktop/hotlist.h"
@@ -70,34 +68,183 @@
#include "gtk/selection.h"
#include "gtk/search.h"
#include "gtk/bitmap.h"
+#include "gtk/misc.h"
#include "gtk/resources.h"
#include "gtk/layout_pango.h"
#include "gtk/accelerator.h"
bool nsgtk_complete = false;
-char *nsgtk_config_home; /* exported global defined in gtk/gui.h */
+/* exported global defined in gtk/gui.h */
+char *nsgtk_config_home;
-GdkPixbuf *favicon_pixbuf; /** favicon default pixbuf */
-GdkPixbuf *win_default_icon_pixbuf; /** default window icon pixbuf */
+/** favicon default pixbuf */
+GdkPixbuf *favicon_pixbuf;
+
+/** default window icon pixbuf */
+GdkPixbuf *win_default_icon_pixbuf;
GtkBuilder *warning_builder;
-char **respaths; /** resource search path vector */
+/** resource search path vector */
+char **respaths;
-/**
- * Cause an abnormal program termination.
- *
- * \note This never returns and is intended to terminate without any cleanup.
- *
- * \param error The message to display to the user.
- */
-static void die(const char * const error)
+
+/* exported function documented in gtk/warn.h */
+nserror nsgtk_warning(const char *warning, const char *detail)
{
- fprintf(stderr, "%s", error);
- exit(EXIT_FAILURE);
+ char buf[300]; /* 300 is the size the RISC OS GUI uses */
+ static GtkWindow *nsgtk_warning_window;
+ GtkLabel *WarningLabel;
+
+ NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : "");
+ fflush(stdout);
+
+ nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning"));
+ WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder,
+ "labelWarning"));
+
+ snprintf(buf, sizeof(buf), "%s %s", messages_get(warning),
+ detail ? detail : "");
+ buf[sizeof(buf) - 1] = 0;
+
+ gtk_label_set_text(WarningLabel, buf);
+
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window));
+
+ return NSERROR_OK;
}
+
+/* exported interface documented in gtk/gui.h */
+uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
+{
+ /* this function will need to become much more complex to support
+ * everything that the RISC OS version does. But this will do for
+ * now. I hope.
+ */
+ switch (key->keyval) {
+
+ case GDK_KEY(Tab):
+ return NS_KEY_TAB;
+
+ case GDK_KEY(BackSpace):
+ if (key->state & GDK_SHIFT_MASK)
+ return NS_KEY_DELETE_LINE_START;
+ else
+ return NS_KEY_DELETE_LEFT;
+
+ case GDK_KEY(Delete):
+ if (key->state & GDK_SHIFT_MASK)
+ return NS_KEY_DELETE_LINE_END;
+ else
+ return NS_KEY_DELETE_RIGHT;
+
+ case GDK_KEY(Linefeed):
+ return 13;
+
+ case GDK_KEY(Return):
+ return 10;
+
+ case GDK_KEY(Left):
+ case GDK_KEY(KP_Left):
+ return NS_KEY_LEFT;
+
+ case GDK_KEY(Right):
+ case GDK_KEY(KP_Right):
+ return NS_KEY_RIGHT;
+
+ case GDK_KEY(Up):
+ case GDK_KEY(KP_Up):
+ return NS_KEY_UP;
+
+ case GDK_KEY(Down):
+ case GDK_KEY(KP_Down):
+ return NS_KEY_DOWN;
+
+ case GDK_KEY(Home):
+ case GDK_KEY(KP_Home):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_LINE_START;
+ else
+ return NS_KEY_TEXT_START;
+
+ case GDK_KEY(End):
+ case GDK_KEY(KP_End):
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_LINE_END;
+ else
+ return NS_KEY_TEXT_END;
+
+ case GDK_KEY(Page_Up):
+ case GDK_KEY(KP_Page_Up):
+ return NS_KEY_PAGE_UP;
+
+ case GDK_KEY(Page_Down):
+ case GDK_KEY(KP_Page_Down):
+ return NS_KEY_PAGE_DOWN;
+
+ case 'a':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_SELECT_ALL;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'u':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_DELETE_LINE;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'c':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_COPY_SELECTION;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'v':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_PASTE;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'x':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_CUT_SELECTION;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'Z':
+ case 'y':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_REDO;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case 'z':
+ if (key->state & GDK_CONTROL_MASK)
+ return NS_KEY_UNDO;
+ return gdk_keyval_to_unicode(key->keyval);
+
+ case GDK_KEY(Escape):
+ return NS_KEY_ESCAPE;
+
+ /* Modifiers - do nothing for now */
+ case GDK_KEY(Shift_L):
+ case GDK_KEY(Shift_R):
+ case GDK_KEY(Control_L):
+ case GDK_KEY(Control_R):
+ case GDK_KEY(Caps_Lock):
+ case GDK_KEY(Shift_Lock):
+ case GDK_KEY(Meta_L):
+ case GDK_KEY(Meta_R):
+ case GDK_KEY(Alt_L):
+ case GDK_KEY(Alt_R):
+ case GDK_KEY(Super_L):
+ case GDK_KEY(Super_R):
+ case GDK_KEY(Hyper_L):
+ case GDK_KEY(Hyper_R):
+ return 0;
+
+ }
+ return gdk_keyval_to_unicode(key->keyval);
+}
+
+
/**
* Create an array of valid paths to search for resources.
*
@@ -156,6 +303,176 @@ nsgtk_init_resource_path(const char *config_home)
/**
+ * create directory name and check it is acessible and a directory.
+ */
+static nserror
+check_dirname(const char *path, const char *leaf, char **dirname_out)
+{
+ nserror ret;
+ char *dirname = NULL;
+ struct stat dirname_stat;
+
+ ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* ensure access is possible and the entry is actualy
+ * a directory.
+ */
+ if (stat(dirname, &dirname_stat) == 0) {
+ if (S_ISDIR(dirname_stat.st_mode)) {
+ if (access(dirname, R_OK | W_OK) == 0) {
+ *dirname_out = dirname;
+ return NSERROR_OK;
+ } else {
+ ret = NSERROR_PERMISSION;
+ }
+ } else {
+ ret = NSERROR_NOT_DIRECTORY;
+ }
+ } else {
+ ret = NSERROR_NOT_FOUND;
+ }
+
+ free(dirname);
+
+ return ret;
+}
+
+
+/**
+ * Get the path to the config directory.
+ *
+ * @param config_home_out Path to configuration directory.
+ * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
+ */
+static nserror get_config_home(char **config_home_out)
+{
+ nserror ret;
+ char *home_dir;
+ char *xdg_config_dir;
+ char *config_home;
+
+ home_dir = getenv("HOME");
+
+ /* The old $HOME/.netsurf/ directory should be used if it
+ * exists and is accessible.
+ */
+ if (home_dir != NULL) {
+ ret = check_dirname(home_dir, ".netsurf", &config_home);
+ if (ret == NSERROR_OK) {
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
+ *config_home_out = config_home;
+ return ret;
+ }
+ }
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ /* If $XDG_CONFIG_HOME is either not set or empty, a
+ * default equal to $HOME/.config should be used.
+ */
+
+ /** @todo the meaning of empty is never defined so I
+ * am assuming it is a zero length string but is it
+ * supposed to mean "whitespace" and if so what counts
+ * as whitespace? (are tabs etc. counted or should
+ * isspace() be used)
+ */
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".config/netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
+
+ *config_home_out = config_home;
+ return NSERROR_OK;
+}
+
+
+static nserror create_config_home(char **config_home_out)
+{
+ char *config_home = NULL;
+ char *home_dir;
+ char *xdg_config_dir;
+ nserror ret;
+
+ NSLOG(netsurf, INFO, "Attempting to create configuration directory");
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = netsurf_mkdir_all(config_home);
+ if (ret != NSERROR_OK) {
+ free(config_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ config_home[strlen(config_home) - 1] = 0;
+
+ NSLOG(netsurf, INFO, "\"%s\"", config_home);
+
+ *config_home_out = config_home;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Ensures output logging stream is correctly configured
+ */
+static bool nslog_stream_configure(FILE *fptr)
+{
+ /* set log stream to be non-buffering */
+ setbuf(fptr, NULL);
+
+ return true;
+}
+
+
+/**
* Set option defaults for gtk frontend.
*
* \param defaults The option table to update.
@@ -250,7 +567,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
/* set default items in toolbar */
nsoption_set_charp(toolbar_items,
- strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu"));
+ strdup("back/history/forward/reloadstop/url_bar/websearch/openmenu"));
/* set default for menu and tool bar visibility */
nsoption_set_charp(bar_show, strdup("tool"));
@@ -258,6 +575,253 @@ static nserror set_defaults(struct nsoption_s *defaults)
return NSERROR_OK;
}
+
+/**
+ * Initialise user options
+ *
+ * Initialise the browser configuration options. These are set by:
+ * - set generic defaults suitable for the gtk frontend
+ * - user choices loaded from Choices file
+ * - command line parameters
+ */
+static nserror nsgtk_option_init(int *pargc, char** argv)
+{
+ nserror ret;
+ char *choices = NULL;
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* Attempt to load the user choices */
+ ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
+ if (ret == NSERROR_OK) {
+ nsoption_read(choices, nsoptions);
+ free(choices);
+ }
+
+ /* overide loaded options with those from commandline */
+ nsoption_commandline(pargc, argv, nsoptions);
+
+ /* ensure all options fall within sensible bounds */
+
+ /* Attempt to handle nonsense status bar widths. These may exist
+ * in people's Choices as the GTK front end used to abuse the
+ * status bar width option by using it for an absolute value in px.
+ * The GTK front end now correctly uses it as a proportion of window
+ * width. Here we assume that a value of less than 15% is wrong
+ * and set to the default two thirds. */
+ if (nsoption_int(toolbar_status_size) < 1500) {
+ nsoption_set_int(toolbar_status_size, 6667);
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * initialise message translation
+ */
+static nserror nsgtk_messages_init(char **respaths)
+{
+ const char *messages;
+ nserror ret;
+ const uint8_t *data;
+ size_t data_size;
+
+ ret = nsgtk_data_from_resname("Messages", &data, &data_size);
+ if (ret == NSERROR_OK) {
+ ret = messages_add_from_inline(data, data_size);
+ } else {
+ /* Obtain path to messages */
+ ret = nsgtk_path_from_resname("Messages", &messages);
+ if (ret == NSERROR_OK) {
+ ret = messages_add_from_file(messages);
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * Get the path to the cache directory.
+ *
+ * @param cache_home_out Path to cache directory.
+ * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
+ */
+static nserror get_cache_home(char **cache_home_out)
+{
+ nserror ret;
+ char *xdg_cache_dir;
+ char *cache_home;
+ char *home_dir;
+
+ /* $XDG_CACHE_HOME defines the base directory relative to
+ * which user specific non-essential data files should be
+ * stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ /* If $XDG_CACHE_HOME is either not set or empty, a
+ * default equal to $HOME/.cache should be used.
+ */
+
+ home_dir = getenv("HOME");
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ NSLOG(netsurf, INFO, "\"%s\"", cache_home);
+
+ *cache_home_out = cache_home;
+ return NSERROR_OK;
+}
+
+
+/**
+ * create a cache directory
+ */
+static nserror create_cache_home(char **cache_home_out)
+{
+ char *cache_home = NULL;
+ char *home_dir;
+ char *xdg_cache_dir;
+ nserror ret;
+
+ NSLOG(netsurf, INFO, "Attempting to create cache directory");
+
+ /* $XDG_CACHE_HOME defines the base directory
+ * relative to which user specific cache files
+ * should be stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/");
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = netsurf_mkdir_all(cache_home);
+ if (ret != NSERROR_OK) {
+ free(cache_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ cache_home[strlen(cache_home) - 1] = 0;
+
+ NSLOG(netsurf, INFO, "\"%s\"", cache_home);
+
+ *cache_home_out = cache_home;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * GTK specific initialisation
+ */
+static nserror nsgtk_init(int *pargc, char ***pargv, char **cache_home)
+{
+ nserror ret;
+
+ /* Locate the correct user configuration directory path */
+ ret = get_config_home(&nsgtk_config_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no config directory exists yet so try to create one */
+ ret = create_config_home(&nsgtk_config_home);
+ }
+ if (ret != NSERROR_OK) {
+ NSLOG(netsurf, INFO,
+ "Unable to locate a configuration directory.");
+ nsgtk_config_home = NULL;
+ }
+
+ /* Initialise gtk */
+ gtk_init(pargc, pargv);
+
+ /* initialise logging. Not fatal if it fails but not much we
+ * can do about it either.
+ */
+ nslog_init(nslog_stream_configure, pargc, *pargv);
+
+ /* build the common resource path list */
+ respaths = nsgtk_init_resource_path(nsgtk_config_home);
+ if (respaths == NULL) {
+ fprintf(stderr, "Unable to locate resources\n");
+ return 1;
+ }
+
+ /* initialise the gtk resource handling */
+ ret = nsgtk_init_resources(respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "GTK resources failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return ret;
+ }
+
+ /* Initialise user options */
+ ret = nsgtk_option_init(pargc, *pargv);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "Options failed to initialise (%s)\n",
+ messages_get_errorcode(ret));
+ return ret;
+ }
+
+ /* Initialise translated messages */
+ ret = nsgtk_messages_init(respaths);
+ if (ret != NSERROR_OK) {
+ fprintf(stderr, "Unable to load translated messages (%s)\n",
+ messages_get_errorcode(ret));
+ NSLOG(netsurf, INFO, "Unable to load translated messages");
+ /** \todo decide if message load faliure should be fatal */
+ }
+
+ /* Locate the correct user cache directory path */
+ ret = get_cache_home(cache_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no cache directory exists yet so try to create one */
+ ret = create_cache_home(cache_home);
+ }
+ if (ret != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Unable to locate a cache directory.");
+ }
+
+
+ return NSERROR_OK;
+}
+
+
#if GTK_CHECK_VERSION(3,14,0)
/**
@@ -266,7 +830,7 @@ static nserror set_defaults(struct nsoption_s *defaults)
static nserror nsgtk_add_named_icons_to_theme(void)
{
gtk_icon_theme_add_resource_path(gtk_icon_theme_get_default(),
- "/org/netsurf/icons");
+ "/org/netsurf/icons");
return NSERROR_OK;
}
@@ -280,7 +844,7 @@ add_builtin_icon(const char *prefix, const char *name, int x, int y)
char *resname;
int resnamelen;
- /* resource name string length allowing for / .png and termination */
+ /* resource name string length allowing for / .png and termination */
resnamelen = strlen(prefix) + strlen(name) + 5 + 1 + 4 + 1;
resname = malloc(resnamelen);
if (resname == NULL) {
@@ -299,13 +863,14 @@ add_builtin_icon(const char *prefix, const char *name, int x, int y)
return NSERROR_OK;
}
+
/**
* adds named icons into gtk theme
*/
static nserror nsgtk_add_named_icons_to_theme(void)
{
/* these must also be in gtk/resources.c pixbuf_resource *and*
- * gtk/res/netsurf.gresource.xml
+ * gtk/res/netsurf.gresource.xml
*/
add_builtin_icon("", "local-history", 8, 32);
add_builtin_icon("", "show-cookie", 24, 24);
@@ -327,13 +892,13 @@ static nserror nsgtk_add_named_icons_to_theme(void)
/**
- * Initialize GTK specific parts of the browser.
+ * setup GTK specific parts of the browser.
*
* \param argc The number of arguments on the command line
* \param argv A string vector of command line arguments.
* \respath A string vector of the path elements of resources
*/
-static nserror nsgtk_init(int argc, char** argv, char **respath)
+static nserror nsgtk_setup(int argc, char** argv, char **respath)
{
char buf[PATH_MAX];
char *resource_filename;
@@ -467,19 +1032,6 @@ static nserror nsgtk_init(int argc, char** argv, char **respath)
}
-
-/**
- * Ensures output logging stream is correctly configured
- */
-static bool nslog_stream_configure(FILE *fptr)
-{
- /* set log stream to be non-buffering */
- setbuf(fptr, NULL);
-
- return true;
-}
-
-
/**
* Run the gtk event loop.
*
@@ -540,7 +1092,10 @@ static void nsgtk_main(void)
}
-static void gui_quit(void)
+/**
+ * finalise the browser
+ */
+static void nsgtk_finalise(void)
{
nserror res;
@@ -592,630 +1147,28 @@ static void gui_quit(void)
free(nsgtk_config_home);
gtk_fetch_filetype_fin();
-}
-
-static nserror gui_launch_url(struct nsurl *url)
-{
- gboolean ok;
- GError *error = NULL;
- ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error);
- if (ok == TRUE) {
- return NSERROR_OK;
- }
-
- if (error) {
- nsgtk_warning(messages_get("URIOpenError"), error->message);
- g_error_free(error);
- }
- return NSERROR_NO_FETCH_HANDLER;
-}
-
-/* exported function documented in gtk/warn.h */
-nserror nsgtk_warning(const char *warning, const char *detail)
-{
- char buf[300]; /* 300 is the size the RISC OS GUI uses */
- static GtkWindow *nsgtk_warning_window;
- GtkLabel *WarningLabel;
-
- NSLOG(netsurf, INFO, "%s %s", warning, detail ? detail : "");
- fflush(stdout);
-
- nsgtk_warning_window = GTK_WINDOW(gtk_builder_get_object(warning_builder, "wndWarning"));
- WarningLabel = GTK_LABEL(gtk_builder_get_object(warning_builder,
- "labelWarning"));
-
- snprintf(buf, sizeof(buf), "%s %s", messages_get(warning),
- detail ? detail : "");
- buf[sizeof(buf) - 1] = 0;
-
- gtk_label_set_text(WarningLabel, buf);
-
- gtk_widget_show_all(GTK_WIDGET(nsgtk_warning_window));
-
- return NSERROR_OK;
-}
-
-
-static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data)
-{
- char **owner_pass = ((void **)data)[0];
- char **user_pass = ((void **)data)[1];
- GtkWindow *wnd = ((void **)data)[2];
- GtkBuilder *password_builder = ((void **)data)[3];
- char *path = ((void **)data)[4];
-
- char *op, *op1;
- char *up, *up1;
-
- op = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFOwnerPassword"))));
- op1 = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFOwnerPassword1"))));
- up = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFUserPassword"))));
- up1 = strdup(gtk_entry_get_text(
- GTK_ENTRY(gtk_builder_get_object(password_builder,
- "entryPDFUserPassword1"))));
-
-
- if (op[0] == '\0') {
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
- "labelInfo")),
- "Owner password must be at least 1 character long:");
- free(op);
- free(up);
- } else if (!strcmp(op, up)) {
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
- "labelInfo")),
- "User and owner passwords must be different:");
- free(op);
- free(up);
- } else if (!strcmp(op, op1) && !strcmp(up, up1)) {
-
- *owner_pass = op;
- if (up[0] == '\0')
- free(up);
- else
- *user_pass = up;
-
- free(data);
- gtk_widget_destroy(GTK_WIDGET(wnd));
- g_object_unref(G_OBJECT(password_builder));
-
- save_pdf(path);
-
- free(path);
- } else {
- gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
- "labelInfo")), "Passwords not confirmed:");
- free(op);
- free(up);
- }
-
- free(op1);
- free(up1);
-}
-
-static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data)
-{
- GtkWindow *wnd = ((void **)data)[2];
- GtkBuilder *password_builder = ((void **)data)[3];
- char *path = ((void **)data)[4];
-
- free(data);
-
- gtk_widget_destroy(GTK_WIDGET(wnd));
- g_object_unref(G_OBJECT(password_builder));
-
- save_pdf(path);
-
- free(path);
-}
-
-static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path)
-{
- GtkButton *ok, *no;
- GtkWindow *wnd;
- void **data;
- GtkBuilder *password_builder;
- nserror res;
-
- res = nsgtk_builder_new_from_resname("password", &password_builder);
- if (res != NSERROR_OK) {
- NSLOG(netsurf, INFO, "Password UI builder init failed");
- return;
- }
-
- gtk_builder_connect_signals(password_builder, NULL);
-
- wnd = GTK_WINDOW(gtk_builder_get_object(password_builder,
- "wndPDFPassword"));
-
- data = malloc(5 * sizeof(void *));
-
- *owner_pass = NULL;
- *user_pass = NULL;
-
- data[0] = owner_pass;
- data[1] = user_pass;
- data[2] = wnd;
- data[3] = password_builder;
- data[4] = path;
-
- ok = GTK_BUTTON(gtk_builder_get_object(password_builder,
- "buttonPDFSetPassword"));
- no = GTK_BUTTON(gtk_builder_get_object(password_builder,
- "buttonPDFNoPassword"));
-
- g_signal_connect(G_OBJECT(ok), "clicked",
- G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data);
- g_signal_connect(G_OBJECT(no), "clicked",
- G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data);
-
- gtk_widget_show(GTK_WIDGET(wnd));
-}
-
-
-uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
-{
- /* this function will need to become much more complex to support
- * everything that the RISC OS version does. But this will do for
- * now. I hope.
- */
- switch (key->keyval) {
-
- case GDK_KEY(Tab):
- return NS_KEY_TAB;
-
- case GDK_KEY(BackSpace):
- if (key->state & GDK_SHIFT_MASK)
- return NS_KEY_DELETE_LINE_START;
- else
- return NS_KEY_DELETE_LEFT;
-
- case GDK_KEY(Delete):
- if (key->state & GDK_SHIFT_MASK)
- return NS_KEY_DELETE_LINE_END;
- else
- return NS_KEY_DELETE_RIGHT;
-
- case GDK_KEY(Linefeed):
- return 13;
-
- case GDK_KEY(Return):
- return 10;
-
- case GDK_KEY(Left):
- case GDK_KEY(KP_Left):
- return NS_KEY_LEFT;
-
- case GDK_KEY(Right):
- case GDK_KEY(KP_Right):
- return NS_KEY_RIGHT;
-
- case GDK_KEY(Up):
- case GDK_KEY(KP_Up):
- return NS_KEY_UP;
-
- case GDK_KEY(Down):
- case GDK_KEY(KP_Down):
- return NS_KEY_DOWN;
-
- case GDK_KEY(Home):
- case GDK_KEY(KP_Home):
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_LINE_START;
- else
- return NS_KEY_TEXT_START;
-
- case GDK_KEY(End):
- case GDK_KEY(KP_End):
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_LINE_END;
- else
- return NS_KEY_TEXT_END;
-
- case GDK_KEY(Page_Up):
- case GDK_KEY(KP_Page_Up):
- return NS_KEY_PAGE_UP;
-
- case GDK_KEY(Page_Down):
- case GDK_KEY(KP_Page_Down):
- return NS_KEY_PAGE_DOWN;
-
- case 'a':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_SELECT_ALL;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'u':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_DELETE_LINE;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'c':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_COPY_SELECTION;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'v':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_PASTE;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'x':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_CUT_SELECTION;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'Z':
- case 'y':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_REDO;
- return gdk_keyval_to_unicode(key->keyval);
-
- case 'z':
- if (key->state & GDK_CONTROL_MASK)
- return NS_KEY_UNDO;
- return gdk_keyval_to_unicode(key->keyval);
-
- case GDK_KEY(Escape):
- return NS_KEY_ESCAPE;
-
- /* Modifiers - do nothing for now */
- case GDK_KEY(Shift_L):
- case GDK_KEY(Shift_R):
- case GDK_KEY(Control_L):
- case GDK_KEY(Control_R):
- case GDK_KEY(Caps_Lock):
- case GDK_KEY(Shift_Lock):
- case GDK_KEY(Meta_L):
- case GDK_KEY(Meta_R):
- case GDK_KEY(Alt_L):
- case GDK_KEY(Alt_R):
- case GDK_KEY(Super_L):
- case GDK_KEY(Super_R):
- case GDK_KEY(Hyper_L):
- case GDK_KEY(Hyper_R):
- return 0;
-
- }
- return gdk_keyval_to_unicode(key->keyval);
-}
-
-
-/**
- * create directory name and check it is acessible and a directory.
- */
-static nserror
-check_dirname(const char *path, const char *leaf, char **dirname_out)
-{
- nserror ret;
- char *dirname = NULL;
- struct stat dirname_stat;
-
- ret = netsurf_mkpath(&dirname, NULL, 2, path, leaf);
- if (ret != NSERROR_OK) {
- return ret;
- }
-
- /* ensure access is possible and the entry is actualy
- * a directory.
- */
- if (stat(dirname, &dirname_stat) == 0) {
- if (S_ISDIR(dirname_stat.st_mode)) {
- if (access(dirname, R_OK | W_OK) == 0) {
- *dirname_out = dirname;
- return NSERROR_OK;
- } else {
- ret = NSERROR_PERMISSION;
- }
- } else {
- ret = NSERROR_NOT_DIRECTORY;
- }
- } else {
- ret = NSERROR_NOT_FOUND;
- }
-
- free(dirname);
-
- return ret;
-}
-
-/**
- * Get the path to the config directory.
- *
- * @param config_home_out Path to configuration directory.
- * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
- */
-static nserror get_config_home(char **config_home_out)
-{
- nserror ret;
- char *home_dir;
- char *xdg_config_dir;
- char *config_home;
-
- home_dir = getenv("HOME");
-
- /* The old $HOME/.netsurf/ directory should be used if it
- * exists and is accessible.
- */
- if (home_dir != NULL) {
- ret = check_dirname(home_dir, ".netsurf", &config_home);
- if (ret == NSERROR_OK) {
- NSLOG(netsurf, INFO, "\"%s\"", config_home);
- *config_home_out = config_home;
- return ret;
- }
- }
-
- /* $XDG_CONFIG_HOME defines the base directory
- * relative to which user specific configuration files
- * should be stored.
- */
- xdg_config_dir = getenv("XDG_CONFIG_HOME");
-
- if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
- /* If $XDG_CONFIG_HOME is either not set or empty, a
- * default equal to $HOME/.config should be used.
- */
-
- /** @todo the meaning of empty is never defined so I
- * am assuming it is a zero length string but is it
- * supposed to mean "whitespace" and if so what counts
- * as whitespace? (are tabs etc. counted or should
- * isspace() be used)
- */
-
- /* the HOME envvar is required */
- if (home_dir == NULL) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = check_dirname(home_dir, ".config/netsurf", &config_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- NSLOG(netsurf, INFO, "\"%s\"", config_home);
-
- *config_home_out = config_home;
- return NSERROR_OK;
-}
-
-static nserror create_config_home(char **config_home_out)
-{
- char *config_home = NULL;
- char *home_dir;
- char *xdg_config_dir;
- nserror ret;
-
- NSLOG(netsurf, INFO, "Attempting to create configuration directory");
-
- /* $XDG_CONFIG_HOME defines the base directory
- * relative to which user specific configuration files
- * should be stored.
- */
- xdg_config_dir = getenv("XDG_CONFIG_HOME");
-
- if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
- home_dir = getenv("HOME");
-
- if ((home_dir == NULL) || (*home_dir == 0)) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = netsurf_mkpath(&config_home, NULL, 4, home_dir, ".config","netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = netsurf_mkpath(&config_home, NULL, 3, xdg_config_dir, "netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- /* ensure all elements of path exist (the trailing / is required) */
- ret = netsurf_mkdir_all(config_home);
- if (ret != NSERROR_OK) {
- free(config_home);
- return ret;
- }
-
- /* strip the trailing separator */
- config_home[strlen(config_home) - 1] = 0;
-
- NSLOG(netsurf, INFO, "\"%s\"", config_home);
-
- *config_home_out = config_home;
-
- return NSERROR_OK;
-}
-
-/**
- * Get the path to the cache directory.
- *
- * @param cache_home_out Path to cache directory.
- * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
- */
-static nserror get_cache_home(char **cache_home_out)
-{
- nserror ret;
- char *xdg_cache_dir;
- char *cache_home;
- char *home_dir;
-
- /* $XDG_CACHE_HOME defines the base directory relative to
- * which user specific non-essential data files should be
- * stored.
- */
- xdg_cache_dir = getenv("XDG_CACHE_HOME");
-
- if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
- /* If $XDG_CACHE_HOME is either not set or empty, a
- * default equal to $HOME/.cache should be used.
- */
-
- home_dir = getenv("HOME");
-
- /* the HOME envvar is required */
- if (home_dir == NULL) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- NSLOG(netsurf, INFO, "\"%s\"", cache_home);
-
- *cache_home_out = cache_home;
- return NSERROR_OK;
-}
-
-static nserror create_cache_home(char **cache_home_out)
-{
- char *cache_home = NULL;
- char *home_dir;
- char *xdg_cache_dir;
- nserror ret;
-
- NSLOG(netsurf, INFO, "Attempting to create configuration directory");
-
- /* $XDG_CACHE_HOME defines the base directory
- * relative to which user specific cache files
- * should be stored.
- */
- xdg_cache_dir = getenv("XDG_CACHE_HOME");
-
- if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
- home_dir = getenv("HOME");
-
- if ((home_dir == NULL) || (*home_dir == 0)) {
- return NSERROR_NOT_DIRECTORY;
- }
-
- ret = netsurf_mkpath(&cache_home, NULL, 4, home_dir, ".cache", "netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- } else {
- ret = netsurf_mkpath(&cache_home, NULL, 3, xdg_cache_dir, "netsurf", "/");
- if (ret != NSERROR_OK) {
- return ret;
- }
- }
-
- /* ensure all elements of path exist (the trailing / is required) */
- ret = netsurf_mkdir_all(cache_home);
- if (ret != NSERROR_OK) {
- free(cache_home);
- return ret;
- }
-
- /* strip the trailing separator */
- cache_home[strlen(cache_home) - 1] = 0;
-
- NSLOG(netsurf, INFO, "\"%s\"", cache_home);
-
- *cache_home_out = cache_home;
-
- return NSERROR_OK;
-}
-
-static nserror nsgtk_option_init(int *pargc, char** argv)
-{
- nserror ret;
- char *choices = NULL;
-
- /* user options setup */
- ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
- if (ret != NSERROR_OK) {
- return ret;
- }
-
- /* Attempt to load the user choices */
- ret = netsurf_mkpath(&choices, NULL, 2, nsgtk_config_home, "Choices");
- if (ret == NSERROR_OK) {
- nsoption_read(choices, nsoptions);
- free(choices);
- }
-
- /* overide loaded options with those from commandline */
- nsoption_commandline(pargc, argv, nsoptions);
+ /* common finalisation */
+ netsurf_exit();
- /* ensure all options fall within sensible bounds */
+ /* finalise options */
+ nsoption_finalise(nsoptions, nsoptions_default);
- /* Attempt to handle nonsense status bar widths. These may exist
- * in people's Choices as the GTK front end used to abuse the
- * status bar width option by using it for an absolute value in px.
- * The GTK front end now correctly uses it as a proportion of window
- * width. Here we assume that a value of less than 15% is wrong
- * and set to the default two thirds. */
- if (nsoption_int(toolbar_status_size) < 1500) {
- nsoption_set_int(toolbar_status_size, 6667);
- }
+ /* finalise logging */
+ nslog_finalise();
- return NSERROR_OK;
}
-static struct gui_misc_table nsgtk_misc_table = {
- .schedule = nsgtk_schedule,
-
- .quit = gui_quit,
- .launch_url = gui_launch_url,
- .pdf_password = nsgtk_pdf_password,
- .present_cookies = nsgtk_cookies_present,
-};
-
-
-static nserror nsgtk_messages_init(char **respaths)
-{
- const char *messages;
- nserror ret;
- const uint8_t *data;
- size_t data_size;
-
- ret = nsgtk_data_from_resname("Messages", &data, &data_size);
- if (ret == NSERROR_OK) {
- ret = messages_add_from_inline(data, data_size);
- } else {
- /* Obtain path to messages */
- ret = nsgtk_path_from_resname("Messages", &messages);
- if (ret == NSERROR_OK) {
- ret = messages_add_from_file(messages);
- }
- }
- return ret;
-}
/**
* Main entry point from OS.
*/
int main(int argc, char** argv)
{
+ nserror res;
char *cache_home = NULL;
- nserror ret;
struct netsurf_table nsgtk_table = {
- .misc = &nsgtk_misc_table,
+ .misc = nsgtk_misc_table,
.window = nsgtk_window_table,
.clipboard = nsgtk_clipboard_table,
.download = nsgtk_download_table,
@@ -1227,99 +1180,43 @@ int main(int argc, char** argv)
.layout = nsgtk_layout_table,
};
- ret = netsurf_register(&nsgtk_table);
- if (ret != NSERROR_OK) {
- die("NetSurf operation table failed registration\n");
- }
-
- /* Locate the correct user configuration directory path */
- ret = get_config_home(&nsgtk_config_home);
- if (ret == NSERROR_NOT_FOUND) {
- /* no config directory exists yet so try to create one */
- ret = create_config_home(&nsgtk_config_home);
- }
- if (ret != NSERROR_OK) {
- NSLOG(netsurf, INFO,
- "Unable to locate a configuration directory.");
- nsgtk_config_home = NULL;
- }
-
- /* Initialise gtk */
- gtk_init(&argc, &argv);
-
- /* initialise logging. Not fatal if it fails but not much we
- * can do about it either.
- */
- nslog_init(nslog_stream_configure, &argc, argv);
-
- /* build the common resource path list */
- respaths = nsgtk_init_resource_path(nsgtk_config_home);
- if (respaths == NULL) {
- fprintf(stderr, "Unable to locate resources\n");
- return 1;
- }
-
- /* initialise the gtk resource handling */
- ret = nsgtk_init_resources(respaths);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "GTK resources failed to initialise (%s)\n",
- messages_get_errorcode(ret));
- return 1;
- }
-
- /* Initialise user options */
- ret = nsgtk_option_init(&argc, argv);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "Options failed to initialise (%s)\n",
- messages_get_errorcode(ret));
+ res = netsurf_register(&nsgtk_table);
+ if (res != NSERROR_OK) {
+ fprintf(stderr,
+ "NetSurf operation table failed registration (%s)\n",
+ messages_get_errorcode(res));
return 1;
}
- /* Initialise translated messages */
- ret = nsgtk_messages_init(respaths);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "Unable to load translated messages (%s)\n",
- messages_get_errorcode(ret));
- NSLOG(netsurf, INFO, "Unable to load translated messages");
- /** \todo decide if message load faliure should be fatal */
- }
-
- /* Locate the correct user cache directory path */
- ret = get_cache_home(&cache_home);
- if (ret == NSERROR_NOT_FOUND) {
- /* no cache directory exists yet so try to create one */
- ret = create_cache_home(&cache_home);
- }
- if (ret != NSERROR_OK) {
- NSLOG(netsurf, INFO, "Unable to locate a cache directory.");
+ /* gtk specific initialisation */
+ res = nsgtk_init(&argc, &argv, &cache_home);
+ if (res != NSERROR_OK) {
+ fprintf(stderr, "NetSurf gtk failed to initialise (%s)\n",
+ messages_get_errorcode(res));
+ return 2;
}
/* core initialisation */
- ret = netsurf_init(cache_home);
+ res = netsurf_init(cache_home);
free(cache_home);
- if (ret != NSERROR_OK) {
+ if (res != NSERROR_OK) {
fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
- messages_get_errorcode(ret));
- return 1;
+ messages_get_errorcode(res));
+ return 3;
}
/* gtk specific initalisation and main run loop */
- ret = nsgtk_init(argc, argv, respaths);
- if (ret != NSERROR_OK) {
- fprintf(stderr, "NetSurf gtk initialise failed (%s)\n",
- messages_get_errorcode(ret));
- } else {
- nsgtk_main();
+ res = nsgtk_setup(argc, argv, respaths);
+ if (res != NSERROR_OK) {
+ nsgtk_finalise();
+ fprintf(stderr, "NetSurf gtk setup failed (%s)\n",
+ messages_get_errorcode(res));
+ return 4;
}
- /* common finalisation */
- netsurf_exit();
+ nsgtk_main();
- /* finalise options */
- nsoption_finalise(nsoptions, nsoptions_default);
-
- /* finalise logging */
- nslog_finalise();
+ nsgtk_finalise();
return 0;
}
diff --git a/frontends/gtk/misc.c b/frontends/gtk/misc.c
new file mode 100644
index 000000000..bda0dd688
--- /dev/null
+++ b/frontends/gtk/misc.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2021 Vincemt Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * \file
+ * Implementation of netsurf miscellaneous operations table
+ */
+
+#include <stdbool.h>
+#include <gtk/gtk.h>
+
+#include "utils/errors.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/nsurl.h"
+#include "netsurf/misc.h"
+#include "desktop/save_pdf.h"
+
+#include "gtk/compat.h"
+#include "gtk/warn.h"
+#include "gtk/schedule.h"
+#include "gtk/resources.h"
+#include "gtk/cookies.h"
+#include "gtk/misc.h"
+
+
+static nserror gui_launch_url(struct nsurl *url)
+{
+ gboolean ok;
+ GError *error = NULL;
+
+ ok = nsgtk_show_uri(NULL, nsurl_access(url), GDK_CURRENT_TIME, &error);
+ if (ok == TRUE) {
+ return NSERROR_OK;
+ }
+
+ if (error) {
+ nsgtk_warning(messages_get("URIOpenError"), error->message);
+ g_error_free(error);
+ }
+ return NSERROR_NO_FETCH_HANDLER;
+}
+
+static void nsgtk_PDF_set_pass(GtkButton *w, gpointer data)
+{
+ char **owner_pass = ((void **)data)[0];
+ char **user_pass = ((void **)data)[1];
+ GtkWindow *wnd = ((void **)data)[2];
+ GtkBuilder *password_builder = ((void **)data)[3];
+ char *path = ((void **)data)[4];
+
+ char *op, *op1;
+ char *up, *up1;
+
+ op = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFOwnerPassword"))));
+ op1 = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFOwnerPassword1"))));
+ up = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFUserPassword"))));
+ up1 = strdup(gtk_entry_get_text(
+ GTK_ENTRY(gtk_builder_get_object(password_builder,
+ "entryPDFUserPassword1"))));
+
+
+ if (op[0] == '\0') {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")),
+ "Owner password must be at least 1 character long:");
+ free(op);
+ free(up);
+ } else if (!strcmp(op, up)) {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")),
+ "User and owner passwords must be different:");
+ free(op);
+ free(up);
+ } else if (!strcmp(op, op1) && !strcmp(up, up1)) {
+
+ *owner_pass = op;
+ if (up[0] == '\0')
+ free(up);
+ else
+ *user_pass = up;
+
+ free(data);
+ gtk_widget_destroy(GTK_WIDGET(wnd));
+ g_object_unref(G_OBJECT(password_builder));
+
+ save_pdf(path);
+
+ free(path);
+ } else {
+ gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(password_builder,
+ "labelInfo")), "Passwords not confirmed:");
+ free(op);
+ free(up);
+ }
+
+ free(op1);
+ free(up1);
+}
+
+static void nsgtk_PDF_no_pass(GtkButton *w, gpointer data)
+{
+ GtkWindow *wnd = ((void **)data)[2];
+ GtkBuilder *password_builder = ((void **)data)[3];
+ char *path = ((void **)data)[4];
+
+ free(data);
+
+ gtk_widget_destroy(GTK_WIDGET(wnd));
+ g_object_unref(G_OBJECT(password_builder));
+
+ save_pdf(path);
+
+ free(path);
+}
+
+static void nsgtk_pdf_password(char **owner_pass, char **user_pass, char *path)
+{
+ GtkButton *ok, *no;
+ GtkWindow *wnd;
+ void **data;
+ GtkBuilder *password_builder;
+ nserror res;
+
+ res = nsgtk_builder_new_from_resname("password", &password_builder);
+ if (res != NSERROR_OK) {
+ NSLOG(netsurf, INFO, "Password UI builder init failed");
+ return;
+ }
+
+ gtk_builder_connect_signals(password_builder, NULL);
+
+ wnd = GTK_WINDOW(gtk_builder_get_object(password_builder,
+ "wndPDFPassword"));
+
+ data = malloc(5 * sizeof(void *));
+
+ *owner_pass = NULL;
+ *user_pass = NULL;
+
+ data[0] = owner_pass;
+ data[1] = user_pass;
+ data[2] = wnd;
+ data[3] = password_builder;
+ data[4] = path;
+
+ ok = GTK_BUTTON(gtk_builder_get_object(password_builder,
+ "buttonPDFSetPassword"));
+ no = GTK_BUTTON(gtk_builder_get_object(password_builder,
+ "buttonPDFNoPassword"));
+
+ g_signal_connect(G_OBJECT(ok), "clicked",
+ G_CALLBACK(nsgtk_PDF_set_pass), (gpointer)data);
+ g_signal_connect(G_OBJECT(no), "clicked",
+ G_CALLBACK(nsgtk_PDF_no_pass), (gpointer)data);
+
+ gtk_widget_show(GTK_WIDGET(wnd));
+}
+
+
+static struct gui_misc_table misc_table = {
+ .schedule = nsgtk_schedule,
+
+ .launch_url = gui_launch_url,
+ .pdf_password = nsgtk_pdf_password,
+ .present_cookies = nsgtk_cookies_present,
+};
+
+struct gui_misc_table *nsgtk_misc_table = &misc_table;
diff --git a/frontends/gtk/misc.h b/frontends/gtk/misc.h
new file mode 100644
index 000000000..3a02c2254
--- /dev/null
+++ b/frontends/gtk/misc.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2021 Vincemt Sanders <vince@netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NETSURF_GTK_MISC_H
+#define NETSURF_GTK_MISC_H 1
+
+extern struct gui_misc_table *nsgtk_misc_table;
+
+#endif
diff --git a/frontends/gtk/window.c b/frontends/gtk/window.c
index f0a53a66f..f5c87ef87 100644
--- a/frontends/gtk/window.c
+++ b/frontends/gtk/window.c
@@ -391,12 +391,25 @@ nsgtk_window_button_release_event(GtkWidget *widget,
bool shift = event->state & GDK_SHIFT_MASK;
bool ctrl = event->state & GDK_CONTROL_MASK;
+ switch (event->button) {
+ case 8:
+ nsgtk_toolbar_item_activate(g->toolbar, BACK_BUTTON);
+ break;
+ case 9:
+ nsgtk_toolbar_item_activate(g->toolbar, FORWARD_BUTTON);
+ break;
+ default:
+ NSLOG(netsurf, DEBUG, "event button %d", event->button);
+ break;
+ }
+
/* If the mouse state is PRESS then we are waiting for a release to emit
* a click event, otherwise just reset the state to nothing */
- if (g->mouse.state & BROWSER_MOUSE_PRESS_1)
+ if (g->mouse.state & BROWSER_MOUSE_PRESS_1) {
g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1);
- else if (g->mouse.state & BROWSER_MOUSE_PRESS_2)
+ } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) {
g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2);
+ }
/* Handle modifiers being removed */
if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift)
diff --git a/frontends/monkey/Makefile.tools b/frontends/monkey/Makefile.tools
new file mode 100644
index 000000000..7546506ff
--- /dev/null
+++ b/frontends/monkey/Makefile.tools
@@ -0,0 +1,15 @@
+# -*- mode: makefile-gmake -*-
+##
+## monkey target tool setup
+##
+
+ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
+ PKG_CONFIG := pkg-config
+else
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+endif
+
+ifneq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
+endif
diff --git a/frontends/monkey/main.c b/frontends/monkey/main.c
index bae815056..463f0bea6 100644
--- a/frontends/monkey/main.c
+++ b/frontends/monkey/main.c
@@ -73,7 +73,8 @@ static void die(const char * const error)
exit(EXIT_FAILURE);
}
-/** obtain language from environment
+/**
+ * obtain language from environment
*
* start with GNU extension LANGUAGE environment variable and then try
* POSIX variables LC_ALL, LC_MESSAGES and LANG
@@ -107,7 +108,8 @@ static const char *get_language(void)
}
-/** provide a string vector of languages in preference order
+/**
+ * provide a string vector of languages in preference order
*
* environment variables are processed to aquire a colon separated
* list of languages which are converted into a string vector. The
@@ -174,7 +176,16 @@ static const char * const *get_languagev(void)
return &langv[0];
}
-/* Stolen from gtk/gui.c */
+/**
+ * Create an array of valid paths to search for resources.
+ *
+ * The idea is that all the complex path computation to find resources
+ * is performed here, once, rather than every time a resource is
+ * searched for.
+ *
+ * \param resource_path A shell style colon separated path list
+ * \return A string vector of valid paths where resources can be found
+ */
static char **
nsmonkey_init_resource(const char *resource_path)
{
diff --git a/frontends/riscos/Makefile.tools b/frontends/riscos/Makefile.tools
new file mode 100644
index 000000000..9ea5c29f2
--- /dev/null
+++ b/frontends/riscos/Makefile.tools
@@ -0,0 +1,52 @@
+# -*- mode: makefile-gmake -*-
+##
+## RISC OS target tool setup
+##
+
+ifeq ($(HOST),riscos)
+ # Build for RO on RO
+ GCCSDK_INSTALL_ENV := <NSLibs$$Dir>
+ CCRES := ccres
+ TPLEXT :=
+ MAKERUN := makerun
+ SQUEEZE := squeeze
+ RUNEXT :=
+ CC := gcc
+ CXX := g++
+ EXEEXT :=
+ PKG_CONFIG :=
+else
+ # Cross-build for RO (either using GCCSDK 3.4.6 - AOF,
+ # either using GCCSDK 4 - ELF)
+ ifeq ($(origin GCCSDK_INSTALL_ENV),undefined)
+ ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/env),)
+ GCCSDK_INSTALL_ENV := /opt/netsurf/arm-unknown-riscos/env
+ else
+ GCCSDK_INSTALL_ENV := /home/riscos/env
+ endif
+ endif
+ ifeq ($(origin GCCSDK_INSTALL_CROSSBIN),undefined)
+ ifneq ($(realpath /opt/netsurf/arm-unknown-riscos/cross/bin),)
+ GCCSDK_INSTALL_CROSSBIN := /opt/netsurf/arm-unknown-riscos/cross/bin
+ else
+ GCCSDK_INSTALL_CROSSBIN := /home/riscos/cross/bin
+ endif
+ endif
+
+ CCRES := $(GCCSDK_INSTALL_CROSSBIN)/ccres
+ TPLEXT := ,fec
+ MAKERUN := $(GCCSDK_INSTALL_CROSSBIN)/makerun
+ SQUEEZE := $(GCCSDK_INSTALL_CROSSBIN)/squeeze
+ RUNEXT := ,feb
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ ifneq (,$(findstring arm-unknown-riscos-gcc,$(CC)))
+ SUBTARGET := -elf
+ EXEEXT := ,e1f
+ ELF2AIF := $(GCCSDK_INSTALL_CROSSBIN)/elf2aif
+ else
+ SUBTARGET := -aof
+ EXEEXT := ,ff8
+ endif
+ CXX := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*g++)
+ PKG_CONFIG := $(GCCSDK_INSTALL_ENV)/ro-pkg-config
+endif
diff --git a/frontends/riscos/buffer.c b/frontends/riscos/buffer.c
index c63a270db..9c8f8fe11 100644
--- a/frontends/riscos/buffer.c
+++ b/frontends/riscos/buffer.c
@@ -81,7 +81,7 @@ static os_mode mode;
*
* \param redraw the current WIMP redraw area to buffer
*/
-void ro_gui_buffer_open(wimp_draw *redraw)
+void ro_gui_buffer_open(const wimp_draw *redraw)
{
int size;
int total_size;
diff --git a/frontends/riscos/buffer.h b/frontends/riscos/buffer.h
index a683c324c..7de0ecdc6 100644
--- a/frontends/riscos/buffer.h
+++ b/frontends/riscos/buffer.h
@@ -25,7 +25,7 @@
#include "oslib/wimp.h"
-void ro_gui_buffer_open(wimp_draw *redraw);
+void ro_gui_buffer_open(const wimp_draw *redraw);
void ro_gui_buffer_close(void);
#endif
diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c
index 2ef05da29..88bb5c3ef 100644
--- a/frontends/riscos/corewindow.c
+++ b/frontends/riscos/corewindow.c
@@ -52,6 +52,8 @@
#define wimp_KEY_END wimp_KEY_COPY
#endif
+static struct ro_corewindow *ro_cw_drag_cw;
+
/**
* Update a windows scrollbars.
*
@@ -120,10 +122,15 @@ static void ro_cw_redraw(wimp_draw *redraw)
origin_x = redraw->box.x0 - redraw->xscroll;
origin_y = redraw->box.y1 + ro_cw->origin_y - redraw->yscroll;
- r.x0 = (redraw->clip.x0 - origin_x) / 2;
- r.y0 = (origin_y - redraw->clip.y1) / 2;
- r.x1 = r.x0 + ((redraw->clip.x1 - redraw->clip.x0) / 2);
- r.y1 = r.y0 + ((redraw->clip.y1 - redraw->clip.y0) / 2);
+ ro_plot_clip_rect.x0 = redraw->clip.x0 - origin_x;
+ ro_plot_clip_rect.y0 = origin_y - redraw->clip.y0;
+ ro_plot_clip_rect.x1 = redraw->clip.x1 - origin_x;
+ ro_plot_clip_rect.y1 = origin_y - redraw->clip.y1;
+
+ r.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ r.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ r.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ r.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
/* call the draw callback */
ro_cw->draw(ro_cw, origin_x, origin_y, &r);
@@ -250,6 +257,11 @@ static void ro_cw_mouse_at(wimp_pointer *pointer, void *data)
(unsigned int)pointer->w);
return;
}
+ if (ro_cw != ro_cw_drag_cw) {
+ NSLOG(netsurf, DEEPDEBUG, "Called without drag window: %p",
+ ro_cw);
+ return;
+ }
NSLOG(netsurf, INFO, "RO corewindow context %p", ro_cw);
/* Not a Menu click. */
@@ -386,6 +398,7 @@ ro_cw_drag_start(struct ro_corewindow *ro_cw,
ro_warn_user("WimpError", error->errmess);
}
+ ro_cw_drag_cw = ro_cw;
ro_mouse_drag_start(ro_cw_drag_end, ro_cw_mouse_at, NULL, NULL);
}
}
@@ -1041,6 +1054,8 @@ ro_corewindow_init(struct ro_corewindow *ro_cw,
}
/* setup context for event handlers */
+ NSLOG(netsurf, INFO, "Setting corewindow %p for window handle %p",
+ ro_cw, ro_cw->wh);
ro_gui_wimp_event_set_user_data(ro_cw->wh, ro_cw);
/* register wimp events. */
diff --git a/frontends/riscos/filetype.c b/frontends/riscos/filetype.c
index 73651cd63..b0dc949f8 100644
--- a/frontends/riscos/filetype.c
+++ b/frontends/riscos/filetype.c
@@ -39,6 +39,7 @@ static const struct type_entry type_map[] = {
{0x188, "application/x-shockwave-flash"},
{0x695, "image/gif"},
{0x69c, "image/x-ms-bmp"},
+ {0xa66, "image/webp"},
{0xaad, "image/svg+xml"},
{0xaff, "image/x-drawfile"},
{0xb60, "image/png"},
@@ -269,6 +270,7 @@ int ro_content_native_type(struct hlcache_handle *c)
case FILETYPE_BMP: /* bmp */
case FILETYPE_ICO: /* ico */
case FILETYPE_PNG: /* png */
+ case FILETYPE_WEBP: /* webp */
case 0xff9: /* sprite */
return osfile_TYPE_SPRITE;
case FILETYPE_SVG: /* svg */
diff --git a/frontends/riscos/filetype.h b/frontends/riscos/filetype.h
index 4c45e7bd0..b9fca4d49 100644
--- a/frontends/riscos/filetype.h
+++ b/frontends/riscos/filetype.h
@@ -67,6 +67,9 @@
#ifndef FILETYPE_SVG
#define FILETYPE_SVG 0xaad
#endif
+#ifndef FILETYPE_WEBP
+#define FILETYPE_WEBP 0xa66
+#endif
/**
* Determine the MIME type of a local file.
diff --git a/frontends/riscos/global_history.c b/frontends/riscos/global_history.c
index 4f0dbd48c..51f5390cb 100644
--- a/frontends/riscos/global_history.c
+++ b/frontends/riscos/global_history.c
@@ -444,6 +444,9 @@ static nserror ro_global_history_init(void)
return res;
}
+ NSLOG(netsurf, INFO, "Created global history corewindow: %p",
+ &ncwin->core);
+
res = global_history_init(ncwin->core.cb_table,
(struct core_window *)ncwin);
if (res != NSERROR_OK) {
diff --git a/frontends/riscos/gui.c b/frontends/riscos/gui.c
index b0eb23256..cc12eaccb 100644
--- a/frontends/riscos/gui.c
+++ b/frontends/riscos/gui.c
@@ -827,6 +827,7 @@ static void ro_msg_dataload(wimp_message *message)
case osfile_TYPE_TEXT:
case FILETYPE_ARTWORKS:
case FILETYPE_SVG:
+ case FILETYPE_WEBP:
/* display the actual file */
error = netsurf_path_to_nsurl(message->data.data_xfer.file_name, &url);
break;
@@ -929,7 +930,8 @@ static void ro_msg_datasave(wimp_message *message)
case osfile_TYPE_SPRITE:
case osfile_TYPE_TEXT:
case FILETYPE_ARTWORKS:
- case FILETYPE_SVG: {
+ case FILETYPE_SVG:
+ case FILETYPE_WEBP: {
os_error *error;
dataxfer->your_ref = dataxfer->my_ref;
diff --git a/frontends/riscos/gui.h b/frontends/riscos/gui.h
index 831c57dc7..5ff17e922 100644
--- a/frontends/riscos/gui.h
+++ b/frontends/riscos/gui.h
@@ -165,6 +165,7 @@ void ro_gui_print_prepare(struct gui_window *g);
extern const struct plotter_table ro_plotters;
extern int ro_plot_origin_x;
extern int ro_plot_origin_y;
+extern struct rect ro_plot_clip_rect;
/* in theme_install.c */
bool ro_gui_theme_install_apply(wimp_w w);
diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c
index 2b306827d..e38e746cd 100644
--- a/frontends/riscos/plotters.c
+++ b/frontends/riscos/plotters.c
@@ -39,6 +39,7 @@
int ro_plot_origin_x = 0;
int ro_plot_origin_y = 0;
+struct rect ro_plot_clip_rect;
/** One version of the A9home OS is incapable of drawing patterned lines */
bool ro_plot_patterned_lines = true;
@@ -110,12 +111,25 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
os_error *error;
char buf[12];
- int clip_x0 = ro_plot_origin_x + clip->x0 * 2;
- int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1;
- int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1;
- int clip_y1 = ro_plot_origin_y - clip->y1 * 2;
-
- if (clip_x1 < clip_x0 || clip_y0 < clip_y1) {
+ int clip_x0 = clip->x0 * 2;
+ int clip_y0 = clip->y1 * 2;
+ int clip_x1 = clip->x1 * 2;
+ int clip_y1 = clip->y0 * 2;
+
+ /* Avoid artefacts due to clip rectangle offsetting in EX0 EY0 modes.
+ * The area the WIMP asked us to draw might have dimensions that are
+ * not a multiple of 2. */
+ if (clip_x0 < ro_plot_clip_rect.x0) clip_x0 = ro_plot_clip_rect.x0;
+ if (clip_x1 > ro_plot_clip_rect.x1) clip_x1 = ro_plot_clip_rect.x1;
+ if (clip_y0 > ro_plot_clip_rect.y0) clip_y0 = ro_plot_clip_rect.y0;
+ if (clip_y1 < ro_plot_clip_rect.y1) clip_y1 = ro_plot_clip_rect.y1;
+
+ clip_x0 = ro_plot_origin_x + clip_x0;
+ clip_y0 = ro_plot_origin_y - clip_y0;
+ clip_x1 = ro_plot_origin_x + clip_x1 - 1;
+ clip_y1 = ro_plot_origin_y - clip_y1 - 1;
+
+ if (clip_x1 < clip_x0 || clip_y1 < clip_y0) {
NSLOG(netsurf, INFO, "bad clip rectangle %i %i %i %i",
clip_x0, clip_y0, clip_x1, clip_y1);
return NSERROR_BAD_SIZE;
@@ -124,12 +138,12 @@ ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip)
buf[0] = os_VDU_SET_GRAPHICS_WINDOW;
buf[1] = clip_x0;
buf[2] = clip_x0 >> 8;
- buf[3] = clip_y1;
- buf[4] = clip_y1 >> 8;
+ buf[3] = clip_y0;
+ buf[4] = clip_y0 >> 8;
buf[5] = clip_x1;
buf[6] = clip_x1 >> 8;
- buf[7] = clip_y0;
- buf[8] = clip_y0 >> 8;
+ buf[7] = clip_y1;
+ buf[8] = clip_y1 >> 8;
error = xos_writen(buf, 9);
if (error) {
@@ -365,7 +379,7 @@ ro_plot_rectangle(const struct redraw_context *ctx,
error = xos_plot(os_MOVE_TO,
ro_plot_origin_x + rect->x0 * 2,
- ro_plot_origin_y - rect->y0 * 2 - 1);
+ ro_plot_origin_y - rect->y1 * 2);
if (error) {
NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
error->errnum, error->errmess);
@@ -374,7 +388,7 @@ ro_plot_rectangle(const struct redraw_context *ctx,
error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO,
ro_plot_origin_x + rect->x1 * 2 - 1,
- ro_plot_origin_y - rect->y1 * 2);
+ ro_plot_origin_y - rect->y0 * 2 - 1);
if (error) {
NSLOG(netsurf, INFO, "xos_plot: 0x%x: %s",
error->errnum, error->errmess);
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index f1728afce..28ef06fa9 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -1639,6 +1639,57 @@ static void ro_gui_window_close(wimp_w w)
}
}
+/**
+ * Wrapper for calls to browser_window_redraw for a wimp_draw rectangle.
+ *
+ * \param[in] gui_win Window to render.
+ * \param[in] wimp_rect The area of gui_win to render into.
+ * \param[in] use_buffer Whether to use buffered rendering.
+ */
+static inline void ro_gui_window__redraw_rect(
+ const struct gui_window *gui_win,
+ const wimp_draw *wimp_rect,
+ bool use_buffer)
+{
+ struct redraw_context ctx = {
+ .interactive = true,
+ .background_images = true,
+ .plot = &ro_plotters
+ };
+ struct rect clip;
+
+ /* OS's redraw request coordinates are in screen coordinates,
+ * with an origin at the bottom left of the screen.
+ * Find the coordinate of the top left of the document in terms
+ * of OS screen coordinates.
+ * NOTE: OS units are 2 per px. */
+ ro_plot_origin_x = wimp_rect->box.x0 - wimp_rect->xscroll;
+ ro_plot_origin_y = wimp_rect->box.y1 - wimp_rect->yscroll;
+
+ /* Adjust clip rect for origin. */
+ ro_plot_clip_rect.x0 = wimp_rect->clip.x0 - ro_plot_origin_x;
+ ro_plot_clip_rect.y0 = ro_plot_origin_y - wimp_rect->clip.y0;
+ ro_plot_clip_rect.x1 = wimp_rect->clip.x1 - ro_plot_origin_x;
+ ro_plot_clip_rect.y1 = ro_plot_origin_y - wimp_rect->clip.y1;
+
+ /* Convert OS redraw rectangle request coordinates into NetSurf
+ * coordinates. NetSurf coordinates have origin at top left of
+ * document and units are in px. */
+ clip.x0 = (ro_plot_clip_rect.x0 ) / 2; /* left */
+ clip.y0 = (ro_plot_clip_rect.y1 ) / 2; /* top */
+ clip.x1 = (ro_plot_clip_rect.x1 + 1) / 2; /* right */
+ clip.y1 = (ro_plot_clip_rect.y0 + 1) / 2; /* bottom */
+
+ if (use_buffer) {
+ ro_gui_buffer_open(wimp_rect);
+ }
+
+ browser_window_redraw(gui_win->bw, 0, 0, &clip, &ctx);
+
+ if (use_buffer) {
+ ro_gui_buffer_close();
+ }
+}
/**
* Handle a Redraw_Window_Request for a browser window.
@@ -1650,11 +1701,6 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
osbool more;
struct gui_window *g;
os_error *error;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
g = (struct gui_window *)ro_gui_wimp_event_get_user_data(redraw->w);
@@ -1675,31 +1721,8 @@ static void ro_gui_window_redraw(wimp_draw *redraw)
return;
}
while (more) {
- struct rect clip;
-
- /* OS's redraw request coordinates are in screen coordinates,
- * with an origin at the bottom left of the screen.
- * Find the coordinate of the top left of the document in terms
- * of OS screen coordinates.
- * NOTE: OS units are 2 per px. */
- ro_plot_origin_x = redraw->box.x0 - redraw->xscroll;
- ro_plot_origin_y = redraw->box.y1 - redraw->yscroll;
-
- /* Convert OS redraw rectangle request coordinates into NetSurf
- * coordinates. NetSurf coordinates have origin at top left of
- * document and units are in px. */
- clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2; /* left */
- clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2; /* top */
- clip.x1 = (redraw->clip.x1 - ro_plot_origin_x) / 2; /* right */
- clip.y1 = (ro_plot_origin_y - redraw->clip.y0) / 2; /* bottom */
-
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_open(redraw);
-
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
-
- if (ro_gui_current_redraw_gui->option.buffer_everything)
- ro_gui_buffer_close();
+ ro_gui_window__redraw_rect(g, redraw,
+ ro_gui_current_redraw_gui->option.buffer_everything);
/* Check to see if there are more rectangles to draw and
* get next one */
@@ -4670,22 +4693,15 @@ void ro_gui_window_redraw_all(void)
}
}
-
/* exported interface documented in riscos/window.h */
void ro_gui_window_update_boxes(void)
{
osbool more;
bool use_buffer;
wimp_draw update;
- struct rect clip;
os_error *error;
struct update_box *cur;
struct gui_window *g;
- struct redraw_context ctx = {
- .interactive = true,
- .background_images = true,
- .plot = &ro_plotters
- };
for (cur = pending_updates; cur != NULL; cur = cur->next) {
g = cur->g;
@@ -4711,22 +4727,8 @@ void ro_gui_window_update_boxes(void)
/* Set the current redraw gui_window to get options from */
ro_gui_current_redraw_gui = g;
- ro_plot_origin_x = update.box.x0 - update.xscroll;
- ro_plot_origin_y = update.box.y1 - update.yscroll;
-
while (more) {
- clip.x0 = (update.clip.x0 - ro_plot_origin_x) / 2;
- clip.y0 = (ro_plot_origin_y - update.clip.y1) / 2;
- clip.x1 = (update.clip.x1 - ro_plot_origin_x) / 2;
- clip.y1 = (ro_plot_origin_y - update.clip.y0) / 2;
-
- if (use_buffer)
- ro_gui_buffer_open(&update);
-
- browser_window_redraw(g->bw, 0, 0, &clip, &ctx);
-
- if (use_buffer)
- ro_gui_buffer_close();
+ ro_gui_window__redraw_rect(g, &update, use_buffer);
error = xwimp_get_rectangle(&update, &more);
/* RISC OS 3.7 returns an error here if enough buffer
diff --git a/frontends/windows/Makefile.tools b/frontends/windows/Makefile.tools
new file mode 100644
index 000000000..24f0f7fbd
--- /dev/null
+++ b/frontends/windows/Makefile.tools
@@ -0,0 +1,19 @@
+# -*- mode: makefile-gmake -*-
+##
+## windows (win32) target tool setup
+##
+
+ifneq ($(HOST),windows)
+ # Set Mingw defaults
+ GCCSDK_INSTALL_ENV ?= /opt/netsurf/i686-w64-mingw32/env
+ GCCSDK_INSTALL_CROSSBIN ?= /opt/netsurf/i686-w64-mingw32/cross/bin
+
+ CC := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*gcc)
+ WINDRES := $(wildcard $(GCCSDK_INSTALL_CROSSBIN)/*windres)
+
+ PKG_CONFIG := PKG_CONFIG_LIBDIR="$(GCCSDK_INSTALL_ENV)/lib/pkgconfig" pkg-config
+else
+ # Building on Windows
+ CC := gcc
+ PKG_CONFIG := pkg-config
+endif
diff --git a/include/netsurf/bitmap.h b/include/netsurf/bitmap.h
index a85efce99..f5de51423 100644
--- a/include/netsurf/bitmap.h
+++ b/include/netsurf/bitmap.h
@@ -143,14 +143,14 @@ struct gui_bitmap_table {
int (*get_height)(void *bitmap);
/**
- * The the *bytes* per pixel.
+ * Get the *bytes* per pixel.
*
* \param bitmap The bitmap
*/
size_t (*get_bpp)(void *bitmap);
/**
- * Savde a bitmap to disc.
+ * Save a bitmap to disc.
*
* \param bitmap The bitmap to save
* \param path The path to save the bitmap to.
diff --git a/include/netsurf/fetch.h b/include/netsurf/fetch.h
index 6e6d653ee..30b204868 100644
--- a/include/netsurf/fetch.h
+++ b/include/netsurf/fetch.h
@@ -49,15 +49,15 @@ struct gui_fetch_table {
/**
* Translate resource to full url.
*
- * @note Only used in resource fetcher
+ * @note Only used in resource protocol fetcher
*
- * Transforms a resource: path into a full URL. The returned URL
+ * Transforms a resource protocol path into a full URL. The returned URL
* is used as the target for a redirect. The caller takes ownership of
* the returned nsurl including unrefing it when finished with it.
*
* \param path The path of the resource to locate.
- * \return A string containing the full URL of the target object or
- * NULL if no suitable resource can be found.
+ * \return A netsurf url object containing the full URL of the resource
+ * path or NULL if a suitable resource URL can not be generated.
*/
struct nsurl* (*get_resource_url)(const char *path);
diff --git a/resources/default.css b/resources/default.css
index 276bc1554..fa47c76ff 100644
--- a/resources/default.css
+++ b/resources/default.css
@@ -50,9 +50,9 @@ pre { display: block; font-family: monospace; white-space: pre; margin-bottom: 1
ins { color: green; text-decoration: underline; }
del { color: red; text-decoration: line-through; }
-ul { display: block; padding-left: 1.5em; margin: 1.12em 0;
+ul { display: block; padding-left: 40px; margin: 1.12em 0;
list-style-type: disc; }
-ol { display: block; padding-left: 1.5em; margin: 1.12em 0;
+ol { display: block; padding-left: 40px; margin: 1.12em 0;
list-style-type: decimal; }
li { display: list-item; }
diff --git a/test/corestrings.c b/test/corestrings.c
index aaa23e4d0..43eb5130e 100644
--- a/test/corestrings.c
+++ b/test/corestrings.c
@@ -40,7 +40,7 @@
*
* This is used to test all the out of memory paths in initialisation.
*/
-#define CORESTRING_TEST_COUNT 483
+#define CORESTRING_TEST_COUNT 487
START_TEST(corestrings_test)
{
diff --git a/test/monkey_driver.py b/test/monkey_driver.py
index 606530e81..9b810d2a6 100755
--- a/test/monkey_driver.py
+++ b/test/monkey_driver.py
@@ -436,13 +436,26 @@ def run_test_step_action_plot_check(ctx, step):
print(get_indent(ctx) + "Action: " + step["action"])
assert_browser(ctx)
win = ctx['windows'][step['window']]
+
+ if 'area' in step.keys():
+ if step["area"] == "extent":
+ # ought to capture the extent updates and use that, instead use a
+ # big area and have the browser clip it
+ area=["0","0","1000","1000000"]
+ else:
+ area = [step["area"]]
+ else:
+ area = None
+
+ # get the list of checks
if 'checks' in step.keys():
checks = step['checks']
else:
checks = {}
+
all_text_list = []
bitmaps = []
- for plot in win.redraw():
+ for plot in win.redraw(coords=area):
if plot[0] == 'TEXT':
all_text_list.extend(plot[6:])
if plot[0] == 'BITMAP':
diff --git a/tools/convert_font.c b/tools/convert_font.c
index 9f5734b71..d22c85920 100644
--- a/tools/convert_font.c
+++ b/tools/convert_font.c
@@ -290,14 +290,14 @@ static bool generate_font_header(const char *path, struct font_data *data)
for (s = 0; s < 4; s++) {
- fprintf(fp, "const uint8_t *%s_section_table;\n",
+ fprintf(fp, "extern const uint8_t *%s_section_table;\n",
var_lables[s]);
- fprintf(fp, "const uint16_t *%s_sections;\n",
+ fprintf(fp, "extern const uint16_t *%s_sections;\n",
var_lables[s]);
}
- fprintf(fp, "const uint8_t *font_glyph_data;\n");
+ fprintf(fp, "extern const uint8_t *font_glyph_data;\n");
fprintf(fp, "\n\n");
diff --git a/utils/corestringlist.h b/utils/corestringlist.h
index d6be3c4c1..b253b3b56 100644
--- a/utils/corestringlist.h
+++ b/utils/corestringlist.h
@@ -295,6 +295,7 @@ CORESTRING_DOM_STRING(rect);
CORESTRING_DOM_STRING(rel);
CORESTRING_DOM_STRING(reset);
CORESTRING_DOM_STRING(resize);
+CORESTRING_DOM_STRING(reversed);
CORESTRING_DOM_STRING(rows);
CORESTRING_DOM_STRING(rowspan);
CORESTRING_DOM_STRING(scroll);
@@ -309,6 +310,7 @@ CORESTRING_DOM_STRING(size);
CORESTRING_DOM_STRING(sizes);
CORESTRING_DOM_STRING(src);
CORESTRING_DOM_STRING(stalled);
+CORESTRING_DOM_STRING(start);
CORESTRING_DOM_STRING(storage);
CORESTRING_DOM_STRING(style);
CORESTRING_DOM_STRING(submit);