calculateHtmlDocDimensions property

String calculateHtmlDocDimensions
getter/setter pair

Implementation

static String calculateHtmlDocDimensions = Platform.isIOS
    ? '''
    (function() {
      const body = document.body;
      const html = document.documentElement;

      html.style.margin = '0';
      html.style.padding = '0';
      html.style.overflow = 'auto';
      body.style.margin = '0';
      body.style.padding = '0';
      body.style.overflow = 'auto';

      // Ensure all images loaded
      const imgs = document.images;
      for (let i = 0; i < imgs.length; i++) {
        if (!imgs[i].complete) return -1;
      }

      let height = Math.max(
        body.scrollHeight, body.offsetHeight,
        html.clientHeight, html.scrollHeight, html.offsetHeight
      );
      let width = Math.max(
        body.scrollWidth, body.offsetWidth,
        html.clientWidth, html.scrollWidth, html.offsetWidth
      );


      // Consider iframes
      const iframes = document.getElementsByTagName('iframe');
      for (let i = 0; i < iframes.length; i++) {
        const iframe = iframes[i];
        let iframeHeight = 0;
        let iframeWidth = 0;

        try {
          // Try reading internal body height (same-origin only)
          const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
          if (iframeDoc && iframeDoc.readyState === 'complete') {
            const ib = iframeDoc.body;
            if (ib) {
              iframeHeight = Math.max(ib.scrollHeight, ib.offsetHeight);
              iframeWidth = Math.max(ib.scrollWidth, ib.offsetWidth);
            }
          }
        } catch (e) {
          // Cross-origin: fallback to visible/computed height
          iframeHeight =
            parseInt(iframe.getAttribute('height')) ||
            iframe.offsetHeight ||
            parseInt(window.getComputedStyle(iframe).height) ||
            0;
          iframeWidth =
            parseInt(iframe.getAttribute('width')) ||
            iframe?.offsetWidth ||
            parseInt((window.getComputedStyle(iframe) || {}).width)  || 0;
        }

        // Add based on bottom edge position, not sum
        height=height+(iframeHeight);
        if(iframeWidth){
          width = iframeWidth;
        }
      }

      return JSON.stringify({ height: height.toString(), width: width.toString() });
    })();
  '''
    : '''
(function() {
try {
  const body = document.body;
  const html = document.documentElement;

  html.style.margin = '0';
  html.style.padding = '0';
  body.style.margin = '0';
  body.style.padding = '0';
  html.style.overflow = 'visible';
  body.style.overflow = 'visible';

  // Wait until all images and iframes are fully loaded
  const imgs = document.images;
  for (let i = 0; i < imgs.length; i++) {
    if (!imgs[i].complete) return -1;
  }

  // Compute true rendered bounds
  const rect = body.getBoundingClientRect();
  const height = rect.bottom - rect.top;
  const width = rect.right - rect.left;

  // Include any absolutely positioned or floating elements outside normal flow
  const all = document.querySelectorAll('*');
  let maxBottom = height;
  let maxRight = width;
  all.forEach(el => {
    const r = el.getBoundingClientRect();
    if (r.bottom > maxBottom) maxBottom = r.bottom;
    if (r.right > maxRight) maxRight = r.right;
  });

  const finalHeight = Math.ceil(maxBottom);
  const finalWidth = Math.ceil(maxRight);

  return JSON.stringify({
    height: finalHeight.toString(),
    width: finalWidth.toString()
  });
} catch (e) {
  return JSON.stringify({ height: "400", width: "400" });
}
})();
''';