{
    "sourceFile": "plugins/screenshot/helpers.js",
    "activeCommit": 0,
    "commits": [
        {
            "activePatchIndex": 10,
            "patches": [
                {
                    "date": 1698915090622,
                    "content": "Index: \n===================================================================\n--- \n+++ \n"
                },
                {
                    "date": 1701686116953,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -298,12 +298,9 @@\n   });\n   const graphicElement = await page.$(\"#q-screenshot-service-container\");\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n-    printBackground: true,\n-    omitBackground: true,\n-    width: size.width,\n-    height: size.height,\n+    omitBackground: isTransparent,\n   });\n \n   await page.close();\n   return imageBuffer;\n"
                },
                {
                    "date": 1701686476608,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -299,8 +299,10 @@\n   const graphicElement = await page.$(\"#q-screenshot-service-container\");\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n     omitBackground: isTransparent,\n+    width: size.width,\n+    height: size.height,\n   });\n \n   await page.close();\n   return imageBuffer;\n"
                },
                {
                    "date": 1701686510736,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -300,9 +300,8 @@\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n     omitBackground: isTransparent,\n     width: size.width,\n-    height: size.height,\n   });\n \n   await page.close();\n   return imageBuffer;\n"
                },
                {
                    "date": 1701687250611,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -298,10 +298,12 @@\n   });\n   const graphicElement = await page.$(\"#q-screenshot-service-container\");\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n-    omitBackground: isTransparent,\n+    printBackground: true,\n+    omitBackground: true,\n     width: size.width,\n+    height: size.height,\n   });\n \n   await page.close();\n   return imageBuffer;\n"
                },
                {
                    "date": 1701687293917,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -298,9 +298,8 @@\n   });\n   const graphicElement = await page.$(\"#q-screenshot-service-container\");\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n-    printBackground: true,\n     omitBackground: true,\n     width: size.width,\n     height: size.height,\n   });\n"
                },
                {
                    "date": 1701687301714,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -300,9 +300,9 @@\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n     omitBackground: true,\n     width: size.width,\n-    height: size.height,\n+    height: size.height + 20,\n   });\n \n   await page.close();\n   return imageBuffer;\n"
                },
                {
                    "date": 1701692472602,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -298,11 +298,12 @@\n   });\n   const graphicElement = await page.$(\"#q-screenshot-service-container\");\n   const size = await graphicElement.boundingBox();\n   const imageBuffer = await page.pdf({\n+    printBackground: true,\n     omitBackground: true,\n     width: size.width,\n-    height: size.height + 20,\n+    height: size.height,\n   });\n \n   await page.close();\n   return imageBuffer;\n"
                },
                {
                    "date": 1702467412801,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -291,8 +291,9 @@\n     stylesheets,\n     config\n   );\n \n+  console.log(\"page\", page)\n   const html = await page.content();\n   await page.setContent(html, {\n     waitUntil: [\"domcontentloaded\", \"load\", \"networkidle0\"],\n   });\n"
                },
                {
                    "date": 1702475656676,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -291,9 +291,8 @@\n     stylesheets,\n     config\n   );\n \n-  console.log('page', page);\n   const html = await page.content();\n   await page.setContent(html, {\n     waitUntil: ['domcontentloaded', 'load', 'networkidle0'],\n   });\n"
                },
                {
                    "date": 1725527966039,
                    "content": "Index: \n===================================================================\n--- \n+++ \n@@ -24,9 +24,9 @@\n \n   return stats.puppeteer\n     .launch({\n       timeout: 120000, // Reduce chances for timeouts\n-      headless: true, // Not needed with xvfb\n+      headless: false, // Not needed with xvfb\n       args: [\n         \"--single-process\", // Reduce chances for timeouts\n         \"--no-sandbox\",\n         \"--disable-dev-shm-usage\",\n"
                }
            ],
            "date": 1698915090622,
            "name": "Commit-0",
            "content": "const puppeteer = require(\"puppeteer\");\nconst fetch = require(\"node-fetch\");\nconst PCR = require(\"puppeteer-chromium-resolver\");\nlet isFirstTime = true;\n\n// start a chromium process here\nlet browserPromise = startPcrChromiumProcess();\n\nasync function startPcrChromiumProcess() {\n  const option = {\n    revision: \"\",\n    detectionPath: \"\",\n    folderName: \".chromium-browser-snapshots\",\n    defaultHosts: [\n      \"https://storage.googleapis.com\",\n      \"https://npm.taobao.org/mirrors\",\n    ],\n    hosts: [],\n    cacheRevisions: 2,\n    retry: 3,\n    silent: false,\n  };\n  const stats = await PCR(option);\n\n  return stats.puppeteer\n    .launch({\n      timeout: 120000, // Reduce chances for timeouts\n      headless: true, // Not needed with xvfb\n      args: [\n        \"--single-process\", // Reduce chances for timeouts\n        \"--no-sandbox\",\n        \"--disable-dev-shm-usage\",\n        \"--font-render-hinting=none\",\n      ],\n      executablePath: stats.executablePath,\n      devtools: true,\n    })\n    .catch(function (error) {\n      Boom.internal(error.message);\n    });\n}\n\n// fetches assets and returns a concatenated string containing everything fetched\nasync function getConcatenatedAssets(assets, userAgent) {\n  const contentPromises = [];\n  for (let asset of assets) {\n    if (asset.content) {\n      contentPromises.push(Promise.resolve(asset.content));\n    }\n    if (asset.url) {\n      const promise = fetch(asset.url, {\n        headers: {\n          \"User-Agent\": userAgent,\n        },\n      }).then((response) => {\n        if (response.ok) {\n          return response.text();\n        } else {\n          return \"\";\n        }\n      });\n      contentPromises.push(promise);\n    }\n  }\n  const contents = await Promise.all(contentPromises);\n  return contents.join(\"\\n\");\n}\n\nasync function getFinishedPage(\n  emptyPageUrl,\n  markup,\n  scripts,\n  stylesheets,\n  config,\n  server\n) {\n  let browser = await browserPromise;\n\n  let page;\n\n  // try to open the page, if it doesn't work, launch a new browser\n  try {\n    page = await browser.newPage();\n  } catch (err) {\n    if (err.stack) {\n      server.log([\"error\"], err.stack);\n    }\n    if (err.isBoom) {\n      throw err;\n    } else {\n      server.log([\"error\"], err.message);\n    }\n\n    browserPromise = startPcrChromiumProcess();\n    browser = await browserPromise;\n    page = await browser.newPage();\n  }\n\n  try {\n    // the height of 16384 is the max height of a GL context in chromium or something\n    await page.setViewport({\n      width: config.width,\n      height: 16384,\n      deviceScaleFactor: config.dpr,\n    });\n\n    // Log the console messages of chromium\n    page.on(\"console\", (msg) => {\n      console.log(msg);\n    });\n\n    // Log the GPU information of chromium\n    if (isFirstTime) {\n      await page\n        .goto(\"chrome://gpu\", {\n          waitUntil: \"networkidle0\",\n          timeout: 20 * 60 * 1000,\n        })\n        .catch((e) => console.log(e));\n\n      const content = await page.content();\n      console.log(content);\n      server.log([\"info\"], content);\n\n      isFirstTime = false;\n    }\n\n    await page.goto(emptyPageUrl);\n  } catch (err) {\n    if (err.stack) {\n      server.log([\"error\"], err.stack);\n    }\n    if (err.isBoom) {\n      throw err;\n    } else {\n      server.log([\"error\"], err.message);\n    }\n\n    throw err;\n  }\n\n  // use strings instead of functions here as it will break in the tests otherwise.\n  const userAgent = await page.evaluate(\"navigator.userAgent\");\n\n  const styleContent = await getConcatenatedAssets(stylesheets, userAgent);\n\n  let bodyStyle = \"margin: 0; padding: 0;\";\n  if (config.background) {\n    bodyStyle += `background: ${config.background}`;\n  }\n\n  const content = `\n    <!DOCTYPE html>\n    <html>\n      <head>\n        <style>${styleContent}</style>\n      </head>\n      <body style=\"${bodyStyle}\">\n        <div id=\"q-screenshot-service-container\"\n             style=\"padding: ${config.padding}; width: ${config.width}px;; height: 100%\">\n          ${markup}\n        </div>\n      </body>\n    </html>`;\n\n  await page.setContent(content, {\n    waitUntil: [\"domcontentloaded\", \"networkidle0\"],\n  });\n\n  const scriptContent = await getConcatenatedAssets(scripts, userAgent);\n\n  if (scriptContent) {\n    await page.mainFrame().addScriptTag({\n      content: scriptContent,\n    });\n  }\n\n  // Temporary fix - in the long run we need a solution for all Q tools\n  if (config.qTool === \"locator_map\") {\n    let retry = 0;\n\n    const qId = `_q_locator_map${config.qId}`;\n\n    while (retry < 2) {\n      try {\n        if (retry === 1) {\n          await page.reload({\n            waitUntil: [\"domcontentloaded\", \"networkidle0\"],\n          });\n        }\n\n        await page.waitForFunction(\n          (qId) => window[qId]?.isLoaded === true,\n          {\n            timeout: 20000,\n          },\n          qId\n        );\n\n        return page;\n      } catch (err) {\n        if (err.name === \"TimeoutError\") {\n          retry++;\n          if (retry >= 2) {\n            throw err;\n          }\n        } else if (err.stack) {\n          server.log([\"error\"], err.stack);\n        } else if (err.isBoom) {\n          throw err;\n        } else {\n          server.log([\"error\"], err.message);\n        }\n      }\n    }\n  }\n\n  // wait for the next idle callback (to have most probably finished all work)\n  await page.evaluate(`() => {\n    return new Promise((resolve, reject) => {\n      requestIdleCallback(resolve);\n    });\n  }`);\n\n  // we support a wait parameter, this is a number in milliseconds to wait for\n  if (config.waitBeforeScreenshot) {\n    await page.waitForTimeout(config.waitBeforeScreenshot);\n  }\n\n  return page;\n}\n\nasync function getScreenshotImage(\n  emptyPageUrl,\n  markup,\n  scripts,\n  stylesheets,\n  config,\n  server\n) {\n  let isTransparent = false;\n  if (!config.background || config.background === \"none\") {\n    isTransparent = true;\n  }\n\n  let imageBuffer;\n\n  try {\n    const page = await getFinishedPage(\n      emptyPageUrl,\n      markup,\n      scripts,\n      stylesheets,\n      config,\n      server\n    );\n\n    const graphicElement = await page.$(\"#q-screenshot-service-container\");\n\n    imageBuffer = await graphicElement.screenshot({\n      omitBackground: isTransparent,\n    });\n\n    await page.close();\n  } catch (err) {\n    if (err.stack) {\n      server.log([\"error\"], err.stack);\n    }\n    if (err.isBoom) {\n      throw err;\n    } else {\n      server.log([\"error\"], err.message);\n    }\n\n    throw err;\n  }\n\n  return imageBuffer;\n}\n\nasync function getPDF(emptyPageUrl, markup, scripts, stylesheets, config) {\n  let isTransparent = false;\n  if (!config.background || config.background === \"none\") {\n    isTransparent = true;\n  }\n\n  const page = await getFinishedPage(\n    emptyPageUrl,\n    markup,\n    scripts,\n    stylesheets,\n    config\n  );\n\n  const html = await page.content();\n  await page.setContent(html, {\n    waitUntil: [\"domcontentloaded\", \"load\", \"networkidle0\"],\n  });\n  const graphicElement = await page.$(\"#q-screenshot-service-container\");\n  const size = await graphicElement.boundingBox();\n  const imageBuffer = await page.pdf({\n    printBackground: true,\n    omitBackground: true,\n    width: size.width,\n    height: size.height,\n  });\n\n  await page.close();\n  return imageBuffer;\n}\n\nasync function getScreenshotInfo(\n  emptyPageUrl,\n  markup,\n  scripts,\n  stylesheets,\n  config,\n  server\n) {\n  const page = await getFinishedPage(\n    emptyPageUrl,\n    markup,\n    scripts,\n    stylesheets,\n    config,\n    server\n  );\n\n  const graphicElement = await page.$(\"#q-screenshot-service-container\");\n  const bbox = await graphicElement.boundingBox();\n\n  return {\n    width: bbox.width,\n    height: bbox.height,\n  };\n}\n\nfunction getInnerWidth(width, padding) {\n  if (!width) {\n    return null;\n  }\n  // if padding is given, we need to know if it's in pixel to calculate with the width\n  if (padding !== undefined) {\n    // split the padding by space\n    const units = padding\n      .split(\" \")\n      .map((paddingPos) => {\n        return paddingPos.match(\n          new RegExp(/^$|^(([0-9.]+)(px|em|ex|%|in|cm|mm|pt|pc|vh|vw)?([ ])?)$/)\n        );\n      })\n      .filter((match) => {\n        return Array.isArray(match);\n      })\n      .map((match) => {\n        if (match[3] === undefined) {\n          // if no unit given, px is default\n          return \"px\";\n        }\n        return match[3]; // the original unit or px if it was undefined before\n      })\n      .reduce((units, unit) => {\n        // unique\n        if (!units.includes(unit)) {\n          units.push(unit);\n        }\n        return units;\n      }, []);\n\n    // if we have only pixels, we can move on\n    if (units.length === 1 && units[0] === \"px\") {\n      const paddingPos = padding.split(\" \");\n      if (paddingPos.length === 1) {\n        // if there is one padding, this is for left and right, the regex separates the number and the unit\n        const pixelNumber = paddingPos[0].match(\n          new RegExp(/^$|^(([0-9.]+)(.*)?)$/)\n        )[2];\n        width = width - 2 * pixelNumber;\n      }\n      if (paddingPos.length === 2 || paddingPos.length === 3) {\n        // for 2 or 3 paddings, we take the second one, as this is left and right padding\n        const pixelNumber = paddingPos[1].match(\n          new RegExp(/^$|^(([0-9.]+)(.*)?)$/)\n        )[2];\n        width = width - 2 * pixelNumber;\n      }\n      if (paddingPos.length === 4) {\n        // if we have 4 paddings, the 2nd and 4th are left and right\n        const pixelNumberLeft = paddingPos[1].match(\n          new RegExp(/^$|^(([0-9.]+)(.*)?)$/)\n        )[2];\n        const pixelNumberRight = paddingPos[3].match(\n          new RegExp(/^$|^(([0-9.]+)(.*)?)$/)\n        )[2];\n        width = width - pixelNumberLeft - pixelNumberRight;\n      }\n    }\n  }\n\n  return width;\n}\n\nmodule.exports = {\n  getScreenshotImage: getScreenshotImage,\n  getScreenshotInfo: getScreenshotInfo,\n  getInnerWidth: getInnerWidth,\n  getPDF,\n};\n"
        }
    ]
}