diff --git a/ChangeLog b/ChangeLog index fe1e5c78..fad7cda9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,7 @@ dillo-3.2.0 [Not released yet] GNU extensions. - Perform an emergency stop of the layout engine loop after 1000 iterations to prevent a hang. + - Improve image resize logic to always try to preserve the aspect ratio. Patches: Rodrigo Arias Mallo +- Add primitive support for SVG using the nanosvg.h library. Patches: dogma, Rodrigo Arias Mallo diff --git a/dw/image.cc b/dw/image.cc index fc914f44..770f82a0 100644 --- a/dw/image.cc +++ b/dw/image.cc @@ -2,6 +2,7 @@ * Dillo Widget * * Copyright 2005-2007 Sebastian Geerken + * Copyright 2024 Rodrigo Arias Mallo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +24,7 @@ #include "dlib/dlib.h" #include "../lout/msg.h" #include "../lout/misc.hh" +//#define DEBUG_LEVEL 1 #include "../lout/debug.hh" namespace dw { @@ -177,6 +179,8 @@ void Image::sizeRequestSimpl (core::Requisition *requisition) { DBG_OBJ_ENTER0 ("resize", 0, "sizeRequestImpl"); + /* First set the a naive size based on the image properties if given */ + if (buffer) { requisition->width = buffer->getRootWidth (); requisition->ascent = buffer->getRootHeight (); @@ -201,9 +205,15 @@ void Image::sizeRequestSimpl (core::Requisition *requisition) requisition->ascent += boxOffsetY (); requisition->descent += boxRestHeight (); + /* Then correct the size, so it fits within the {min,max}-{width,height} + * contraints */ + correctRequisition (requisition, core::splitHeightPreserveDescent, true, true); + /* Finally, ensure that we don't distort the image unless the height and + * width are fixed. */ + if (buffer) { // If one dimension is set, preserve the aspect ratio (without // extraSpace/margin/border/padding). Notice that @@ -214,24 +224,164 @@ void Image::sizeRequestSimpl (core::Requisition *requisition) // TODO Check again possible overflows. (Aren't buffer // dimensions limited to 2^15?) - bool widthSpecified = getStyle()->width != core::style::LENGTH_AUTO || - getStyle()->minWidth != core::style::LENGTH_AUTO || - getStyle()->maxWidth != core::style::LENGTH_AUTO; - bool heightSpecified = getStyle()->height != core::style::LENGTH_AUTO || - getStyle()->minHeight != core::style::LENGTH_AUTO || - getStyle()->maxHeight != core::style::LENGTH_AUTO; - - if (!widthSpecified && heightSpecified) - requisition->width = - (requisition->ascent + requisition->descent - boxDiffHeight ()) - * buffer->getRootWidth () / buffer->getRootHeight () - + boxDiffWidth (); - else if (widthSpecified && !heightSpecified) { - requisition->ascent = (requisition->width + boxDiffWidth ()) - * buffer->getRootHeight () / buffer->getRootWidth () - + boxOffsetY (); - requisition->descent = boxRestHeight (); + bool wFixed = getStyle()->width != core::style::LENGTH_AUTO; + bool hFixed = getStyle()->height != core::style::LENGTH_AUTO; + + /* Image dimensions */ + int w = buffer->getRootWidth (); + int h = buffer->getRootHeight (); + + /* Reference size in case we are the root */ + int w_ref = -1, h_ref = -1; + + /* TODO: What if we have a quasiParent? */ + if (getParent() == NULL) { + w_ref = layout->getWidthViewport(); + h_ref = layout->getHeightViewport(); + } + + /* FIXME: Cannot get private information from Layout to avoid the + * scrollbar width. */ + //int w_ref = layout->getWidthViewport() - (layout->canvasHeightGreater ? + // layout->vScrollbarThickness : 0); + + DEBUG_MSG(1, "initial size: w=%d, h=%d\n", w, h); + + float ratio = (float) h / (float) w; + + DEBUG_MSG(1, "wFixed=%d, hFixed=%d\n", wFixed, hFixed); + + /* When the size is fixed, set w and h accordingly */ + if (hFixed) { + int hh = calcHeight(getStyle()->height, true, h_ref, getParent(), true); + if (hh == -1) + hFixed = false; + else + h = hh; + } + + if (wFixed) { + int ww = calcWidth(getStyle()->width, w_ref, getParent(), 0, true); + if (ww == -1) + wFixed = false; + else + w = ww; + } + + DEBUG_MSG(1, "size after fixed correction: w=%d, h=%d\n", w, h); + + /* Correct the image size to keep the aspect ratio, but only change the + * dimensions that are not fixed, if any. */ + + if (!wFixed && !hFixed) { + DEBUG_MSG(1, "case: both can change\n"); + /* Both width and height are not set, so we can play with both dimensions. */ + int minWidth = calcWidth(getStyle()->minWidth, w_ref, getParent(), 0, true); + int maxWidth = calcWidth(getStyle()->maxWidth, w_ref, getParent(), 0, true); + int minHeight = calcHeight(getStyle()->minHeight, true, h_ref, getParent(), true); + int maxHeight = calcHeight(getStyle()->maxHeight, true, h_ref, getParent(), true); + + DEBUG_MSG(1, "minWidth = %d, maxWidth = %d\n", minWidth, maxWidth); + DEBUG_MSG(1, "minHeight= %d, maxHeight= %d\n", minHeight, maxHeight); + + /* Fix broken width by expanding the maximum */ + if (minWidth != -1 && maxWidth != -1 && minWidth > maxWidth) + maxWidth = minWidth; + + /* Fix broken height by expanding the maximum */ + if (minHeight != -1 && maxHeight != -1 && minHeight > maxHeight) + maxHeight = minHeight; + + DEBUG_MSG(1, "corrected minWidth = %d, maxWidth = %d\n", minWidth, maxWidth); + DEBUG_MSG(1, "corrected minHeight= %d, maxHeight= %d\n", minHeight, maxHeight); + + /* Repeat 2 times fixing the aspect ratio, two more without */ + for (int i = 0; i < 4; i++) { + DEBUG_MSG(1, "iteration %d, w=%d, h=%d\n", i, w, h); + int old_w = w; + + /* Constraint the width first */ + if (maxWidth != -1 && w > maxWidth) + w = maxWidth; + else if (minWidth != -1 && w < minWidth) + w = minWidth; + + /* Now we may have distorted the image, so try to fix the aspect ratio */ + if (w != old_w && i < 2) + h = w * ratio; + + int old_h = h; + + /* Now constraint the height */ + if (maxHeight != -1 && h > maxHeight) + h = maxHeight; + else if (minHeight != -1 && h < minHeight) + h = minHeight; + + /* Now we may have distorted the image again, so fix w */ + if (h != old_h && i < 2) + w = h / ratio; + + DEBUG_MSG(1, "w=%d, h=%d\n", w, h); + + /* All contraints meet */ + if (old_h == h && old_w == w) + break; + } + } else if (wFixed && !hFixed) { + /* Only height can change */ + DEBUG_MSG(1, "case: only heigh can change\n"); + int minHeight = calcHeight(getStyle()->minHeight, true, h_ref, getParent(), true); + int maxHeight = calcHeight(getStyle()->maxHeight, true, h_ref, getParent(), true); + + DEBUG_MSG(1, "minHeight= %d, maxHeight= %d\n", minHeight, maxHeight); + + /* Fix broken height by expanding the maximum */ + if (minHeight != -1 && maxHeight != -1 && minHeight > maxHeight) + maxHeight = minHeight; + + DEBUG_MSG(1, "corrected minHeight= %d, maxHeight= %d\n", minHeight, maxHeight); + + /* Try preserving the ratio */ + h = w * ratio; + + /* Now constraint the height */ + if (maxHeight != -1 && h > maxHeight) + h = maxHeight; + else if (minHeight != -1 && h < minHeight) + h = minHeight; + } else if (!wFixed && hFixed) { + /* Only width can change */ + DEBUG_MSG(1, "case: only width can change\n"); + int minWidth = calcWidth(getStyle()->minWidth, w_ref, getParent(), 0, true); + int maxWidth = calcWidth(getStyle()->maxWidth, w_ref, getParent(), 0, true); + + DEBUG_MSG(1, "minWidth = %d, maxWidth = %d\n", minWidth, maxWidth); + + /* Fix broken width by expanding the maximum */ + if (minWidth != -1 && maxWidth != -1 && minWidth > maxWidth) + maxWidth = minWidth; + + DEBUG_MSG(1, "corrected minWidth = %d, maxWidth = %d\n", minWidth, maxWidth); + + /* Try preserving the ratio */ + w = h / ratio; + DEBUG_MSG(1, "by ratio, w=%d\n", w); + + /* Now constraint the width */ + if (maxWidth != -1 && w > maxWidth) + w = maxWidth; + else if (minWidth != -1 && w < minWidth) + w = minWidth; + } else { + /* Both dimensions are fixed, so nothing to do. */ } + + DEBUG_MSG(1, "final: w=%d, h=%d\n", w, h); + + requisition->width = w + boxDiffWidth (); + requisition->ascent = h + boxOffsetY (); + requisition->descent = boxRestHeight (); } DBG_OBJ_MSGF ("resize", 1, "=> %d * (%d + %d)", diff --git a/test/html/Makefile.am b/test/html/Makefile.am index 6bcd5855..5997a057 100644 --- a/test/html/Makefile.am +++ b/test/html/Makefile.am @@ -44,8 +44,6 @@ TESTS = \ XFAIL_TESTS = \ render/div-100-percent-with-padding.html \ render/float-img-justify.html \ - render/img-aspect-ratio.html \ - render/img-max-bounds.html \ render/margin-auto.html \ render/max-width-html.html \ render/min-width-html.html \