From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Alan Third Newsgroups: gmane.emacs.devel Subject: Re: Linking to ImageMagick by default Date: Mon, 10 Dec 2018 22:09:44 +0000 Message-ID: <20181210220944.GA4793@breton.holly.idiocy.org> References: <20181205223901.GA5543@breton.holly.idiocy.org> <20181208183810.GA2465@breton.holly.idiocy.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="AhhlLboLdkugWU4S" Content-Transfer-Encoding: 8bit X-Trace: blaine.gmane.org 1544479680 32114 195.159.176.226 (10 Dec 2018 22:08:00 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Mon, 10 Dec 2018 22:08:00 +0000 (UTC) User-Agent: Mutt/1.10.1 (2018-07-13) Cc: Glenn Morris , Lars Ingebrigtsen , emacs-devel@gnu.org To: Paul Eggert Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Mon Dec 10 23:07:56 2018 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1gWTiU-0008FF-AE for ged-emacs-devel@m.gmane.org; Mon, 10 Dec 2018 23:07:54 +0100 Original-Received: from localhost ([::1]:34954 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gWTka-0001B1-Vu for ged-emacs-devel@m.gmane.org; Mon, 10 Dec 2018 17:10:05 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:56696) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gWTkU-0001Aw-2Q for emacs-devel@gnu.org; Mon, 10 Dec 2018 17:09:59 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gWTkS-0007Ru-Hm for emacs-devel@gnu.org; Mon, 10 Dec 2018 17:09:58 -0500 Original-Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]:39514) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gWTkQ-00077L-3h; Mon, 10 Dec 2018 17:09:54 -0500 Original-Received: by mail-wm1-x32c.google.com with SMTP id f81so220760wmd.4; Mon, 10 Dec 2018 14:09:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to :user-agent; bh=F0/dE3m+ySpaCriTmO0FjlIwisGLB2UbpOxOPFKKfOM=; b=T+Hy7wbkr1npedfTK5pb0gVRi4xlBmr7ndwV0dufYYqDaFW2Y0imHajTWJbzkAIdou xCWazJUpcZVXunSB4ng4NnPFEvhAV8I6O6ySw+oS6Zb2r8LCkoqOdhbmJFR5xsJQVjjU 2/lIZJBnZ6frEPuAsmCes6WRIEK2/8GsiThknASUYNd6aPKKWX9GFiQcPO2rv4TfuD4F zM6UWLyYLaIC30vZz+qLvZbF8aV0i7je3D+HV4z8LzlriPXuLSeu9DibT09c0o+EFPGn PbKmw5Gd1Zcmxjfiiv+1LPct+P2YiebtV+ly03kGAnYzDoheZOPAlNnO8jLoWVuWI6pE h6eg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :references:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=F0/dE3m+ySpaCriTmO0FjlIwisGLB2UbpOxOPFKKfOM=; b=hzZcz2C95XR9jDdBaiNtNHNl7hMCC3kKdAeXECy9aDQHXYZeo0wtJtA9wK3M5nr4cK qvBvQLdRZw8KWdaw5NYPt6hFLGZi5J3YxNpNZfhsCnY/k7nVmjD2XFoiYvOKq4CtuhA0 DANWNcOZlDdM6ijvi4YPj5wIVyzkAlkYpxpdjOp9A++NCmY6kIej4qTrHbQg7JbcsPiL kPGe0ItIACZmkksYYt1WJXMSCzFxFi7BDufIEXFkmgQsiqHhMOFfHqqDQ3gqrXwwOwzZ YP0Xs4x22oZ9J103AprthUrTnxKOO7MDy7aEN1iiQSMCZfYA2zeqG82tWdpoFwXkYKLv ixHA== X-Gm-Message-State: AA+aEWb60FXd7F+QdnSbEbyimgLFajv7ZjywUDRSRe64j0fb7ByHF55K 4hSGaZQ7WNYPqRZ7lqFbQPM= X-Google-Smtp-Source: AFSGD/XoJThGr+o+YPcY/JN/cx64Ny3kEduEAbZLDcCRdYSFYb7Q1y1yCieTSZBroft0ZCW4fau0NQ== X-Received: by 2002:a7b:ce17:: with SMTP id m23mr149424wmc.74.1544479788226; Mon, 10 Dec 2018 14:09:48 -0800 (PST) Original-Received: from breton.holly.idiocy.org (ip6-2001-08b0-03f8-8129-9023-b606-56d4-f721.holly.idiocy.org. [2001:8b0:3f8:8129:9023:b606:56d4:f721]) by smtp.gmail.com with ESMTPSA id s8sm9744069wrn.44.2018.12.10.14.09.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 10 Dec 2018 14:09:46 -0800 (PST) Content-Disposition: inline In-Reply-To: X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::32c X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:231749 Archived-At: --AhhlLboLdkugWU4S Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit On Sat, Dec 08, 2018 at 01:24:13PM -0800, Paul Eggert wrote: > Alan Third wrote: > > In case anyone cares, I looked into this and XRender would do the > > trick. I had a look at how to go about it, but as usual with X stuff > > it looks a fair bit more complicated than with NS (and Windows), and I > > don’t have a good X environment to play about in. > > I have an X environment (and a Wayland one too); could you please post any > code you wrote, if you think the idea is worth a try? The attached appears to somewhat work (at least on my incredibly slow atom laptop). It’s not really workable in its current form. It’s slow because it has to load the image each time due to the way image caching works. I think there are a number of other places we may need to replace XCopyArea. It doesn’t handle the case where XRender isn’t available. Nor with animated gifs in X. They’re fine in NS... ¯\_(ツ)_/¯ It also doesn’t play nice with imagemagick, so make sure to build --without-imagemagick. If we want to go with this method I’ll have to rewrite some of the image handling code. At the moment we create one ‘struct image’ per lisp image spec, and store the image in the image cache, but this means if the same image is displayed twice at two different sizes we load it twice and store it twice. OTOH, it’s the resized version that’s stored, so that might save memory if we assume people are mostly shrinking images. What I’ve done in the attached would work better if we only loaded the image once and didn’t tie it to an image spec, so we’d only keep one (full size) copy in memory, and just resize it on demand. I’m unsure how we’d go about detangling the image data from the image spec. It may be possible to use XRender (and NSImage resizing) when we load the image, and therefore work in the same way we do at the moment. -- Alan Third --AhhlLboLdkugWU4S Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="0001-Scaling-PoC.patch" >From e1969beea284022ab721b452a43736b49cf74ce3 Mon Sep 17 00:00:00 2001 From: Alan Third Date: Mon, 10 Dec 2018 19:43:08 +0000 Subject: [PATCH] Scaling PoC --- lisp/image.el | 2 -- src/dispextern.h | 7 +++++++ src/image.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ src/nsimage.m | 2 +- src/nsterm.m | 7 ++++--- src/xterm.c | 48 +++++++++++++++++++++++++++++++++++++-------- 6 files changed, 103 insertions(+), 14 deletions(-) diff --git a/lisp/image.el b/lisp/image.el index 74a23046e9..8989fceefd 100644 --- a/lisp/image.el +++ b/lisp/image.el @@ -982,8 +982,6 @@ image--get-image image)) (defun image--get-imagemagick-and-warn () - (unless (or (fboundp 'imagemagick-types) (featurep 'ns)) - (error "Cannot rescale images without ImageMagick support")) (let ((image (image--get-image))) (image-flush image) (when (fboundp 'imagemagick-types) diff --git a/src/dispextern.h b/src/dispextern.h index 4cd017603d..490cc10c6c 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -2987,6 +2987,13 @@ struct image /* Width and height of the image. */ int width, height; + /* Width and height of the image data. */ + int actual_width, actual_height; + + /* The scaling factor between the actual image data and the + output. */ + double scale; + /* These values are used for the rectangles displayed for images that can't be loaded. */ #define DEFAULT_IMAGE_WIDTH 30 diff --git a/src/image.c b/src/image.c index 633d66e7a7..8bda88a6ce 100644 --- a/src/image.c +++ b/src/image.c @@ -1748,6 +1748,55 @@ postprocess_image (struct frame *f, struct image *img) } +static void +set_image_size (struct image *img, Lisp_Object spec) +{ + Lisp_Object value; + int width = INT_MAX, height = INT_MAX; + double scale = 1; + + img->actual_width = img->width; + img->actual_height = img->height; + + value = image_spec_value (spec, QCscale, NULL); + if (NUMBERP (value)) + scale = XFLOATINT (value); + + /* Calculate the maximum width and height. */ + value = image_spec_value (spec, QCmax_width, NULL); + if (FIXNATP (value)) + width = XFIXNAT (value); + + value = image_spec_value (spec, QCmax_height, NULL); + if (FIXNATP (value)) + height = XFIXNAT (value); + + value = image_spec_value (spec, QCwidth, NULL); + if (FIXNATP (value)) + width = min (XFIXNAT (value) * scale, width); + + value = image_spec_value (spec, QCheight, NULL); + if (FIXNATP (value)) + height = min (XFIXNAT (value) * scale, height); + + /* Calculate the final scaling factor. */ + if (img->width * scale > width) + scale = (double) img->width / width; + + if (img->height * scale > height) + scale = (double) img->height / height; + + /* Set the final sizes. We always maintain the aspect ratio. */ + if (scale != 1) + { + img->width *= scale; + img->height *= scale; + } + + img->scale = scale; +} + + /* Return the id of image with Lisp specification SPEC on frame F. SPEC must be a valid Lisp image specification (see valid_image_p). */ @@ -1803,6 +1852,8 @@ lookup_image (struct frame *f, Lisp_Object spec) Lisp_Object ascent, margin, relief, bg; int relief_bound; + set_image_size (img, spec); + ascent = image_spec_value (spec, QCascent, NULL); if (FIXNUMP (ascent)) img->ascent = XFIXNAT (ascent); diff --git a/src/nsimage.m b/src/nsimage.m index 0ae1b88edd..cc3aceae69 100644 --- a/src/nsimage.m +++ b/src/nsimage.m @@ -126,7 +126,7 @@ Updated by Christian Limpach (chris@nice.ch) eImg = temp; } - [eImg setSizeFromSpec:XCDR (img->spec)]; + //[eImg setSizeFromSpec:XCDR (img->spec)]; size = [eImg size]; img->width = size.width; diff --git a/src/nsterm.m b/src/nsterm.m index 6c285f0abb..db357a9623 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3828,6 +3828,7 @@ Function modeled after x_draw_glyph_string_box (). NSRect br; struct face *face; NSColor *tdCol; + double scale = s->img->scale; NSTRACE ("ns_dumpglyphs_image"); @@ -3877,9 +3878,9 @@ Function modeled after x_draw_glyph_string_box (). { #ifdef NS_IMPL_COCOA NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height); - NSRect ir = NSMakeRect (s->slice.x, - s->img->height - s->slice.y - s->slice.height, - s->slice.width, s->slice.height); + NSRect ir = NSMakeRect (s->slice.x / scale, + (s->img->height - s->slice.y - s->slice.height) / scale, + s->slice.width / scale , s->slice.height / scale); [img drawInRect: dr fromRect: ir operation: NSCompositingOperationSourceOver diff --git a/src/xterm.c b/src/xterm.c index 3a7e31e712..f3d0af4177 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -136,6 +136,9 @@ along with GNU Emacs. If not, see . */ #include #endif +#include +#include + /* Default to using XIM if available. */ #ifdef USE_XIM bool use_xim = true; @@ -2970,6 +2973,39 @@ x_draw_glyph_string_box (struct glyph_string *s) } +static void +x_composite_image (struct glyph_string *s, Pixmap dest, + int srcX, int srcY, int dstX, int dstY, + int width, int height) +{ + Picture source, destination; + XRenderPictFormat *default_format, *source_format; + XRenderPictureAttributes source_attr, dest_attr; + + double scale = s->img->scale; + XTransform tmat = {{{XDoubleToFixed (1), XDoubleToFixed (0), XDoubleToFixed (0)}, + {XDoubleToFixed (0), XDoubleToFixed (1), XDoubleToFixed (0)}, + {XDoubleToFixed (0), XDoubleToFixed (0), XDoubleToFixed (scale)}}}; + + default_format = XRenderFindVisualFormat (s->display, DefaultVisual (s->display, 0)); + source_format = XRenderFindStandardFormat (s->display, PictStandardRGB24); + + source = XRenderCreatePicture (s->display, s->img->pixmap, source_format, 0, &source_attr); + destination = XRenderCreatePicture (s->display, dest, default_format, 0, &dest_attr); + + XRenderSetPictureTransform (s->display, source, &tmat); + + XRenderComposite (s->display, PictOpOver, source, None, destination, + srcX*scale, srcY*scale, + 0, 0, + dstX, dstY, + width, height); + + XRenderFreePicture (s->display, source); + XRenderFreePicture (s->display, destination); +} + + /* Draw foreground of image glyph string S. */ static void @@ -3018,10 +3054,8 @@ x_draw_image_foreground (struct glyph_string *s) image_rect.width = s->slice.width; image_rect.height = s->slice.height; if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) - XCopyArea (s->display, s->img->pixmap, - FRAME_X_DRAWABLE (s->f), s->gc, - s->slice.x + r.x - x, s->slice.y + r.y - y, - r.width, r.height, r.x, r.y); + x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y, + r.x, r.y, r.width, r.height); } else { @@ -3033,10 +3067,8 @@ x_draw_image_foreground (struct glyph_string *s) image_rect.width = s->slice.width; image_rect.height = s->slice.height; if (x_intersect_rectangles (&clip_rect, &image_rect, &r)) - XCopyArea (s->display, s->img->pixmap, - FRAME_X_DRAWABLE (s->f), s->gc, - s->slice.x + r.x - x, s->slice.y + r.y - y, - r.width, r.height, r.x, r.y); + x_composite_image (s, FRAME_X_DRAWABLE (s->f), s->slice.x + r.x - x, s->slice.y + r.y - y, + r.x, r.y, r.width, r.height); /* When the image has a mask, we can expect that at least part of a mouse highlight or a block cursor will -- 2.19.1 --AhhlLboLdkugWU4S--