emf_win.cc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "printing/emf_win.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <memory>
  8. #include "base/check_op.h"
  9. #include "base/files/file.h"
  10. #include "base/files/file_path.h"
  11. #include "base/notreached.h"
  12. #include "base/numerics/safe_conversions.h"
  13. #include "printing/mojom/print.mojom.h"
  14. #include "skia/ext/skia_utils_win.h"
  15. #include "third_party/skia/include/core/SkBitmap.h"
  16. #include "ui/gfx/codec/jpeg_codec.h"
  17. #include "ui/gfx/codec/png_codec.h"
  18. #include "ui/gfx/geometry/rect.h"
  19. #include "ui/gfx/geometry/size.h"
  20. namespace printing {
  21. namespace {
  22. bool DIBFormatNativelySupported(HDC dc,
  23. uint32_t escape,
  24. const BYTE* bits,
  25. int size) {
  26. BOOL supported = FALSE;
  27. if (ExtEscape(dc, QUERYESCSUPPORT, sizeof(escape),
  28. reinterpret_cast<LPCSTR>(&escape), 0, 0) > 0) {
  29. ExtEscape(dc, escape, size, reinterpret_cast<LPCSTR>(bits),
  30. sizeof(supported), reinterpret_cast<LPSTR>(&supported));
  31. }
  32. return !!supported;
  33. }
  34. } // namespace
  35. Emf::Emf() : emf_(nullptr), hdc_(nullptr) {}
  36. Emf::~Emf() {
  37. Close();
  38. }
  39. void Emf::Close() {
  40. DCHECK(!hdc_);
  41. if (emf_)
  42. DeleteEnhMetaFile(emf_);
  43. emf_ = nullptr;
  44. }
  45. bool Emf::InitToFile(const base::FilePath& metafile_path) {
  46. DCHECK(!emf_ && !hdc_);
  47. hdc_ = CreateEnhMetaFile(nullptr, metafile_path.value().c_str(), nullptr,
  48. nullptr);
  49. DCHECK(hdc_);
  50. return !!hdc_;
  51. }
  52. bool Emf::InitFromFile(const base::FilePath& metafile_path) {
  53. DCHECK(!emf_ && !hdc_);
  54. emf_ = GetEnhMetaFile(metafile_path.value().c_str());
  55. DCHECK(emf_);
  56. return !!emf_;
  57. }
  58. bool Emf::Init() {
  59. DCHECK(!emf_ && !hdc_);
  60. hdc_ = CreateEnhMetaFile(nullptr, nullptr, nullptr, nullptr);
  61. DCHECK(hdc_);
  62. return !!hdc_;
  63. }
  64. bool Emf::InitFromData(base::span<const uint8_t> data) {
  65. DCHECK(!emf_ && !hdc_);
  66. if (!base::IsValueInRangeForNumericType<UINT>(data.size()))
  67. return false;
  68. emf_ = SetEnhMetaFileBits(static_cast<UINT>(data.size()), data.data());
  69. return !!emf_;
  70. }
  71. bool Emf::FinishDocument() {
  72. DCHECK(!emf_ && hdc_);
  73. emf_ = CloseEnhMetaFile(hdc_);
  74. DCHECK(emf_);
  75. hdc_ = nullptr;
  76. return !!emf_;
  77. }
  78. bool Emf::Playback(HDC hdc, const RECT* rect) const {
  79. DCHECK(emf_ && !hdc_);
  80. RECT bounds;
  81. if (!rect) {
  82. // Get the natural bounds of the EMF buffer.
  83. bounds = GetPageBounds(1).ToRECT();
  84. rect = &bounds;
  85. }
  86. return PlayEnhMetaFile(hdc, emf_, rect) != 0;
  87. }
  88. bool Emf::SafePlayback(HDC context) const {
  89. DCHECK(emf_ && !hdc_);
  90. XFORM base_matrix;
  91. if (!GetWorldTransform(context, &base_matrix)) {
  92. NOTREACHED();
  93. return false;
  94. }
  95. Emf::EnumerationContext playback_context;
  96. playback_context.base_matrix = &base_matrix;
  97. gfx::Rect bound = GetPageBounds(1);
  98. RECT rect = bound.ToRECT();
  99. return bound.IsEmpty() ||
  100. EnumEnhMetaFile(context, emf_, &Emf::SafePlaybackProc,
  101. reinterpret_cast<void*>(&playback_context),
  102. &rect) != 0;
  103. }
  104. gfx::Rect Emf::GetPageBounds(unsigned int page_number) const {
  105. DCHECK(emf_ && !hdc_);
  106. DCHECK_EQ(1U, page_number);
  107. ENHMETAHEADER header;
  108. if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) {
  109. NOTREACHED();
  110. return gfx::Rect();
  111. }
  112. // Add 1 to right and bottom because it's inclusive rectangle.
  113. // See ENHMETAHEADER.
  114. return gfx::Rect(header.rclBounds.left, header.rclBounds.top,
  115. header.rclBounds.right - header.rclBounds.left + 1,
  116. header.rclBounds.bottom - header.rclBounds.top + 1);
  117. }
  118. unsigned int Emf::GetPageCount() const {
  119. return 1;
  120. }
  121. HDC Emf::context() const {
  122. return hdc_;
  123. }
  124. uint32_t Emf::GetDataSize() const {
  125. DCHECK(emf_ && !hdc_);
  126. return GetEnhMetaFileBits(emf_, 0, nullptr);
  127. }
  128. bool Emf::GetData(void* buffer, uint32_t size) const {
  129. DCHECK(emf_ && !hdc_);
  130. DCHECK(buffer && size);
  131. uint32_t size2 =
  132. GetEnhMetaFileBits(emf_, size, reinterpret_cast<BYTE*>(buffer));
  133. DCHECK(size2 == size);
  134. return size2 == size && size2 != 0;
  135. }
  136. bool Emf::ShouldCopySharedMemoryRegionData() const {
  137. // `InitFromData()` operates directly upon memory provide to it, so any
  138. // caller for cases where this data is shared cross-process should have the
  139. // data copied before it is operated upon.
  140. return true;
  141. }
  142. mojom::MetafileDataType Emf::GetDataType() const {
  143. return mojom::MetafileDataType::kEMF;
  144. }
  145. int CALLBACK Emf::SafePlaybackProc(HDC hdc,
  146. HANDLETABLE* handle_table,
  147. const ENHMETARECORD* record,
  148. int objects_count,
  149. LPARAM param) {
  150. Emf::EnumerationContext* context =
  151. reinterpret_cast<Emf::EnumerationContext*>(param);
  152. context->handle_table = handle_table;
  153. context->objects_count = objects_count;
  154. context->hdc = hdc;
  155. Record record_instance(record);
  156. bool success = record_instance.SafePlayback(context);
  157. DCHECK(success);
  158. return 1;
  159. }
  160. Emf::EnumerationContext::EnumerationContext() {
  161. memset(this, 0, sizeof(*this));
  162. }
  163. Emf::Record::Record(const ENHMETARECORD* record) : record_(record) {
  164. DCHECK(record_);
  165. }
  166. bool Emf::Record::Play(Emf::EnumerationContext* context) const {
  167. return 0 != PlayEnhMetaFileRecord(context->hdc, context->handle_table,
  168. record_, context->objects_count);
  169. }
  170. bool Emf::Record::SafePlayback(Emf::EnumerationContext* context) const {
  171. // For EMF field description, see [MS-EMF] Enhanced Metafile Format
  172. // Specification.
  173. //
  174. // This is the second major EMF breakage I get; the first one being
  175. // SetDCBrushColor/SetDCPenColor/DC_PEN/DC_BRUSH being silently ignored.
  176. //
  177. // This function is the guts of the fix for bug 1186598. Some printer drivers
  178. // somehow choke on certain EMF records, but calling the corresponding
  179. // function directly on the printer HDC is fine. Still, playing the EMF record
  180. // fails. Go figure.
  181. //
  182. // The main issue is that SetLayout is totally unsupported on these printers
  183. // (HP 4500/4700). I used to call SetLayout and I stopped. I found out this is
  184. // not sufficient because GDI32!PlayEnhMetaFile internally calls SetLayout(!)
  185. // Damn.
  186. //
  187. // So I resorted to manually parse the EMF records and play them one by one.
  188. // The issue with this method compared to using PlayEnhMetaFile to play back
  189. // an EMF buffer is that the later silently fixes the matrix to take in
  190. // account the matrix currently loaded at the time of the call.
  191. // The matrix magic is done transparently when using PlayEnhMetaFile but since
  192. // I'm processing one field at a time, I need to do the fixup myself. Note
  193. // that PlayEnhMetaFileRecord doesn't fix the matrix correctly even when
  194. // called inside an EnumEnhMetaFile loop. Go figure (bis).
  195. //
  196. // So when I see a EMR_SETWORLDTRANSFORM and EMR_MODIFYWORLDTRANSFORM, I need
  197. // to fix the matrix according to the matrix previously loaded before playing
  198. // back the buffer. Otherwise, the previously loaded matrix would be ignored
  199. // and the EMF buffer would always be played back at its native resolution.
  200. // Duh.
  201. //
  202. // I also use this opportunity to skip over eventual EMR_SETLAYOUT record that
  203. // could remain.
  204. //
  205. // Another tweak we make is for JPEGs/PNGs in calls to StretchDIBits.
  206. // (Our Pepper plugin code uses a JPEG). If the printer does not support
  207. // JPEGs/PNGs natively we decompress the JPEG/PNG and then set it to the
  208. // device.
  209. // TODO(sanjeevr): We should also add JPEG/PNG support for SetSIBitsToDevice
  210. //
  211. // We also process any custom EMR_GDICOMMENT records which are our
  212. // placeholders for StartPage and EndPage.
  213. // Note: I should probably care about view ports and clipping, eventually.
  214. bool res = false;
  215. const XFORM* base_matrix = context->base_matrix;
  216. switch (record()->iType) {
  217. case EMR_STRETCHDIBITS: {
  218. const EMRSTRETCHDIBITS* sdib_record =
  219. reinterpret_cast<const EMRSTRETCHDIBITS*>(record());
  220. const BYTE* record_start = reinterpret_cast<const BYTE*>(record());
  221. const BITMAPINFOHEADER* bmih = reinterpret_cast<const BITMAPINFOHEADER*>(
  222. record_start + sdib_record->offBmiSrc);
  223. const BYTE* bits = record_start + sdib_record->offBitsSrc;
  224. bool play_normally = true;
  225. res = false;
  226. HDC hdc = context->hdc;
  227. std::unique_ptr<SkBitmap> bitmap;
  228. if (bmih->biCompression == BI_JPEG) {
  229. if (!DIBFormatNativelySupported(hdc, CHECKJPEGFORMAT, bits,
  230. bmih->biSizeImage)) {
  231. play_normally = false;
  232. bitmap = gfx::JPEGCodec::Decode(bits, bmih->biSizeImage);
  233. DCHECK(bitmap);
  234. DCHECK(!bitmap->isNull());
  235. }
  236. } else if (bmih->biCompression == BI_PNG) {
  237. if (!DIBFormatNativelySupported(hdc, CHECKPNGFORMAT, bits,
  238. bmih->biSizeImage)) {
  239. play_normally = false;
  240. bitmap = std::make_unique<SkBitmap>();
  241. bool png_ok =
  242. gfx::PNGCodec::Decode(bits, bmih->biSizeImage, &*bitmap);
  243. DCHECK(png_ok);
  244. DCHECK(!bitmap->isNull());
  245. }
  246. }
  247. if (play_normally) {
  248. res = Play(context);
  249. } else {
  250. const uint32_t* pixels =
  251. static_cast<const uint32_t*>(bitmap->getPixels());
  252. if (!pixels) {
  253. NOTREACHED();
  254. return false;
  255. }
  256. BITMAPINFOHEADER bmi = {0};
  257. skia::CreateBitmapHeaderForN32SkBitmap(*bitmap, &bmi);
  258. res =
  259. (0 != StretchDIBits(hdc, sdib_record->xDest, sdib_record->yDest,
  260. sdib_record->cxDest, sdib_record->cyDest,
  261. sdib_record->xSrc, sdib_record->ySrc,
  262. sdib_record->cxSrc, sdib_record->cySrc, pixels,
  263. reinterpret_cast<const BITMAPINFO*>(&bmi),
  264. sdib_record->iUsageSrc, sdib_record->dwRop));
  265. }
  266. break;
  267. }
  268. case EMR_SETWORLDTRANSFORM: {
  269. DCHECK_EQ(record()->nSize, sizeof(DWORD) * 2 + sizeof(XFORM));
  270. const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
  271. HDC hdc = context->hdc;
  272. if (base_matrix) {
  273. res = 0 != SetWorldTransform(hdc, base_matrix) &&
  274. ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
  275. } else {
  276. res = 0 != SetWorldTransform(hdc, xform);
  277. }
  278. break;
  279. }
  280. case EMR_MODIFYWORLDTRANSFORM: {
  281. DCHECK_EQ(record()->nSize,
  282. sizeof(DWORD) * 2 + sizeof(XFORM) + sizeof(DWORD));
  283. const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
  284. const DWORD* option = reinterpret_cast<const DWORD*>(xform + 1);
  285. HDC hdc = context->hdc;
  286. switch (*option) {
  287. case MWT_IDENTITY:
  288. if (base_matrix) {
  289. res = 0 != SetWorldTransform(hdc, base_matrix);
  290. } else {
  291. res = 0 != ModifyWorldTransform(hdc, xform, MWT_IDENTITY);
  292. }
  293. break;
  294. case MWT_LEFTMULTIPLY:
  295. case MWT_RIGHTMULTIPLY:
  296. res = 0 != ModifyWorldTransform(hdc, xform, *option);
  297. break;
  298. case 4: // MWT_SET
  299. if (base_matrix) {
  300. res = 0 != SetWorldTransform(hdc, base_matrix) &&
  301. ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
  302. } else {
  303. res = 0 != SetWorldTransform(hdc, xform);
  304. }
  305. break;
  306. default:
  307. res = false;
  308. break;
  309. }
  310. break;
  311. }
  312. case EMR_SETLAYOUT:
  313. // Ignore it.
  314. res = true;
  315. break;
  316. default: {
  317. res = Play(context);
  318. break;
  319. }
  320. }
  321. return res;
  322. }
  323. void Emf::StartPage(const gfx::Size& /*page_size*/,
  324. const gfx::Rect& /*content_area*/,
  325. float /*scale_factor*/,
  326. mojom::PageOrientation /*page_orientation*/) {}
  327. bool Emf::FinishPage() {
  328. return true;
  329. }
  330. Emf::Enumerator::Enumerator(const Emf& emf, HDC context, const RECT* rect) {
  331. items_.clear();
  332. if (!EnumEnhMetaFile(context, emf.emf(), &Emf::Enumerator::EnhMetaFileProc,
  333. reinterpret_cast<void*>(this), rect)) {
  334. NOTREACHED();
  335. items_.clear();
  336. }
  337. DCHECK_EQ(context_.hdc, context);
  338. }
  339. Emf::Enumerator::~Enumerator() {}
  340. Emf::Enumerator::const_iterator Emf::Enumerator::begin() const {
  341. return items_.begin();
  342. }
  343. Emf::Enumerator::const_iterator Emf::Enumerator::end() const {
  344. return items_.end();
  345. }
  346. int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc,
  347. HANDLETABLE* handle_table,
  348. const ENHMETARECORD* record,
  349. int objects_count,
  350. LPARAM param) {
  351. Enumerator& emf = *reinterpret_cast<Enumerator*>(param);
  352. if (!emf.context_.handle_table) {
  353. DCHECK(!emf.context_.handle_table);
  354. DCHECK(!emf.context_.objects_count);
  355. emf.context_.handle_table = handle_table;
  356. emf.context_.objects_count = objects_count;
  357. emf.context_.hdc = hdc;
  358. } else {
  359. DCHECK_EQ(emf.context_.handle_table, handle_table);
  360. DCHECK_EQ(emf.context_.objects_count, objects_count);
  361. DCHECK_EQ(emf.context_.hdc, hdc);
  362. }
  363. emf.items_.push_back(Record(record));
  364. return 1;
  365. }
  366. } // namespace printing