Fix image margin leak
This commit is contained in:
@@ -353,6 +353,18 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
|
|
||||||
// imageRendering: 0=display, 1=placeholder (alt text only), 2=suppress entirely
|
// imageRendering: 0=display, 1=placeholder (alt text only), 2=suppress entirely
|
||||||
if (self->imageRendering == 2) {
|
if (self->imageRendering == 2) {
|
||||||
|
// Suppressing an image should not leak accumulated wrapper block spacing
|
||||||
|
// (e.g. figure/h1 margins) into the next text paragraph.
|
||||||
|
if (self->currentTextBlock && self->currentTextBlock->isEmpty()) {
|
||||||
|
BlockStyle resetStyle;
|
||||||
|
resetStyle.textAlignDefined = true;
|
||||||
|
const auto align = (self->paragraphAlignment == static_cast<uint8_t>(CssTextAlign::None))
|
||||||
|
? CssTextAlign::Justify
|
||||||
|
: static_cast<CssTextAlign>(self->paragraphAlignment);
|
||||||
|
resetStyle.alignment = align;
|
||||||
|
self->currentTextBlock->setBlockStyle(resetStyle);
|
||||||
|
LOG_DBG("EHP", "Image suppressed: pending empty block style reset");
|
||||||
|
}
|
||||||
self->skipUntilDepth = self->depth;
|
self->skipUntilDepth = self->depth;
|
||||||
self->depth += 1;
|
self->depth += 1;
|
||||||
return;
|
return;
|
||||||
@@ -373,6 +385,17 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
imgDisplayStyle.applyOver(it->second);
|
imgDisplayStyle.applyOver(it->second);
|
||||||
}
|
}
|
||||||
if (imgDisplayStyle.hasDisplay() && imgDisplayStyle.display == CssDisplay::None) {
|
if (imgDisplayStyle.hasDisplay() && imgDisplayStyle.display == CssDisplay::None) {
|
||||||
|
// CSS-hidden images should behave like suppressed images for spacing.
|
||||||
|
if (self->currentTextBlock && self->currentTextBlock->isEmpty()) {
|
||||||
|
BlockStyle resetStyle;
|
||||||
|
resetStyle.textAlignDefined = true;
|
||||||
|
const auto align = (self->paragraphAlignment == static_cast<uint8_t>(CssTextAlign::None))
|
||||||
|
? CssTextAlign::Justify
|
||||||
|
: static_cast<CssTextAlign>(self->paragraphAlignment);
|
||||||
|
resetStyle.alignment = align;
|
||||||
|
self->currentTextBlock->setBlockStyle(resetStyle);
|
||||||
|
LOG_DBG("EHP", "Image hidden via CSS display:none: pending empty block style reset");
|
||||||
|
}
|
||||||
self->skipUntilDepth = self->depth;
|
self->skipUntilDepth = self->depth;
|
||||||
self->depth += 1;
|
self->depth += 1;
|
||||||
return;
|
return;
|
||||||
@@ -517,9 +540,30 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
self->startNewTextBlock(parentBlockStyle);
|
self->startNewTextBlock(parentBlockStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the current text block is still empty, it may carry accumulated parent
|
||||||
|
// block spacing (e.g. div/figure/h1 wrappers). Apply that spacing around the
|
||||||
|
// image itself so it doesn't leak into the next text paragraph.
|
||||||
|
BlockStyle pendingImageBlockStyle;
|
||||||
|
if (self->currentTextBlock && self->currentTextBlock->isEmpty()) {
|
||||||
|
pendingImageBlockStyle = self->currentTextBlock->getBlockStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int imageSpacingTop = std::max(0, static_cast<int>(pendingImageBlockStyle.marginTop)) +
|
||||||
|
std::max(0, static_cast<int>(pendingImageBlockStyle.paddingTop));
|
||||||
|
const int imageSpacingBottom = std::max(0, static_cast<int>(pendingImageBlockStyle.marginBottom)) +
|
||||||
|
std::max(0, static_cast<int>(pendingImageBlockStyle.paddingBottom));
|
||||||
|
const int totalImageHeightWithSpacing = imageSpacingTop + displayHeight + imageSpacingBottom;
|
||||||
|
|
||||||
|
LOG_DBG("EHP",
|
||||||
|
"Image layout prep: src=%s dims=%dx%d display=%dx%d y=%d spacing(top=%d,bottom=%d,total=%d)",
|
||||||
|
src.c_str(), dims.width, dims.height, displayWidth, displayHeight, self->currentPageNextY,
|
||||||
|
imageSpacingTop, imageSpacingBottom, totalImageHeightWithSpacing);
|
||||||
|
|
||||||
// Create page for image - only break if image won't fit remaining space
|
// Create page for image - only break if image won't fit remaining space
|
||||||
if (self->currentPage && !self->currentPage->elements.empty() &&
|
if (self->currentPage && !self->currentPage->elements.empty() &&
|
||||||
(self->currentPageNextY + displayHeight > self->viewportHeight)) {
|
(self->currentPageNextY + totalImageHeightWithSpacing > self->viewportHeight)) {
|
||||||
|
LOG_DBG("EHP", "Image page break: currentY=%d needed=%d viewportH=%d", self->currentPageNextY,
|
||||||
|
totalImageHeightWithSpacing, self->viewportHeight);
|
||||||
self->paragraphIndexPerPage.push_back(self->xpathParagraphIndex);
|
self->paragraphIndexPerPage.push_back(self->xpathParagraphIndex);
|
||||||
self->completePageFn(std::move(self->currentPage));
|
self->completePageFn(std::move(self->currentPage));
|
||||||
self->completedPageCount++;
|
self->completedPageCount++;
|
||||||
@@ -538,6 +582,8 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
self->currentPageNextY = 0;
|
self->currentPageNextY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->currentPageNextY += imageSpacingTop;
|
||||||
|
|
||||||
// Create ImageBlock and add to page
|
// Create ImageBlock and add to page
|
||||||
auto imageBlock = std::make_shared<ImageBlock>(cachedImagePath, displayWidth, displayHeight);
|
auto imageBlock = std::make_shared<ImageBlock>(cachedImagePath, displayWidth, displayHeight);
|
||||||
if (!imageBlock) {
|
if (!imageBlock) {
|
||||||
@@ -552,6 +598,24 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
}
|
}
|
||||||
self->currentPage->elements.push_back(pageImage);
|
self->currentPage->elements.push_back(pageImage);
|
||||||
self->currentPageNextY += displayHeight;
|
self->currentPageNextY += displayHeight;
|
||||||
|
self->currentPageNextY += imageSpacingBottom;
|
||||||
|
|
||||||
|
LOG_DBG("EHP", "Image placed: x=%d y=%d w=%d h=%d nextY=%d", xPos, pageImage->yPos, displayWidth,
|
||||||
|
displayHeight, self->currentPageNextY);
|
||||||
|
|
||||||
|
// Reset empty pending block style after consuming spacing around the image.
|
||||||
|
// This prevents figure/header wrapper margins from being applied again to the
|
||||||
|
// next paragraph block.
|
||||||
|
if (self->currentTextBlock && self->currentTextBlock->isEmpty()) {
|
||||||
|
BlockStyle resetStyle;
|
||||||
|
resetStyle.textAlignDefined = true;
|
||||||
|
const auto align = (self->paragraphAlignment == static_cast<uint8_t>(CssTextAlign::None))
|
||||||
|
? CssTextAlign::Justify
|
||||||
|
: static_cast<CssTextAlign>(self->paragraphAlignment);
|
||||||
|
resetStyle.alignment = align;
|
||||||
|
self->currentTextBlock->setBlockStyle(resetStyle);
|
||||||
|
LOG_DBG("EHP", "Image spacing consumed; pending empty block style reset for following text");
|
||||||
|
}
|
||||||
|
|
||||||
self->depth += 1;
|
self->depth += 1;
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user