--- a/widget/windows/gtest/TestEMFConversion.cpp
+++ b/widget/windows/gtest/TestEMFConversion.cpp
@@ -133,10 +133,306 @@ TEST(TestEMFConversion, TestInsufficient
pageHeight = -1;
result = PDFHelper->DrawPageToFile(emfPath.get(), 0,
pageWidth, pageHeight);
ASSERT_FALSE(result);
PDFHelper->CloseDocument();
}
+class EMFtoBitmapHelper
+{
+public:
+ EMFtoBitmapHelper();
+ ~EMFtoBitmapHelper();
+
+ // Convert an EMF to a bitmap and retrive the bitmap content
+ DWORD GetBitmapViaEMF(nsAutoString aEMFFile, Vector<char>& aBitmapBuf);
+
+private:
+ bool CalculateWidthAndHeight(HENHMETAFILE aEmf,
+ LONG& aWidth, LONG& aHeight);
+ bool SetWhiteColorToMemoryDC();
+ DWORD GetBitmap(Vector<char>& aBitmapBuf);
+
+ HDC mDC;
+ HDC mMemDC;
+ HBITMAP mBitmap;
+};
+
+EMFtoBitmapHelper::EMFtoBitmapHelper()
+ : mDC(NULL)
+ , mMemDC(NULL)
+ , mBitmap(NULL)
+{
+}
+
+EMFtoBitmapHelper::~EMFtoBitmapHelper()
+{
+ if (mBitmap) {
+ ::DeleteObject(mBitmap);
+ }
+
+ if (mMemDC) {
+ ::DeleteObject(mMemDC);
+ }
+
+ if (mDC) {
+ ::ReleaseDC(NULL, mDC);
+ }
+}
+
+bool
+EMFtoBitmapHelper::SetWhiteColorToMemoryDC()
+{
+ if (mMemDC == NULL) {
+ return false;
+ }
+
+ // Set brush to desired background color
+ HBRUSH backBrush= reinterpret_cast<HBRUSH>(RGB(255, 255, 255));
+ // Save old brush
+ HBRUSH oldBrush = reinterpret_cast<HBRUSH>(::SelectObject(mMemDC, backBrush));
+
+ RECT rect;
+ int clipBoxType = ::GetClipBox(mMemDC, &rect);
+ if (clipBoxType == ERROR) {
+ return false;
+ }
+
+ // paint the given rectangle using the brush that is currently selected
+ // into the specified device context
+ if (!::PatBlt(mMemDC, rect.left, rect.top, abs(rect.left - rect.right),
+ abs(rect.top-rect.bottom ), PATCOPY)) {
+ return false;
+ }
+
+ // Select back the old brush
+ ::SelectObject(mMemDC, oldBrush);
+ return true;
+}
+
+bool
+EMFtoBitmapHelper::CalculateWidthAndHeight(HENHMETAFILE aEmf,
+ LONG& aWidth, LONG& aHeight)
+{
+ if (aEmf == NULL || mMemDC == NULL) {
+ return false;
+ }
+
+ // Get the header from the enhanced metafile.
+ ENHMETAHEADER emh;
+ memset(&emh, 0, sizeof(ENHMETAHEADER));
+ emh.nSize = sizeof(ENHMETAHEADER);
+ if(::GetEnhMetaFileHeader(aEmf, sizeof(ENHMETAHEADER), &emh) == 0 ) {
+ return false;
+ }
+
+ // Get the characteristics of the output device.
+ int pixelsX = ::GetDeviceCaps(mMemDC, HORZRES);
+ int pixelsY = ::GetDeviceCaps(mMemDC, VERTRES);
+ int mmX = ::GetDeviceCaps(mMemDC, HORZSIZE);
+ int mmY = ::GetDeviceCaps(mMemDC, VERTSIZE);
+ if (mmX == 0 || mmY == 0) {
+ return false;
+ }
+
+ // The metafile intended dimension is given 0.01 mm units. But, the units of
+ // bitmap dimension are pixels. Therefore, we need to convert those to device
+ // units on the target device.
+ LONG top = static_cast<LONG>(emh.rclFrame.top * pixelsY / (mmY * 100.0f));
+ LONG left = static_cast<LONG>(emh.rclFrame.left * pixelsX / (mmX * 100.0f));
+ LONG right = static_cast<LONG>(emh.rclFrame.right * pixelsX / (mmX * 100.0f));
+ LONG bottom = static_cast<LONG>(emh.rclFrame.bottom * pixelsY /
+ (mmY * 100.0f));
+
+ // Calculate the width and height of the metafile
+ aWidth = abs(left - right);
+ aHeight = abs(top - bottom);
+ if (aWidth == 0 || aHeight == 0) {
+ return false;
+ }
+
+ return true;
+}
+
+DWORD
+EMFtoBitmapHelper::GetBitmapViaEMF(nsAutoString aEMFFile, Vector<char>& aBitmapBuf)
+{
+ if (mDC == NULL) {
+ mDC = ::GetDC(NULL);
+ if (mDC == NULL) {
+ return 0;
+ }
+ }
+
+ // Create a Memory DC compatible to WindowDC
+ if (mMemDC == NULL) {
+ mMemDC = ::CreateCompatibleDC(mDC);
+ if (mMemDC == NULL) {
+ return 0;
+ }
+ }
+
+ // Get the Handle from the enhanced metafile
+ HENHMETAFILE hEMF = ::GetEnhMetaFileW(aEMFFile.get());
+ if (hEMF == NULL) {
+ return 0;
+ }
+
+ // Calculate the width and height of the metafile
+ LONG width;
+ LONG height;
+ if (!CalculateWidthAndHeight(hEMF, width, height)) {
+ ::DeleteEnhMetaFile(hEMF);
+ return 0;
+ }
+ RECT rect = {0, 0, width, height};
+
+ // Create a bitmap compatible
+ if (mBitmap) {
+ ::DeleteObject(mBitmap);
+ }
+ mBitmap = ::CreateCompatibleBitmap(mDC, width, height);
+ if (mBitmap == NULL) {
+ ::DeleteEnhMetaFile(hEMF);
+ return 0;
+ }
+
+ // Select the bitmap into the Mem DC
+ HBITMAP oldBitmap = reinterpret_cast<HBITMAP>(::SelectObject(mMemDC, mBitmap));
+
+ // Paint the background of the DC to White
+ if (!SetWhiteColorToMemoryDC()) {
+ ::DeleteEnhMetaFile(hEMF);
+ return 0;
+ }
+
+ // Now play the enhanced metafile into the memory DC;
+ bool result = ::PlayEnhMetaFile(mMemDC, hEMF, &rect);
+ ::DeleteEnhMetaFile(hEMF);
+
+ // Select back the old bitmap
+ ::SelectObject(mMemDC, oldBitmap);
+
+ if (!result) {
+ return 0;
+ }
+
+ return GetBitmap(aBitmapBuf);
+}
+
+DWORD
+EMFtoBitmapHelper::GetBitmap(Vector<char>& aBitmapBuf)
+{
+ if (mDC == NULL || mBitmap == NULL) {
+ return 0;
+ }
+
+ BITMAPINFO bitmapInfo = {0};
+
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ if (!::GetDIBits(mDC, mBitmap, 0, 0, NULL, &bitmapInfo, DIB_RGB_COLORS)) {
+ return 0;
+ }
+
+ if (!aBitmapBuf.initCapacity(bitmapInfo.bmiHeader.biSizeImage)) {
+ return 0;
+ }
+
+ // calculate the size in BYTEs of the additional
+ // memory needed for the bmiColor table
+ int AdditionalMemory = 0;
+ switch (bitmapInfo.bmiHeader.biBitCount) {
+ case 1:
+ AdditionalMemory = 1 * sizeof(RGBQUAD);
+ break;
+ case 4:
+ AdditionalMemory = 15 * sizeof(RGBQUAD);
+ break;
+ case 8:
+ AdditionalMemory = 255 * sizeof(RGBQUAD);
+ break;
+ }
+
+ // we have to allocate room for the bmiColor table that will be
+ // attached to our BITMAPINFO variables
+ Vector<char> tempBuf;
+ if (!tempBuf.initCapacity(sizeof(BITMAPINFO) + AdditionalMemory)) {
+ return 0;
+ }
+ memset(tempBuf.begin(), 0, sizeof(BITMAPINFO) + AdditionalMemory);
+ memcpy(tempBuf.begin(), &bitmapInfo, sizeof(BITMAPINFO));
+ PBITMAPINFO pBitmapInfoLeft = reinterpret_cast<PBITMAPINFO>(tempBuf.begin());
+
+ // zero out the bitmap bit buffers
+ memset(aBitmapBuf.begin(), 0, bitmapInfo.bmiHeader.biSizeImage);
+ if (!::GetDIBits(mDC, mBitmap, 0,
+ pBitmapInfoLeft->bmiHeader.biHeight,
+ aBitmapBuf.begin(),
+ pBitmapInfoLeft, DIB_RGB_COLORS)) {
+ return 0;
+ }
+
+ return bitmapInfo.bmiHeader.biSizeImage;
+}
+
+TEST(TestEMFConversion, CompareEMFbyBitmap)
+{
+ UniquePtr<PDFViaEMFPrintHelper> PDFHelper =
+ CreatePrintHelper("PrinterTestPage.pdf");
+ ASSERT_NE(PDFHelper, nullptr);
+
+ // Convert a PDF file to an EMF file(PrinterTestPage.pdf -> gtest.emf)
+ nsAutoString emfPath;
+ nsresult rv = GetFilePathViaSpecialDirectory(NS_OS_TEMP_DIR,
+ "gtest.emf",
+ emfPath);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ int pageWidth = 4961;
+ int pageHeight = 7016;
+ bool result = PDFHelper->DrawPageToFile(emfPath.get(), 0,
+ pageWidth, pageHeight);
+ ASSERT_TRUE(result);
+
+ PDFHelper->CloseDocument();
+
+ // Check the EMF file size if it is great than zero
+ RefPtr<nsLocalFile> savedFile = new nsLocalFile();
+ savedFile->InitWithPath(emfPath);
+ RefPtr<nsFileInputStream> inputStream = new nsFileInputStream();
+ rv = inputStream->Init(savedFile,
+ /* ioFlags */ PR_RDONLY,
+ /* perm */ -1,
+ /* behaviorFlags */ 0);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ int64_t size = 0;
+ inputStream->GetSize(&size);
+ ASSERT_GT(size, 0);
+
+ // Get the reference file, PrinterTestPage_ref.emf.
+ nsAutoString emfPathRef;
+ rv = GetFilePathViaSpecialDirectory(NS_OS_CURRENT_WORKING_DIR,
+ "PrinterTestPage_ref.emf",
+ emfPathRef);
+ ASSERT_TRUE(NS_SUCCEEDED(rv));
+
+ UniquePtr<EMFtoBitmapHelper> bitmapHelper =
+ MakeUnique<EMFtoBitmapHelper>();
+
+ Vector<char> bitmap;
+ DWORD bitmapSize = bitmapHelper->GetBitmapViaEMF(emfPath, bitmap);
+
+ UniquePtr<EMFtoBitmapHelper> bitmapHelperRef =
+ MakeUnique<EMFtoBitmapHelper>();
+
+ Vector<char> bitmapRef;
+ DWORD bitmapSizeRef = bitmapHelperRef->GetBitmapViaEMF(emfPathRef, bitmapRef);
+
+ ASSERT_TRUE((bitmapSize != 0) && (bitmapSize == bitmapSizeRef));
+ ASSERT_TRUE(memcmp(bitmap.begin(), bitmapRef.begin(),
+ bitmapSize) == 0);
+}
+
} // namespace widget
} // namespace mozilla
\ No newline at end of file