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 *);