-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CSS: add support for min-width, max-width, min-height, max-height #409
Conversation
It was hardcoded'ly removed as part of 9214bfc when implementing support for CSS width & height for images, so they don't get in the way. Removed the hardcoding so the original CoolReader settings can work again. We can still disable that from frontend code.
Increase nb of bitmaps from 2 to 3 lUInt32 as we're going over 64 properties.
Compute image size according to CSS2 specs, ensuring CSS width, height, min-width, min-height, max-width and max-height. Used in lvtextfm when drawing images, and when estimating block widths in getRenderedWidths() instead of the previous wrong computation. Limitation: heights in % are not supported and ignored.
Ensure min-width, min-height, max-width (but not max-height) on block elements, inline-block/table, block floats and floating images (min-height in % not supported). Ensure min-width on the table element itself (but not supported on the table inner elements like cells and cols).
7f70d8d
to
55eb7fa
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing jumps out at a cursory glance, but I'm obviously unfamiliar with the logic involved ;).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing much to say about it either.
Possible rounding error (ceiling while we might want flooring) somewhere, causing some image to be splitted onto 2 pages (because after resizing, it is higher than the page height) instead of make a page on its own:
|
I could have get done with adding at the end: // Really be sure the computations did not overflow
if ( height > max_h )
height = max_h;
if ( width > max_w )
width = max_w; But I think I'm gonna trust buggins/coolreader#252 (without the Current code: if ( maxScaleMult<1 ) maxScaleMult = 1;
if ( arbitraryImageScaling ) {
int pscale_x = 1000 * maxw / width;
int pscale_y = 1000 * maxh / height;
int pscale = pscale_x < pscale_y ? pscale_x : pscale_y;
int maxscale = maxScaleMult * 1000;
if ( pscale>maxscale )
pscale = maxscale;
height = height * pscale / 1000;
width = width * pscale / 1000;
} else {
if (maxw == 0 || maxh == 0) {
// Avoid a floating point exception (division by zero) crash.
printf("CRE WARNING: resizeImage(maxw=0 or maxh=0)\n");
return;
}
int scale_div = 1;
int scale_mul = 1;
int div_x = (width * 1000 / maxw);
int div_y = (height * 1000 / maxh);
if ( maxScaleMult>=3 && height*3 < maxh - 20
&& width*3 < maxw - 20 ) {
scale_mul = 3;
} else if ( maxScaleMult>=2 && height * 2 < maxh - 20
&& width * 2 < maxw - 20 ) {
scale_mul = 2;
} else if (div_x>1 || div_y>1) {
if (div_x>div_y)
scale_div = div_x;
else
scale_div = div_y;
}
height = height * 1000 * scale_mul / scale_div;
width = width * 1000 * scale_mul / scale_div;
} Could become (buggins/coolreader#252, without if ( maxScaleMult < 1 ) maxScaleMult = 1;
if ( maxw < 2 ) maxw = 2;
if ( maxh < 2 ) maxh = 2;
if ( !arbitraryImageScaling ) {
// Integer scaling. Try some integer scales first.
if ( maxScaleMult >= 3 && height*3 < maxh - 20 && width*3 < maxw - 20 ) {
width = width * 3;
height = height * 3;
return;
}
if ( maxScaleMult >= 2 && height * 2 < maxh - 20 && width * 2 < maxw - 20 ) {
width = width * 2;
height = height * 2;
return;
}
if ( height <= maxh && width <= maxw ) {
// Fits without scaling (one).
return;
}
// Fall through to arbitrary scale down.
}
if (width * maxh > height * maxw) {
if (width * maxScaleMult > maxw) {
height = height * maxw / width;
width = maxw;
return;
}
}
else {
if (height * maxScaleMult > maxh) {
width = width * maxh / height;
height = maxh;
return;
}
}
width = width * maxScaleMult;
height = height * maxScaleMult; I'm still not friend with aspect ratio and these |
I wouldn't mind an explanation behind the magic I also wouldn't mind better variables names, because I have no idea what's the source image's dimensions, what's the scaled values (because it appears that the same out pointer is used for both...). At least I imagine maxh/maxw and are the bounding box dimensions. Otherwise, AR is as simple as that (which translates to this with slightly less obscure variable names). Sidebar: I wouldn't call CRe's house style "clearer" ^^. It's just... CRe's house style ;p. But we've already had this conversation ^^. |
I have no explanation: it's there since ages, not from me, and it's in a code path we won't be taking (but CoolReader may).
Right, computed (from CSS or native image size) width & height, updated in place:
Oh my, why did I ask ?! :) |
Also, this appears to prefer scaling to fit dims * maxScaleMult, instead of fitting maxw/maxh, while, AFAICT, the older code properly used it as a cap. |
Which means, if I understood what maxScaleMult is supposed to do, the tail end could look something like this: // FIXME: Move me to a dedicated inline function to avoid code dupe inside the maxScaleMult block
int bbox_width = maxw;
int bbox_height = maxh;
// We want to fit *inside* the bbox
int scaled_width = bbox_width;
int scaled_height = bbox_height;
int rescaled_width = bbox_height * width / height;
if (rescaled_width <= bbox_width) {
scaled_width = rescaled_width;
} else {
scaled_height = bbox_width * height / width;
}
// We also want to make sure we haven't gone past maxScaleMult when upscaling...
// FIXME: Should we skip this if maxScaleMult is 1 or something?
if (scaled_height > height && scaled_height / height > maxScaleMult || scaled_width > width && scaled_width / width > maxScaleMult) {
bbox_width = width * maxScaleMult;
bbox_height = height * maxScaleMult;
// e.g., call inlined function here ;p
scaled_width = bbox_width;
scaled_height = bbox_height;
rescaled_width = bbox_height * width / height;
if (rescaled_width <= bbox_width) {
scaled_width = rescaled_width;
} else {
scaled_height = bbox_width * height / width;
}
}
// We're done, update out pointers
width = scaled_width;
height = scaled_height; |
e.g., static inline void fit_inside(int & width, int & height, int bbox_width, int bbox_height) {
// We want to fit *inside* the bbox, so this is a good start, we'll honor AR below.
int scaled_width = bbox_width;
int scaled_height = bbox_height;
int rescaled_width = bbox_height * width / height;
if (rescaled_width <= bbox_width) {
scaled_width = rescaled_width;
} else {
scaled_height = bbox_width * height / width;
}
// We're done, update out pointers
width = scaled_width;
height = scaled_height;
}
...
// Start with the source dimensions, fit_inside will update 'em
int scaled_width = width;
int scaled_height = height;
fit_inside(scaled_width, scaled_height, maxw, maxh);
// We also want to make sure we haven't gone past maxScaleMult when upscaling...
// FIXME: Should we skip this if maxScaleMult is 1 or something?
if (scaled_height > height && scaled_height / height > maxScaleMult || scaled_width > width && scaled_width / width > maxScaleMult) {
// Start with the source dimensions, fit_inside will update 'em
scaled_width = width;
scaled_height = height;
fit_inside(scaled_width, scaled_height, width * maxScaleMult, height * maxScaleMult);
}
// We're done, update out pointers
width = scaled_width;
height = scaled_height; |
Mhhh, hard to get into what you want to do (just as hard to get into the current code, and the new one :) but it looks like you want to always scale to fit in the bbox - which is not the only purpose of this function: when From what I understand, this function should do:
|
Oh, that's what I meant by "the tail end of" (hence the ellipsis), e.g., it's just the e.g., it replaces this section, but keeps the rest: if (width * maxh > height * maxw) {
if (width * maxScaleMult > maxw) {
height = height * maxw / width;
width = maxw;
return;
}
}
else {
if (height * maxScaleMult > maxh) {
width = width * maxh / height;
height = maxh;
return;
}
}
width = width * maxScaleMult;
height = height * maxScaleMult; |
So, yeah, that's what I understood to, and I think that the new code broke this, hence my revision. |
Pfff, you're talking about the other codepath. (Oh, why do we have to spend so much time on these kind of things...;) |
Yeah, the convoluted way in which it handles that is precisely what makes me wary of the effective results ;). (As in, I literally can't wrap my brain around it, so I'm not confident it does it right without putting it through a rigorous test harness, which we don't have ^^. While I feel more confident about an approach that actually compares a scale ratio post-scaling, which is also what the current code does ^^.) |
Dunno if that's rigorous enough: testResizeImage.cpp.txt Haven't extended the test case to limit the output below. 1,2c3,4
> [22 44] arbSc 0 scMul 1 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 2 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 3 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 4 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 1 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 2 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 3 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 4 : 22/44 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 1 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 0 scMul 2 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 0 scMul 3 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 0 scMul 4 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 1 scMul 1 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 1 scMul 2 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 1 scMul 3 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 1 scMul 4 : 44/22 => old: 22/11 |new: 22/11
> [22 44] arbSc 0 scMul 1 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 2 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 3 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 4 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 1 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 2 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 3 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 1 scMul 4 : 100/200 => old: 22/44 |new: 22/44
> [22 44] arbSc 0 scMul 1 : 150/100 => old: 22/14 |new: 22/14
> [22 44] arbSc 0 scMul 2 : 150/100 => old: 22/14 |new: 22/14
> [22 44] arbSc 0 scMul 3 : 150/100 => old: 22/14 |new: 22/14
> [22 44] arbSc 0 scMul 4 : 150/100 => old: 22/14 |new: 22/14
< [22 44] arbSc 1 scMul 1 : 150/100 => old: 21/14 |new: 22/14 diff 1 / 0
< [22 44] arbSc 1 scMul 2 : 150/100 => old: 21/14 |new: 22/14 diff 1 / 0
< [22 44] arbSc 1 scMul 3 : 150/100 => old: 21/14 |new: 22/14 diff 1 / 0
< [22 44] arbSc 1 scMul 4 : 150/100 => old: 21/14 |new: 22/14 diff 1 / 0
> [44 22] arbSc 0 scMul 1 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 2 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 3 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 4 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 1 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 2 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 3 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 4 : 22/44 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 1 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 0 scMul 2 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 0 scMul 3 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 0 scMul 4 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 1 scMul 1 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 1 scMul 2 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 1 scMul 3 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 1 scMul 4 : 44/22 => old: 44/22 |new: 44/22
> [44 22] arbSc 0 scMul 1 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 2 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 3 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 4 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 1 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 2 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 3 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 1 scMul 4 : 100/200 => old: 11/22 |new: 11/22
> [44 22] arbSc 0 scMul 1 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 0 scMul 2 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 0 scMul 3 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 0 scMul 4 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 1 scMul 1 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 1 scMul 2 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 1 scMul 3 : 150/100 => old: 33/22 |new: 33/22
> [44 22] arbSc 1 scMul 4 : 150/100 => old: 33/22 |new: 33/22
< [100 200] arbSc 0 scMul 1 : 22/44 => old: 100/200 |new: 22/44 diff -78 / -156
< [100 200] arbSc 0 scMul 2 : 22/44 => old: 44000/88000 |new: 44/88 diff -43956 / -87912
< [100 200] arbSc 0 scMul 3 : 22/44 => old: 66000/132000 |new: 66/132 diff -65934 / -131868
< [100 200] arbSc 0 scMul 4 : 22/44 => old: 66000/132000 |new: 66/132 diff -65934 / -131868
> [100 200] arbSc 1 scMul 1 : 22/44 => old: 22/44 |new: 22/44
> [100 200] arbSc 1 scMul 2 : 22/44 => old: 44/88 |new: 44/88
> [100 200] arbSc 1 scMul 3 : 22/44 => old: 66/132 |new: 66/132
> [100 200] arbSc 1 scMul 4 : 22/44 => old: 88/176 |new: 88/176
< [100 200] arbSc 0 scMul 1 : 44/22 => old: 100/50 |new: 44/22 diff -56 / -28
< [100 200] arbSc 0 scMul 2 : 44/22 => old: 100/50 |new: 44/22 diff -56 / -28
< [100 200] arbSc 0 scMul 3 : 44/22 => old: 100/50 |new: 44/22 diff -56 / -28
< [100 200] arbSc 0 scMul 4 : 44/22 => old: 100/50 |new: 44/22 diff -56 / -28
> [100 200] arbSc 1 scMul 1 : 44/22 => old: 44/22 |new: 44/22
> [100 200] arbSc 1 scMul 2 : 44/22 => old: 88/44 |new: 88/44
< [100 200] arbSc 1 scMul 3 : 44/22 => old: 99/49 |new: 100/50 diff 1 / 1
< [100 200] arbSc 1 scMul 4 : 44/22 => old: 99/49 |new: 100/50 diff 1 / 1
> [100 200] arbSc 0 scMul 1 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 0 scMul 2 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 0 scMul 3 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 0 scMul 4 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 1 scMul 1 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 1 scMul 2 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 1 scMul 3 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 1 scMul 4 : 100/200 => old: 100/200 |new: 100/200
> [100 200] arbSc 0 scMul 1 : 150/100 => old: 100/66 |new: 100/66
> [100 200] arbSc 0 scMul 2 : 150/100 => old: 100/66 |new: 100/66
> [100 200] arbSc 0 scMul 3 : 150/100 => old: 100/66 |new: 100/66
> [100 200] arbSc 0 scMul 4 : 150/100 => old: 100/66 |new: 100/66
< [100 200] arbSc 1 scMul 1 : 150/100 => old: 99/66 |new: 100/66 diff 1 / 0
< [100 200] arbSc 1 scMul 2 : 150/100 => old: 99/66 |new: 100/66 diff 1 / 0
< [100 200] arbSc 1 scMul 3 : 150/100 => old: 99/66 |new: 100/66 diff 1 / 0
< [100 200] arbSc 1 scMul 4 : 150/100 => old: 99/66 |new: 100/66 diff 1 / 0
< [150 100] arbSc 0 scMul 1 : 22/44 => old: 50/100 |new: 22/44 diff -28 / -56
< [150 100] arbSc 0 scMul 2 : 22/44 => old: 50/100 |new: 22/44 diff -28 / -56
< [150 100] arbSc 0 scMul 3 : 22/44 => old: 50/100 |new: 22/44 diff -28 / -56
< [150 100] arbSc 0 scMul 4 : 22/44 => old: 50/100 |new: 22/44 diff -28 / -56
> [150 100] arbSc 1 scMul 1 : 22/44 => old: 22/44 |new: 22/44
> [150 100] arbSc 1 scMul 2 : 22/44 => old: 44/88 |new: 44/88
< [150 100] arbSc 1 scMul 3 : 22/44 => old: 49/99 |new: 50/100 diff 1 / 1
< [150 100] arbSc 1 scMul 4 : 22/44 => old: 49/99 |new: 50/100 diff 1 / 1
< [150 100] arbSc 0 scMul 1 : 44/22 => old: 150/75 |new: 44/22 diff -106 / -53
< [150 100] arbSc 0 scMul 2 : 44/22 => old: 88000/44000 |new: 88/44 diff -87912 / -43956
< [150 100] arbSc 0 scMul 3 : 44/22 => old: 88000/44000 |new: 88/44 diff -87912 / -43956
< [150 100] arbSc 0 scMul 4 : 44/22 => old: 88000/44000 |new: 88/44 diff -87912 / -43956
> [150 100] arbSc 1 scMul 1 : 44/22 => old: 44/22 |new: 44/22
> [150 100] arbSc 1 scMul 2 : 44/22 => old: 88/44 |new: 88/44
> [150 100] arbSc 1 scMul 3 : 44/22 => old: 132/66 |new: 132/66
< [150 100] arbSc 1 scMul 4 : 44/22 => old: 149/74 |new: 150/75 diff 1 / 1
> [150 100] arbSc 0 scMul 1 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 0 scMul 2 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 0 scMul 3 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 0 scMul 4 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 1 scMul 1 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 1 scMul 2 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 1 scMul 3 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 1 scMul 4 : 100/200 => old: 50/100 |new: 50/100
> [150 100] arbSc 0 scMul 1 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 0 scMul 2 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 0 scMul 3 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 0 scMul 4 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 1 scMul 1 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 1 scMul 2 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 1 scMul 3 : 150/100 => old: 150/100 |new: 150/100
> [150 100] arbSc 1 scMul 4 : 150/100 => old: 150/100 |new: 150/100 |
The good news is I get similar results w/ my code above, after a simple fix to account for truncation of the scaled ratio: (e.g.,
|
Getting rid of the magic 20 pixels fixes the arbSc 0 inconsistencies, FWIW ;). (With results that make sense, given our understanding of the function's intent). |
This comment has been minimized.
This comment has been minimized.
e.g., this appears to behave: if ( !arbitraryImageScaling ) {
// Integer scaling. Try some integer scales first.
if ( maxScaleMult >= 3 && height*3 < maxh && width*3 < maxw ) {
width = width * 3;
height = height * 3;
return;
}
if ( maxScaleMult >= 2 && height * 2 < maxh && width * 2 < maxw ) {
width = width * 2;
height = height * 2;
return;
}
if ( height <= maxh && width <= maxw ) {
// Fits without scaling (one).
return;
}
// Fall through to arbitrary scale down.
}
// Make sure we never blow past maxScaleMult while still fitting inside maxw/maxh
int bbox_width = width * maxScaleMult > maxw ? maxw : width * maxScaleMult;
int bbox_height = height * maxScaleMult > maxh ? maxh : height * maxScaleMult;
// We want to fit *inside* the bbox, so this is a good start, as we'll ultimately keep that value for one side.
int scaled_width = bbox_width;
int scaled_height = bbox_height;
// And now see whether we need to compute width or height to honor the AR.
int rescaled_width = bbox_height * width / height;
if (rescaled_width <= bbox_width) {
scaled_width = rescaled_width;
} else {
scaled_height = bbox_width * height / width;
}
// We're done, update out pointers
width = scaled_width;
height = scaled_height; |
But the old one had these magic 20 (although using it a bit differently), and did not stop scaling. Why? A little comment (as you've already put a few, why not one more, to help those who suck at arithmetics :) explaining me why I don't have to wonder why you just compute |
Because the * 1000 shenanigans relegated those 20 to noise, I guess? That's the first comment, we only need to compute a single side since we want to fit inside a bbox and keep AR: one side will be the bbox value itself. Hence, start by initializing the final values to the bbox for both sides, since we'll ultimately keep one of those, and then compute one of those sides (we could invert the logic depending on whether we mostly scale to portrait or landscape bboxes) to see if that's the one we actually want to keep, depending on whether it fits or not. EDIT: Tweaked comments above. |
e.g., if you prefer, this block can read: int scaled_width;
int scaled_height;
// And now see whether we need to compute width or height to honor the AR.
int rescaled_width = bbox_height * width / height;
if (rescaled_width <= bbox_width) {
scaled_width = rescaled_width;
scaled_height = bbox_height;
} else {
scaled_width = bbox_width;
scaled_height = bbox_width * height / width;
} |
OK thanks. Yes, that reads better. |
Well, it's still more than half @ourairquality's ;p. I can take a look at it later (probably not tomorrow, though), but you have my blessing to fold it with whatever else you may have in the pipes in the meantime ;). |
Simplified the integer scaling codepath, and made it actually honor maxScaleMult, instead of arbitrarily stopping at 3? if ( !arbitraryImageScaling ) {
// Integer scaling, constrained to maxScaleMult
for ( int i = maxScaleMult; i > 0; i-- ) {
// Use the largest integer multiplier that fits
int scaled_width = width * i;
int scaled_height = height * i;
if ( scaled_width <= maxw && scaled_height <= maxh ) {
width = scaled_width;
height = scaled_height;
return;
}
}
// Fall through to arbitrary scaling
}
// Make sure we never blow past maxScaleMult while still fitting inside maxw/maxh
int bbox_width = width * maxScaleMult > maxw ? maxw : width * maxScaleMult;
int bbox_height = height * maxScaleMult > maxh ? maxh : height * maxScaleMult;
int scaled_width;
int scaled_height;
// And now see whether we need to compute width or height to honor the AR.
// c.f., QSize::scaled @ https://github.com/qt/qtbase/blob/dev/src/corelib/tools/qsize.cpp for Qt::KeepAspectRatio
int rescaled_width = bbox_height * width / height;
if ( rescaled_width <= bbox_width ) {
scaled_width = rescaled_width;
scaled_height = bbox_height;
} else {
scaled_width = bbox_width;
scaled_height = bbox_width * height / width;
}
// We're done, update out pointers
width = scaled_width;
height = scaled_height; I'll give it a proper look tomorrow, sleep deprivation and maths don't mix well ^^. |
Note to self: simplify the guards to be <= 0 for everybody in every codepath, because 0/negative dims make no sense, regardless of crashing considerations. |
I'll definititely let this one to you as you seem to have fun :) // See if using maxScaleMult (possibly 1) we would overflow maxw/maxh
if (width * maxh > height * maxw) {
// Keeping aspect ratio, width would overflow first: so check width
if (width * maxScaleMult > maxw) {
// width overflows: cap width, compute height keeping A/R
height = height * maxw / width;
width = maxw;
return;
}
}
else {
// Keeping aspect ratio, height would overflow first: so check height
if (height * maxScaleMult > maxh) {
// height overflows: cap height, compute width keeping A/R
width = width * maxh / height;
height = maxh;
return;
}
}
// No overflow: just scale
width = width * maxScaleMult;
height = height * maxScaleMult; ) |
As discussed in koreader#409 Basically: * If !arbitraryImageScaling: try integer scaling, from maxScaleMult to 1. If nothing fits the bounding box, fall back to arbitrary scaling. Get rid of the weird mutlitplier and magic scratch pixels, because when they weren't introducins egregious errors, they were actually *introducing* rounding errors! * Simplify the classic scaling code, based on Qt's algorithm. No floats or weird multiplier needed, because we *always* MUL before we DIV. And if no rounding was deemed necessary by Qt, then implicit truncation is probably good enough for us, too ;).
As discussed in #409 Basically: * If !arbitraryImageScaling: try integer scaling, from maxScaleMult to 1. If nothing fits the bounding box, fall back to arbitrary scaling. Get rid of the weird mutlitplier and magic scratch pixels, because when they weren't introducins egregious errors, they were actually *introducing* rounding errors! * Simplify the classic scaling code, based on Qt's algorithm. No floats or weird multiplier needed, because we *always* MUL before we DIV. And if no rounding was deemed necessary by Qt, then implicit truncation is probably good enough for us, too ;).
See #360 (comment). Closes #360.
CSS: parse and store min/max-width/height
Increase nb of bitmaps from 2 to 3 lUInt32 as we're going over 64 properties.
Add getStyledImageSize() ensuring min/max-width/height
Compute image size according to CSS2 specs, ensuring CSS
width
,height
,min-width
,min-height
,max-width
andmax-height
.Used in lvtextfm when drawing images, and when estimating block widths in
getRenderedWidths()
instead of the previous wrong computation.Limitation: heights in
%
are not supported and ignored.renderBlockElementEnhanced(): ensure min/max-width/height
Ensure
min-width
,min-height
,max-width
(but notmax-height
) on block elements, inline-block/table, block floats and floating images (min-height
in%
not supported).Ensure
min-width
on the table element itself (but not supported on the table inner elements like cells and cols).Also includes:
EPUB ncx TOC: allow items with an empty title
No reason to ignore them - and they may have sub-items with non-empty titles that would all be ignored. koreader/koreader#5961 (comment)
resizeImage(): restore original scaling options code
It was hardcoded'ly removed as part of #35 9214bfc when implementing support for CSS width & height for images, so they don't get in the way.
Removed the hardcoding so the original CoolReader settings can work again. buggins/coolreader#125 (comment)
We can still disable that from frontend code with:
This change is![Reviewable](https://camo.githubusercontent.com/1541c4039185914e83657d3683ec25920c672c6c5c7ab4240ee7bff601adec0b/68747470733a2f2f72657669657761626c652e696f2f7265766965775f627574746f6e2e737667)