diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000000..73cbf256df87
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,21 @@
+language: c
+compiler: clang
+
+addons:
+ apt:
+ update: true
+ packages:
+ - libxml2-dev
+ - libgtk-3-dev
+ - libxpm-dev
+ - libgif-dev
+ - libgnutls-dev
+
+jobs:
+ include:
+ - os: osx
+ before_script: ./autogen.sh && ./configure --without-makeinfo --with-ns --without-xml2
+ script: make -j8
+ - os: linux
+ before_script: ./autogen.sh && ./configure --without-makeinfo --with-x --with-x-toolkit=gtk3
+ script: make -j8
diff --git a/README b/README.emacs
similarity index 100%
rename from README
rename to README.emacs
diff --git a/README.md b/README.md
new file mode 100644
index 000000000000..c8a4fd853db6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,26 @@
+# EmacsMoe Patchset
+
+The original README is `README.emacs`.
+
+This patchset tries to introduce modern visual effects to Emacs. Like
+them or not, implementing them is a fun weekend project.
+
+## Help wanted!
+
+1. As you know, Emacs supports a variety of GUI platforms. I'm familiar
+ with none of them! Right now, I have only Linux and macOS
+ environments, so at least someone with Windows expertise is wanted.
+2. There may be design flaws. Please don't hesitate to bring forth
+ your idea.
+
+## Implemented features
+
+Nothing so far.
+
+## WIP
+
+- Colorful Shadows. [Like this one.](https://marketplace.visualstudio.com/items?itemName=webrender.synthwave-x-fluoromachine)
+
+## Planned
+
+- Background images.
diff --git a/configure.ac b/configure.ac
index 4456cd89b7a7..e8bb6ea62f3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4383,6 +4383,7 @@ if test "${HAVE_X11}" = "yes"; then
fi
HAVE_CAIRO=no
+CAIRO_OBJ=""
if test "${HAVE_X11}" = "yes"; then
if test "${with_cairo}" != "no"; then
CAIRO_REQUIRED=1.8.0
@@ -4400,8 +4401,10 @@ if test "${HAVE_X11}" = "yes"; then
AC_DEFINE([USE_CAIRO], [1], [Define to 1 if using cairo.])
CFLAGS="$CFLAGS $CAIRO_CFLAGS"
LIBS="$LIBS $CAIRO_LIBS"
+ CAIRO_OBJ="xcairo.o"
AC_SUBST([CAIRO_CFLAGS])
AC_SUBST([CAIRO_LIBS])
+ AC_SUBST([CAIRO_OBJ])
else
AC_MSG_WARN([cairo requested but not found.])
fi
@@ -4469,8 +4472,10 @@ if test "$window_system" = "pgtk"; then
CFLAGS="$CFLAGS $CAIRO_CFLAGS"
LIBS="$LIBS $CAIRO_LIBS"
+ CAIRO_OBJ="xcairo.o"
AC_SUBST([CAIRO_CFLAGS])
AC_SUBST([CAIRO_LIBS])
+ AC_SUBST([CAIRO_OBJ])
fi
if test "${HAVE_BE_APP}" = "yes"; then
@@ -4482,8 +4487,10 @@ if test "${HAVE_BE_APP}" = "yes"; then
AC_DEFINE([USE_BE_CAIRO], [1], [Define to 1 if using cairo on Haiku.])
CFLAGS="$CFLAGS $CAIRO_CFLAGS"
LIBS="$LIBS $CAIRO_LIBS"
+ CAIRO_OBJ="xcairo.o"
AC_SUBST([CAIRO_CFLAGS])
AC_SUBST([CAIRO_LIBS])
+ AC_SUBST([CAIRO_OBJ])
else
AC_MSG_WARN([cairo requested but not found.])
fi
diff --git a/lisp/faces.el b/lisp/faces.el
index 7eacc40443a3..cc2601be0c0d 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -1256,6 +1256,7 @@ an integer value."
(:height . "height in 1/10 pt")
(:weight . "weight")
(:slant . "slant")
+ (:shadow . "shadow")
(:underline . "underline")
(:overline . "overline")
(:extend . "extend")
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index e93c535bbef2..b6b6fa231451 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -1835,6 +1835,7 @@ If FRAME is omitted or nil, use the selected frame."
(:foreground . "Foreground")
(:distant-foreground . "DistantForeground")
(:background . "Background")
+ (:shadow . "Shadow")
(:underline . "Underline")
(:overline . "Overline")
(:strike-through . "Strike-through")
diff --git a/moe/shadow-demo.el b/moe/shadow-demo.el
new file mode 100644
index 000000000000..aec7dfb58492
--- /dev/null
+++ b/moe/shadow-demo.el
@@ -0,0 +1,8 @@
+;; To see the effect of text shadows, use the command:
+;; emacs -q -l moe/shadow-demo.el
+
+(set-face-attribute 'font-lock-function-name-face nil :shadow '(5.0 . "red"))
+(set-face-attribute 'font-lock-variable-name-face nil :shadow '(5.0 . "green"))
+(set-face-attribute 'font-lock-keyword-face nil :shadow '(5.0 . "yellow"))
+(set-face-attribute 'font-lock-type-face nil :shadow '5.0)
+(set-face-attribute 'default nil :shadow '(5.0 nil 2 . 2))
diff --git a/src/Makefile.in b/src/Makefile.in
index b14681f2537c..de3f02461fd6 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -252,6 +252,7 @@ WEBKIT_CFLAGS= @WEBKIT_CFLAGS@
CAIRO_LIBS= @CAIRO_LIBS@
CAIRO_CFLAGS= @CAIRO_CFLAGS@
+CAIRO_OBJ= @CAIRO_OBJ@
IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@
IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@
@@ -480,7 +481,7 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
$(if $(HYBRID_MALLOC),sheap.o) \
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
$(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ) $(JSON_OBJ) \
- $(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ)
+ $(HAIKU_OBJ) $(PGTK_OBJ) $(ANDROID_OBJ) $(CAIRO_OBJ)
doc_obj = $(base_obj) $(NS_OBJC_OBJ)
obj = $(doc_obj) $(HAIKU_CXX_OBJ)
diff --git a/src/dispextern.h b/src/dispextern.h
index 3a4d6095f734..8e72a803764f 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1652,6 +1652,7 @@ enum lface_attribute_index
LFACE_HEIGHT_INDEX,
LFACE_WEIGHT_INDEX,
LFACE_SLANT_INDEX,
+ LFACE_SHADOW_INDEX,
LFACE_UNDERLINE_INDEX,
LFACE_INVERSE_INDEX,
LFACE_FOREGROUND_INDEX,
@@ -1737,11 +1738,12 @@ struct face
unsigned long background;
/* Pixel value or color index of underline, overlined,
- strike-through, or box color. */
+ strike-through, box color, or shadow color. */
unsigned long underline_color;
unsigned long overline_color;
unsigned long strike_through_color;
unsigned long box_color;
+ unsigned long shadow_color;
struct font *font;
@@ -1783,9 +1785,16 @@ struct face
bool_bf use_box_color_for_shadows_p : 1;
/* Non-zero if text in this face should be underlined, overlined,
- strike-through or have a box drawn around it. */
+ strike-through, have a box drawn around it, or have shadows. */
bool_bf overline_p : 1;
bool_bf strike_through_p : 1;
+ bool_bf shadow_p : 1;
+
+ /* The blur parameter of the shadow. */
+ double shadow_blur;
+
+ /* Shadow offset. In most cases, both fields are taken to be zero. */
+ struct { short x, y; } shadow_offset;
/* True means that the colors specified for this face could not be
loaded, and were replaced by default colors, so they shouldn't be
@@ -1800,6 +1809,7 @@ struct face
bool_bf overline_color_defaulted_p : 1;
bool_bf strike_through_color_defaulted_p : 1;
bool_bf box_color_defaulted_p : 1;
+ bool_bf shadow_color_defaulted_p : 1;
/* True means the underline should be drawn at the descent line. */
bool_bf underline_at_descent_line_p : 1;
diff --git a/src/ftcrfont.c b/src/ftcrfont.c
index 49564692b750..b40aaee5c5c9 100644
--- a/src/ftcrfont.c
+++ b/src/ftcrfont.c
@@ -16,6 +16,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see . */
+#include
#include
#include
@@ -41,11 +42,11 @@ along with GNU Emacs. If not, see . */
#include "xsettings.h"
#endif
-#ifdef USE_BE_CAIRO
+#include "xcairo.h"
+
#define RED_FROM_ULONG(color) (((color) >> 16) & 0xff)
#define GREEN_FROM_ULONG(color) (((color) >> 8) & 0xff)
#define BLUE_FROM_ULONG(color) ((color) & 0xff)
-#endif
#define METRICS_NCOLS_PER_ROW (128)
@@ -529,16 +530,11 @@ ftcrfont_variation_glyphs (struct font *font, int c, unsigned variations[256])
}
#endif /* HAVE_OTF_GET_VARIATION_GLYPHS || HAVE_FT_FACE_GETCHARVARIANTINDEX */
-static int
-ftcrfont_draw (struct glyph_string *s,
- int from, int to, int x, int y, bool with_background)
+static void
+ftcrfont_select_foreground_color (struct frame *f,
+ cairo_t *cr,
+ struct glyph_string *s)
{
- struct frame *f = s->f;
- struct font_info *ftcrfont_info = (struct font_info *) s->font;
- cairo_t *cr;
- cairo_glyph_t *glyphs;
- int len = to - from;
- int i;
#ifdef USE_BE_CAIRO
unsigned long be_foreground, be_background;
@@ -552,6 +548,101 @@ ftcrfont_draw (struct glyph_string *s,
&be_background);
#endif
+#ifndef USE_BE_CAIRO
+#ifdef HAVE_X_WINDOWS
+ x_set_other_cr_source_with_gc_foreground (f, s->gc, cr, false);
+#else
+ pgtk_set_other_cr_source_with_color (f, cr, s->xgcv.foreground, false);
+#endif
+#else
+ uint32_t col = be_foreground;
+
+ cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
+ GREEN_FROM_ULONG (col) / 255.0,
+ BLUE_FROM_ULONG (col) / 255.0);
+#endif
+}
+
+/* Select the proper foreground color (source) before calling this. */
+static void
+ftcrfont_show_glyphs (struct glyph_string *s, cairo_t *cr,
+ int from, int to, int x, int y)
+{
+ struct font_info *ftcrfont_info = (struct font_info *) s->font;
+ int len = to - from;
+ cairo_glyph_t *glyphs;
+ int i;
+
+ glyphs = alloca (sizeof (cairo_glyph_t) * len);
+ for (i = 0; i < len; i++)
+ {
+ glyphs[i].index = s->char2b[from + i];
+ glyphs[i].x = x;
+ glyphs[i].y = y;
+ x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font,
+ glyphs[i].index,
+ NULL));
+ }
+
+ cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font);
+ cairo_show_glyphs (cr, glyphs, len);
+}
+
+static void
+ftcrfont_draw_shadow (struct glyph_string *s, cairo_t *frame_cr,
+ int from, int to, int x, int y, bool save)
+{
+ cairo_surface_t *surface;
+ cairo_t *dc;
+
+ int x1, y1, w1, h1;
+ unsigned long col;
+ int margin;
+
+ margin = (int) ceil (s->face->shadow_blur);
+ w1 = s->width + margin;
+ h1 = FONT_HEIGHT (s->font) + margin;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w1, h1);
+ dc = cairo_create (surface);
+
+ if (s->face->shadow_color_defaulted_p)
+ col = s->face->foreground;
+ else
+ col = s->face->shadow_color;
+
+ cairo_set_source_rgb (dc,
+ RED_FROM_ULONG (col) / 255.0,
+ GREEN_FROM_ULONG (col) / 255.0,
+ BLUE_FROM_ULONG (col) / 255.0);
+ cairo_set_operator (dc, CAIRO_OPERATOR_OVER);
+
+ ftcrfont_show_glyphs (s, dc, from, to, margin, FONT_BASE(s->font) + margin);
+ gaussian_blur (surface, w1, h1, s->face->shadow_blur / 2.0);
+
+ x1 = x + s->face->shadow_offset.x - margin;
+ y1 = y - FONT_BASE (s->font) + s->face->shadow_offset.y - margin;
+
+ if (save)
+ cairo_save (frame_cr);
+ cairo_set_source_surface (frame_cr, surface, x1, y1);
+ cairo_rectangle (frame_cr, x1, y1, w1, h1);
+ cairo_fill (frame_cr);
+ if (save)
+ cairo_restore (frame_cr);
+
+ cairo_destroy (dc);
+ cairo_surface_destroy (surface);
+}
+
+static int
+ftcrfont_draw (struct glyph_string *s,
+ int from, int to, int x, int y, bool with_background)
+{
+ struct frame *f = s->f;
+ cairo_t *cr;
+ int len = to - from;
+
block_input ();
#ifndef USE_BE_CAIRO
@@ -595,31 +686,19 @@ ftcrfont_draw (struct glyph_string *s,
cairo_fill (cr);
}
- glyphs = alloca (sizeof (cairo_glyph_t) * len);
- for (i = 0; i < len; i++)
- {
- glyphs[i].index = s->char2b[from + i];
- glyphs[i].x = x;
- glyphs[i].y = y;
- x += (s->padding_p ? 1 : ftcrfont_glyph_extents (s->font,
- glyphs[i].index,
- NULL));
- }
-#ifndef USE_BE_CAIRO
-#ifdef HAVE_X_WINDOWS
- x_set_cr_source_with_gc_foreground (f, s->gc, false);
+#if defined(HAVE_PGTK)
+ /* PGTK requires the foreground color to be selected BEFORE creating
+ the shadow layer. Hence we need to save and restore cairo_t. */
+ ftcrfont_select_foreground_color (f, cr, s);
+ if (s->face->shadow_p)
+ ftcrfont_draw_shadow (s, cr, from, to, x, y, true);
#else
- pgtk_set_cr_source_with_color (f, s->xgcv.foreground, false);
+ if (s->face->shadow_p)
+ ftcrfont_draw_shadow (s, cr, from, to, x, y, false);
+ ftcrfont_select_foreground_color (f, cr, s);
#endif
-#else
- uint32_t col = be_foreground;
+ ftcrfont_show_glyphs (s, cr, from, to, x, y);
- cairo_set_source_rgb (cr, RED_FROM_ULONG (col) / 255.0,
- GREEN_FROM_ULONG (col) / 255.0,
- BLUE_FROM_ULONG (col) / 255.0);
-#endif
- cairo_set_scaled_font (cr, ftcrfont_info->cr_scaled_font);
- cairo_show_glyphs (cr, glyphs, len);
#ifndef USE_BE_CAIRO
#ifdef HAVE_X_WINDOWS
x_end_cr_clip (f);
diff --git a/src/macfont.m b/src/macfont.m
index 9f9f6f4efaff..de63e9f446eb 100644
--- a/src/macfont.m
+++ b/src/macfont.m
@@ -2963,6 +2963,21 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
{
CGAffineTransform atfm;
+ if (face->shadow_p)
+ {
+ CGSize offset;
+ CGColorRef shadow_color;
+
+ offset = CGSizeMake (face->shadow_offset.x, - face->shadow_offset.y);
+ if (face->shadow_color_defaulted_p)
+ shadow_color = get_cgcolor (NS_FACE_FOREGROUND (face));
+ else
+ shadow_color = get_cgcolor (face->shadow_color);
+ CGContextSetShadowWithColor (context, offset, face->shadow_blur,
+ shadow_color);
+ CGColorRelease (shadow_color);
+ }
+
CGContextScaleCTM (context, 1, -1);
if (s->hl == DRAW_CURSOR)
{
@@ -2993,13 +3008,13 @@ So we use CTFontDescriptorCreateMatchingFontDescriptor (no
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
if ([[FRAME_NS_VIEW(f) window] respondsToSelector:
@selector(backingScaleFactor)])
-#endif
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1070
CGContextSetLineWidth (context, synthetic_bold_factor * font_size
* [[FRAME_NS_VIEW(f) window] backingScaleFactor]);
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
else
-#endif
-#endif
+#endif // MAC_OS_X_VERSION_MIN_REQUIRED < 1070
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
CGContextSetLineWidth (context, synthetic_bold_factor * font_size);
#endif
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index a7c687d811d4..399726332039 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -7259,8 +7259,9 @@ pgtk_set_cr_source_with_gc_background (struct frame *f, Emacs_GC *gc,
}
void
-pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
- bool respects_alpha_background)
+pgtk_set_other_cr_source_with_color (struct frame *f, cairo_t *cr,
+ unsigned long color,
+ bool respects_alpha_background)
{
Emacs_Color col;
col.pixel = color;
@@ -7268,19 +7269,26 @@ pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
if (!respects_alpha_background)
{
- cairo_set_source_rgb (FRAME_CR_CONTEXT (f), col.red / 65535.0,
+ cairo_set_source_rgb (cr, col.red / 65535.0,
col.green / 65535.0, col.blue / 65535.0);
- cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
}
else
{
- cairo_set_source_rgba (FRAME_CR_CONTEXT (f), col.red / 65535.0,
+ cairo_set_source_rgba (cr, col.red / 65535.0,
col.green / 65535.0, col.blue / 65535.0,
f->alpha_background);
- cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
}
}
+void
+pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
+ bool respects_alpha_background)
+{
+ pgtk_set_other_cr_source_with_color (f, FRAME_CR_CONTEXT (f), color, respects_alpha_background);
+}
+
void
pgtk_cr_draw_frame (cairo_t * cr, struct frame *f)
{
diff --git a/src/pgtkterm.h b/src/pgtkterm.h
index 069e425fd9c3..c08876e62e62 100644
--- a/src/pgtkterm.h
+++ b/src/pgtkterm.h
@@ -586,6 +586,7 @@ extern void pgtk_end_cr_clip (struct frame *);
extern void pgtk_set_cr_source_with_gc_foreground (struct frame *, Emacs_GC *, bool);
extern void pgtk_set_cr_source_with_gc_background (struct frame *, Emacs_GC *, bool);
extern void pgtk_set_cr_source_with_color (struct frame *, unsigned long, bool);
+extern void pgtk_set_other_cr_source_with_color (struct frame *, cairo_t *, unsigned long, bool);
extern void pgtk_cr_draw_frame (cairo_t *, struct frame *);
extern void pgtk_cr_destroy_frame_context (struct frame *);
extern Lisp_Object pgtk_cr_export_frames (Lisp_Object , cairo_surface_type_t);
diff --git a/src/xcairo.c b/src/xcairo.c
new file mode 100644
index 000000000000..7f0b6a83ec8c
--- /dev/null
+++ b/src/xcairo.c
@@ -0,0 +1,139 @@
+#include
+#include
+#include
+#include "xcairo.h"
+
+typedef unsigned char v4uc __attribute__((vector_size (4)));
+typedef float v4f __attribute__((vector_size (16)));
+
+#define NUM_BOXES 3
+
+static int *
+boxes_for_gaussian (double sigma)
+{
+ static double last_sigma = -0.0;
+ static int sizes[NUM_BOXES];
+ double wIdeal, mIdeal;
+ int wl, wu, m;
+ int n = NUM_BOXES;
+
+ if (sigma == last_sigma)
+ return sizes;
+ else
+ last_sigma = sigma;
+
+ wIdeal = sqrt ((12 * sigma * sigma / n) + 1);
+ wl = floor (wIdeal);
+ if (wl % 2 == 0)
+ wl --;
+ wu = wl + 2;
+
+ mIdeal = (12 * sigma * sigma - n * wl * wl - 4 * n * wl - 3 * n) / (- 4 * wl - 4);
+ m = round(mIdeal);
+
+ for (int i = 0; i < n; ++i)
+ sizes[i] = i < m ? wl : wu;
+ return sizes;
+}
+
+#define uc2f(v) (__builtin_convertvector((v), v4f) / 128.0f)
+#define f2uc(v) (__builtin_convertvector((v) * 128.0f, v4uc))
+#define scaled_mult4(v,x) f2uc(uc2f((v))*x)
+
+static void
+box_blur_h (v4uc *s, v4uc *t, int w, int h, int r)
+{
+ float iarr = 1.0f / (r + r + 1.0f);
+ for (int i = 0; i < h; ++i)
+ {
+ int ti = i * w, li = ti, ri = ti + r;
+ v4uc fv = s[ti], lv = s[ti+w-1];
+ v4f val = uc2f(fv) * (float)(r+1);
+ for(int j=0;j
+
+void box_blur (cairo_surface_t *s, cairo_surface_t *t, int w, int h, int r);
+void gaussian_blur (cairo_surface_t *s, int w, int h, double r);
+
+#endif /* EMACS_XCAIRO_H */
diff --git a/src/xfaces.c b/src/xfaces.c
index 96382e783973..ff82a266adf0 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -42,21 +42,24 @@ along with GNU Emacs. If not, see . */
8. Background color.
- 9. Whether or not characters should be underlined, and in what color.
+ 9. Whether or not characters should be decorated with shadows, in
+ what color, and where should them be placed.
- 10. Whether or not characters should be displayed in inverse video.
+ 10. Whether or not characters should be underlined, and in what color.
- 11. A background stipple, a bitmap.
+ 11. Whether or not characters should be displayed in inverse video.
- 12. Whether or not characters should be overlined, and in what color.
+ 12. A background stipple, a bitmap.
- 13. Whether or not characters should be strike-through, and in what
+ 13. Whether or not characters should be overlined, and in what color.
+
+ 14. Whether or not characters should be strike-through, and in what
color.
- 14. Whether or not a box should be drawn around characters, the box
+ 15. Whether or not a box should be drawn around characters, the box
type, and, for simple boxes, in what color.
- 15. Font-spec, or nil. This is a special attribute.
+ 16. Font-spec, or nil. This is a special attribute.
A font-spec is a collection of font attributes (specs).
@@ -68,17 +71,17 @@ along with GNU Emacs. If not, see . */
On the other hand, if one of the other font-related attributes are
specified, the corresponding specs in this attribute is set to nil.
- 16. A face name or list of face names from which to inherit attributes.
+ 17. A face name or list of face names from which to inherit attributes.
- 17. A fontset name. This is another special attribute.
+ 18. A fontset name. This is another special attribute.
A fontset is a mappings from characters to font-specs, and the
specs overwrite the font-spec in the 14th attribute.
- 18. A "distant background" color, to be used when the foreground is
+ 19. A "distant background" color, to be used when the foreground is
too close to the background and is hard to read.
- 19. Whether to extend the face to end of line when the face
+ 20. Whether to extend the face to end of line when the face
"covers" the newline that ends the line.
On the C level, a Lisp face is completely represented by its array
@@ -394,7 +397,7 @@ static void clear_face_gcs (struct face_cache *);
static struct face *realize_non_ascii_face (struct frame *, Lisp_Object,
struct face *);
#endif /* HAVE_WINDOW_SYSTEM */
-
+
/***********************************************************************
Utilities
***********************************************************************/
@@ -1761,6 +1764,7 @@ the WIDTH times as wide as FACE on FRAME. */)
#define LFACE_HEIGHT(LFACE) AREF ((LFACE), LFACE_HEIGHT_INDEX)
#define LFACE_WEIGHT(LFACE) AREF ((LFACE), LFACE_WEIGHT_INDEX)
#define LFACE_SLANT(LFACE) AREF ((LFACE), LFACE_SLANT_INDEX)
+#define LFACE_SHADOW(LFACE) AREF((LFACE), LFACE_SHADOW_INDEX)
#define LFACE_UNDERLINE(LFACE) AREF ((LFACE), LFACE_UNDERLINE_INDEX)
#define LFACE_INVERSE(LFACE) AREF ((LFACE), LFACE_INVERSE_INDEX)
#define LFACE_FOREGROUND(LFACE) AREF ((LFACE), LFACE_FOREGROUND_INDEX)
@@ -3246,6 +3250,46 @@ FRAME 0 means change the face on all frames, and change the default
ASET (lface, LFACE_SLANT_INDEX, value);
prop_index = FONT_SLANT_INDEX;
}
+ else if (EQ (attr, QCshadow))
+ {
+ bool valid_p = false;
+
+ /* TODO allow ignore-defface? */
+ if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value))
+ valid_p = true;
+ else if (NILP (value) || EQ (value, Qt))
+ valid_p = true;
+ else if (FLOATP (value))
+ valid_p = true;
+ else if (CONSP (value))
+ {
+ Lisp_Object blur, color, offsetx, offsety, temp;
+ blur = CAR (value);
+ temp = CDR (value);
+ if (NILP (temp) || STRINGP (temp) || SCHARS (temp) > 0)
+ valid_p = FLOATP (blur);
+ else if (CONSP (temp))
+ {
+ color = CAR (temp);
+ temp = CDR (temp);
+ offsetx = CAR (temp);
+ offsety = CDR (temp);
+ valid_p = FLOATP (blur)
+ && (NILP (color) || STRINGP (color) || SCHARS (color) > 0)
+ && FIXNUMP (offsetx) && FIXNUMP (offsety);
+ }
+ else
+ valid_p = false;
+ }
+
+ if (!valid_p)
+ signal_error ("Invalid text shadow", value);
+ else
+ {
+ old_value = LFACE_SHADOW (lface);
+ ASET (lface, LFACE_SHADOW_INDEX, value);
+ }
+ }
else if (EQ (attr, QCunderline))
{
bool valid_p = false;
@@ -4129,6 +4173,8 @@ frames). If FRAME is omitted or nil, use the selected frame. */)
value = LFACE_WEIGHT (lface);
else if (EQ (keyword, QCslant))
value = LFACE_SLANT (lface);
+ else if (EQ (keyword, QCshadow))
+ value = LFACE_SHADOW (lface);
else if (EQ (keyword, QCunderline))
value = LFACE_UNDERLINE (lface);
else if (EQ (keyword, QCoverline))
@@ -6085,7 +6131,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
#ifdef HAVE_WINDOW_SYSTEM
struct face *default_face;
struct frame *f;
- Lisp_Object stipple, underline, overline, strike_through, box;
+ Lisp_Object stipple, underline, overline, strike_through, box, shadow;
eassert (FRAME_WINDOW_P (cache->f));
@@ -6282,6 +6328,106 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
}
}
+ /* Text shadow */
+
+ shadow = attrs[LFACE_SHADOW_INDEX];
+ if (EQ (shadow, Qt))
+ {
+ /* Use the default parameters. */
+ face->shadow_p = true;
+ face->shadow_blur = 1.0;
+ face->shadow_color_defaulted_p = true;
+ face->shadow_offset.x = 0;
+ face->shadow_offset.y = 0;
+ }
+ else if (NILP (shadow))
+ {
+ face->shadow_p = false;
+ face->shadow_blur = 0.0;
+ face->shadow_color_defaulted_p = false;
+ face->shadow_offset.x = 0;
+ face->shadow_offset.y = 0;
+ }
+ else if (FLOATP (shadow))
+ {
+ face->shadow_p = true;
+ face->shadow_blur = XFLOAT_DATA (shadow);
+ face->shadow_color_defaulted_p = true;
+ face->shadow_offset.x = 0;
+ face->shadow_offset.y = 0;
+ }
+ else if (CONSP (shadow))
+ {
+ /* (blur . color) or (blur color offset) */
+ Lisp_Object blur, color, offset, rest;
+ blur = CAR (shadow);
+ if (FLOATP (blur))
+ {
+ face->shadow_p = true;
+ face->shadow_blur = XFLOAT_DATA (blur);
+ }
+ else
+ {
+ face->shadow_p = false;
+ add_to_log ("Invalid shadow blur value");
+ }
+
+ rest = CDR (shadow);
+ if (STRINGP (rest))
+ {
+ color = rest;
+ offset = Qnil;
+ rest = Qnil;
+ }
+ else if (CONSP (rest))
+ {
+ color = CAR (rest);
+ offset = CDR (rest);
+ if (CONSP (CAR (offset)) && NILP (CDR (offset)))
+ {
+ /* Be tolerant about something like (5.0 "color" (x . y)) */
+ offset = CAR (offset);
+ }
+ }
+ else
+ {
+ add_to_log ("Invalid shadow");
+ color = Qnil;
+ offset = Qnil;
+ }
+
+ if (STRINGP (color))
+ {
+ face->shadow_color_defaulted_p = false;
+ face->shadow_color = load_color (f, face, color,
+ LFACE_SHADOW_INDEX);
+ }
+ else
+ {
+ add_to_log ("Invalid shadow color");
+ face->shadow_color_defaulted_p = true;
+ }
+
+ if (NILP (offset))
+ {
+ face->shadow_offset.x = 0;
+ face->shadow_offset.y = 0;
+ }
+ else if (FIXNUMP (CAR (offset)) && FIXNUMP (CDR (offset)))
+ {
+ EMACS_INT x = XFIXNUM (CAR (offset)), y = XFIXNUM (CDR (offset));
+ if (x >= 128 || y >= 128 || x <= -127 || y <= -127)
+ add_to_log ("Invalid shadow offset");
+ else
+ {
+ face->shadow_offset.x = x;
+ face->shadow_offset.y = y;
+ }
+ }
+ else
+ add_to_log ("Invalid shadow offset");
+ }
+
/* Text underline, overline, strike-through. */
underline = attrs[LFACE_UNDERLINE_INDEX];
@@ -7180,6 +7326,7 @@ syms_of_xfaces (void)
DEFSYM (QCheight, ":height");
DEFSYM (QCweight, ":weight");
DEFSYM (QCslant, ":slant");
+ DEFSYM (QCshadow, ":shadow");
DEFSYM (QCunderline, ":underline");
DEFSYM (QCinverse_video, ":inverse-video");
DEFSYM (QCreverse_video, ":reverse-video");
diff --git a/src/xterm.c b/src/xterm.c
index 517bdf57aabf..543f9966d6f1 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -6055,8 +6055,9 @@ x_end_cr_clip (struct frame *f)
}
void
-x_set_cr_source_with_gc_foreground (struct frame *f, GC gc,
- bool respect_alpha_background)
+x_set_other_cr_source_with_gc_foreground (struct frame *f, GC gc,
+ cairo_t *cr,
+ bool respect_alpha_background)
{
XGCValues xgcv;
XColor color;
@@ -6070,20 +6071,29 @@ x_set_cr_source_with_gc_foreground (struct frame *f, GC gc,
if (f->alpha_background < 1.0 && depth == 32
&& respect_alpha_background)
{
- cairo_set_source_rgba (FRAME_CR_CONTEXT (f), color.red / 65535.0,
+ cairo_set_source_rgba (cr, color.red / 65535.0,
color.green / 65535.0, color.blue / 65535.0,
f->alpha_background);
- cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
}
else
{
- cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0,
+ cairo_set_source_rgb (cr, color.red / 65535.0,
color.green / 65535.0, color.blue / 65535.0);
- cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER);
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
}
}
+void
+x_set_cr_source_with_gc_foreground (struct frame *f, GC gc,
+ bool respect_alpha_background)
+{
+ x_set_other_cr_source_with_gc_foreground (f, gc,
+ FRAME_CR_CONTEXT (f),
+ respect_alpha_background);
+}
+
void
x_set_cr_source_with_gc_background (struct frame *f, GC gc,
bool respect_alpha_background)
diff --git a/src/xterm.h b/src/xterm.h
index cb477645bfaa..7bc35679e4a8 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1806,6 +1806,7 @@ extern void x_cr_destroy_frame_context (struct frame *);
extern void x_cr_update_surface_desired_size (struct frame *, int, int);
extern cairo_t *x_begin_cr_clip (struct frame *, GC);
extern void x_end_cr_clip (struct frame *);
+extern void x_set_other_cr_source_with_gc_foreground (struct frame *, GC, cairo_t *, bool);
extern void x_set_cr_source_with_gc_foreground (struct frame *, GC, bool);
extern void x_set_cr_source_with_gc_background (struct frame *, GC, bool);
extern void x_cr_draw_frame (cairo_t *, struct frame *);