Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1371 lines
27 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. emfspool.cxx
  5. Abstract:
  6. EMF spooling functions
  7. Environment:
  8. Windows NT GDI
  9. Revision History:
  10. 01/09/97 -davidx-
  11. Created it.
  12. --*/
  13. #define NO_STRICT
  14. extern "C" {
  15. #if defined(_GDIPLUS_)
  16. #include <gpprefix.h>
  17. #endif
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <stddef.h>
  22. #include <windows.h> // GDI function declarations.
  23. #include <winerror.h>
  24. #include "firewall.h"
  25. #define __CPLUSPLUS
  26. #include <winspool.h>
  27. #include <wingdip.h>
  28. #include "ntgdistr.h"
  29. #include "winddi.h"
  30. #include "hmgshare.h"
  31. #include "icm.h"
  32. #include "local.h" // Local object support.
  33. #include "gdiicm.h"
  34. #include "metadef.h" // Metafile record type constants.
  35. }
  36. #include "rectl.hxx"
  37. #include "mfdc.hxx" // Metafile DC class declarations.
  38. //
  39. // Class for representing extra information used during EMF spooling
  40. //
  41. BOOL
  42. EMFSpoolData::Init(
  43. HANDLE hSpooler,
  44. BOOL banding
  45. )
  46. /*++
  47. Routine Description:
  48. Initialize an EMFSpoolData object
  49. Arguments:
  50. hSpooler - Spooler handle to the current printer
  51. banding - Whether GDI is doing banding on the current DC
  52. Return Value:
  53. TRUE if successful, FALSE if there is an error
  54. --*/
  55. {
  56. TRACE_EMFSPL(("EMFSpoolData::Init - banding = %d ...\n", banding));
  57. //
  58. // initialize all fields to default values
  59. //
  60. signature = 'LPSE';
  61. hPrinter = hSpooler;
  62. bBanding = banding;
  63. pmdcActive = NULL;
  64. scratchBuf = fontBuf = NULL;
  65. ResetMappingState();
  66. //
  67. // Get a handle to the EMF spool file
  68. //
  69. hFile = bBanding ?
  70. GetTempSpoolFileHandle() :
  71. fpGetSpoolFileHandle(hPrinter);
  72. if (hFile == INVALID_HANDLE_VALUE)
  73. {
  74. WARNING("GetSpoolFileHandle failed\n");
  75. return FALSE;
  76. }
  77. //
  78. // Map the spooler file
  79. //
  80. return MapFile();
  81. }
  82. VOID
  83. EMFSpoolData::Cleanup()
  84. {
  85. UnmapFile();
  86. FreeTempBuffers();
  87. }
  88. PVOID
  89. EMFSpoolData::GetPtr(UINT32 inOffset, UINT32 inSize)
  90. {
  91. PVOID ptr = emfc.ObtainPtr(currentOffset + inOffset, inSize);
  92. return ptr;
  93. }
  94. VOID
  95. EMFSpoolData::ReleasePtr(PVOID inPtr)
  96. {
  97. emfc.ReleasePtr(inPtr);
  98. }
  99. PVOID
  100. EMFSpoolData::GetPtrUsingSignedOffset(INT32 inOffset, UINT32 inSize)
  101. {
  102. if((inOffset + (INT32) currentOffset) < 0)
  103. {
  104. WARNING("EMFSpoolData::GetPtrUsingSignedOffset() Bad offset\n");
  105. return NULL;
  106. }
  107. PVOID ptr = emfc.ObtainPtr((UINT32) (currentOffset + inOffset), inSize);
  108. return ptr;
  109. }
  110. BOOL
  111. EMFSpoolData::WriteData(
  112. PVOID buffer,
  113. DWORD size
  114. )
  115. /*++
  116. Routine Description:
  117. Write data to the end of mapped file
  118. Arguments:
  119. buffer - Pointer to data buffer
  120. size - Size of data buffer
  121. Return Value:
  122. TRUE if successful, FALSE if there is an error
  123. --*/
  124. {
  125. ASSERTGDI(size != 0, "WriteData: size is 0\n");
  126. if(!bMapping)
  127. return FALSE;
  128. //
  129. // Check if the current buffer is used for recording EMF data
  130. //
  131. if (!pmdcActive)
  132. {
  133. //
  134. // Make sure we have enough space left and remap if necessary
  135. //
  136. if ((size > mapSize - currentOffset) &&
  137. !ResizeCurrentBuffer(size))
  138. {
  139. return FALSE;
  140. }
  141. //
  142. // If the current buffer is NOT used for recording EMF data,
  143. // we simply copy the input data buffer to the end of mapped file
  144. //
  145. PVOID pvBuf = GetPtr(0, size);
  146. if(pvBuf)
  147. {
  148. CopyMemory(pvBuf, buffer, size);
  149. ReleasePtr(pvBuf);
  150. CompleteCurrentBuffer(size);
  151. }
  152. else
  153. {
  154. return FALSE;
  155. }
  156. }
  157. else
  158. {
  159. TRACE_EMFSPL(("WriteData called while recording EMF data: %d ...\n", size));
  160. //
  161. // If we have an actively mapped view for recording EMF data,
  162. // then we need to cache the input buffer into a temporary buffer.
  163. //
  164. ASSERTGDI(size % sizeof(DWORD) == 0, "WriteData: misalignment\n");
  165. return WriteTempData(&scratchBuf, buffer, size);
  166. }
  167. return TRUE;
  168. }
  169. BOOL
  170. EMFSpoolData::ResizeCurrentBuffer(
  171. DWORD newsize
  172. )
  173. /*++
  174. Routine Description:
  175. Resize the current buffer so that its size is at least newsize
  176. Arguments:
  177. newsize - New size for the current buffer
  178. Return Value:
  179. TRUE if successful, FALSE if there is an error
  180. --*/
  181. {
  182. UINT64 newMapStart, newFileSize;
  183. DWORD newMapSize, newOffset;
  184. HANDLE hNewMap;
  185. PVOID pNewMap;
  186. BOOL success = FALSE;
  187. TRACE_EMFSPL(("ResizeCurrentBuffer: %d\n", newsize));
  188. //
  189. // Don't need to do anything if we're just shrinking the current buffer
  190. //
  191. if (newsize <= mapSize - currentOffset)
  192. return TRUE;
  193. if (hFile == INVALID_HANDLE_VALUE)
  194. return FALSE;
  195. //
  196. // We should always start file mapping at an offset that's
  197. // a multiple of file mapping block size. Similarly, mapping
  198. // size should also be a multiple of block size.
  199. //
  200. // Make sure the content of the current page are always mapped in view.
  201. //
  202. DWORD blockSize = GetFileMappingAlignment();
  203. if (emfrOffset == INVALID_EMFROFFSET)
  204. newOffset = currentOffset % blockSize;
  205. else
  206. newOffset = currentOffset;
  207. newMapStart = mapStart + (currentOffset - newOffset);
  208. newMapSize = ((newsize + newOffset + blockSize - 1) / blockSize) * blockSize;
  209. newFileSize = newMapStart + newMapSize;
  210. // WINBUG 365006 04-10-2001 pravins Further cleanup needed in EMFSpoolData
  211. // We wanted to minimize the number of changes to this class to support
  212. // arbitrary sized EMF streams. There is further cleanup that is needed
  213. // in this code (removing cruft) to help reduce support costs in the furture.
  214. if(bMapping)
  215. emfc.Term();
  216. bMapping = emfc.Init(hFile, newMapStart, newFileSize);
  217. if(bMapping)
  218. {
  219. mapStart = newMapStart;
  220. mapSize = newMapSize;
  221. currentOffset = newOffset;
  222. bMapping = TRUE;
  223. success = TRUE;
  224. }
  225. else
  226. {
  227. // try to get back the old mapping ... hope this works :-)
  228. bMapping = emfc.Init(hFile, mapStart, mapSize);
  229. WARNING("ResizeCurrentBuffer: emfc intialization failed\n");
  230. }
  231. return success;
  232. }
  233. BOOL
  234. EMFSpoolData::GetEMFData(
  235. MDC *pmdc
  236. )
  237. /*++
  238. Routine Description:
  239. Return a pointer to the start the current buffer for recording EMF data.
  240. Arguments:
  241. pmdc - Pointer to the MDC object used for EMF recording
  242. Return Value:
  243. Pointer to beginning of EMF data buffer
  244. NULL if there is an error
  245. --*/
  246. {
  247. TRACE_EMFSPL(("GetEMFData: %x ...\n", pmdc));
  248. if (pmdcActive)
  249. {
  250. WARNING("GetEMFData: overlapping EMF data buffer\n");
  251. return (FALSE);
  252. }
  253. if (!ResizeCurrentBuffer(sizeof(EMFITEMHEADER) + MF_BUFSIZE_INIT))
  254. return (FALSE);
  255. //
  256. // If we're not banding, write out an incomplete EMFITEMHEADER
  257. // for an EMF_METAFILE_DATA record.
  258. //
  259. emfrOffset = mapStart + currentOffset;
  260. if (!IsBanding())
  261. {
  262. EMFITEMHEADER emfr = { EMRI_METAFILE_DATA, 0 };
  263. if (!WriteData(&emfr, sizeof(emfr)))
  264. {
  265. emfrOffset = INVALID_EMFROFFSET;
  266. return (FALSE);
  267. }
  268. }
  269. pmdcActive = pmdc;
  270. return(TRUE);
  271. }
  272. BOOL
  273. EMFSpoolData::ResizeEMFData(
  274. DWORD newsize
  275. )
  276. /*++
  277. Routine Description:
  278. Resize current EMF data buffer
  279. Arguments:
  280. newsize - new size of EMF data buffer
  281. Return Value:
  282. Pointer to the beginning of EMF data buffer
  283. NULL if there is an error
  284. --*/
  285. {
  286. TRACE_EMFSPL(("ResizeEMFData: 0x%x ...\n", newsize));
  287. ASSERTGDI(pmdcActive, "ResizeEMFData: pmdcActive is NULL\n");
  288. return ResizeCurrentBuffer(newsize);
  289. }
  290. BOOL
  291. EMFSpoolData::CompleteEMFData(
  292. DWORD size,
  293. HANDLE* outFile,
  294. UINT64* outOffset
  295. )
  296. /*++
  297. Routine Description:
  298. Finish recording EMF data
  299. Arguments:
  300. size - size of EMF data recorded
  301. Return Value:
  302. Pointer to beginning of EMF data, NULL if there is an error
  303. --*/
  304. {
  305. DWORD emfHeaderOffset = currentOffset;
  306. TRACE_EMFSPL(("CompleteEMFData: 0x%x ...\n", size));
  307. if (!pmdcActive)
  308. return FALSE;
  309. //
  310. // If size parameter is 0, the caller wants us to discard
  311. // any data recorded in the current EMF data buffer.
  312. //
  313. if (size == 0)
  314. {
  315. //
  316. // If we're not banding, we need to back over the incomplete
  317. // EMFITEMHEADER structure.
  318. //
  319. if (!IsBanding())
  320. currentOffset -= sizeof(EMFITEMHEADER);
  321. //
  322. // Get rid of any data collected in the temporary buffers as well
  323. //
  324. if ((scratchBuf && scratchBuf->currentSize) ||
  325. (fontBuf && fontBuf->currentSize))
  326. {
  327. WARNING("CompleteEMFData: temp buffers not empty\n");
  328. }
  329. FreeTempBuffers(FALSE);
  330. pmdcActive = NULL;
  331. *outOffset = emfHeaderOffset + mapStart;
  332. *outFile = hFile;
  333. return TRUE;
  334. }
  335. //
  336. // If we're not banding, fill out the incomplete EMF_METAFILE_DATA
  337. // record that we inserted earlier during GetEMFData()
  338. //
  339. if (!IsBanding())
  340. {
  341. EMFITEMHEADER *pemfr;
  342. pemfr = (EMFITEMHEADER *) GetPtrUsingSignedOffset(-((INT32) sizeof(EMFITEMHEADER)), sizeof(EMFITEMHEADER));
  343. if(pemfr)
  344. {
  345. pemfr->cjSize = size;
  346. ReleasePtr(pemfr);
  347. }
  348. else
  349. {
  350. WARNING("CompleteEMFData: failed to get EMFITEMHEADER pointer\n");
  351. return FALSE;
  352. }
  353. }
  354. //
  355. // Mark the current EMF data buffer as complete
  356. //
  357. CompleteCurrentBuffer(size);
  358. pmdcActive = NULL;
  359. //
  360. // Flush and empty the content of temporary buffers
  361. //
  362. BOOL result;
  363. result = FlushFontExtRecords() &&
  364. FlushTempBuffer(scratchBuf);
  365. FreeTempBuffers(FALSE);
  366. if(result)
  367. {
  368. *outOffset = emfHeaderOffset + mapStart;
  369. *outFile = hFile;
  370. }
  371. return result;
  372. }
  373. BOOL
  374. EMFSpoolData::AbortEMFData()
  375. /*++
  376. Routine Description:
  377. Ensure we're not actively recording EMF data
  378. Arguments:
  379. NONE
  380. Return Value:
  381. TRUE if successful, FALSE if there is a problem
  382. --*/
  383. {
  384. // if (pMapping == NULL)
  385. if(!bMapping)
  386. return FALSE;
  387. FreeTempBuffers(FALSE);
  388. if (pmdcActive != NULL)
  389. {
  390. WARNING("AbortEMFData: pmdcActive is not NULL\n");
  391. pmdcActive = NULL;
  392. emfrOffset = INVALID_EMFROFFSET;
  393. return FALSE;
  394. }
  395. return TRUE;
  396. }
  397. BOOL
  398. EMFSpoolData::MapFile()
  399. /*++
  400. Routine Description:
  401. Map the EMF spool file into the current process' address space
  402. Arguments:
  403. NONE
  404. Return Value:
  405. TRUE if successful, FALSE if there is an error
  406. --*/
  407. {
  408. if (hFile == INVALID_HANDLE_VALUE)
  409. return FALSE;
  410. else
  411. {
  412. //
  413. // Map in 64KB to start with
  414. //
  415. ResetMappingState();
  416. return ResizeCurrentBuffer(GetFileMappingAlignment());
  417. }
  418. }
  419. VOID
  420. EMFSpoolData::UnmapFile(
  421. BOOL bCloseHandle
  422. )
  423. /*++
  424. Routine Description:
  425. Unmap the currently mapped EMF spool file
  426. Arguments:
  427. bCloseHandle - Whether to close the EMF spool file handle
  428. Return Value:
  429. NONE
  430. --*/
  431. {
  432. TRACE_EMFSPL(("EMFSpoolData::UnmapFile(%d) ...\n", bCloseHandle));
  433. if(bMapping)
  434. {
  435. emfc.Term();
  436. bMapping = FALSE;
  437. }
  438. if (bCloseHandle && hFile != INVALID_HANDLE_VALUE)
  439. {
  440. if (IsBanding())
  441. {
  442. //
  443. // Close the temporary spool file (it's be deleted automatically)
  444. //
  445. if (!CloseHandle(hFile))
  446. {
  447. WARNING("Failed to close temporary spool file\n");
  448. }
  449. }
  450. else
  451. {
  452. if (!fpCloseSpoolFileHandle(hPrinter, hFile))
  453. {
  454. WARNING("CloseSpoolFileHandle failed\n");
  455. }
  456. }
  457. hFile = INVALID_HANDLE_VALUE;
  458. }
  459. ResetMappingState();
  460. }
  461. BOOL
  462. EMFSpoolData::FlushPage(
  463. DWORD pageType
  464. )
  465. /*++
  466. Routine Description:
  467. Finish the current page and flush the content of
  468. EMF spool file to the spooler
  469. Arguments:
  470. NONE
  471. Return Value:
  472. TRUE if successful, FALSE if there is an error
  473. --*/
  474. {
  475. // ASSERTGDI(pMapping && !pmdcActive, "FlushFile: inconsistent state\n");
  476. ASSERTGDI(bMapping && !pmdcActive, "FlushFile: inconsistent state\n");
  477. //
  478. // Output an EMRI_METAFILE_EXT or EMRI_BW_METAFILE_EXT record
  479. //
  480. EMFITEMHEADER_EXT endpage;
  481. endpage.emfi.ulID = (pageType == EMRI_BW_METAFILE) ?
  482. EMRI_BW_METAFILE_EXT :
  483. EMRI_METAFILE_EXT;
  484. endpage.emfi.cjSize = sizeof(endpage.offset);
  485. endpage.offset = mapStart + currentOffset - emfrOffset ;
  486. emfrOffset = INVALID_EMFROFFSET;
  487. if (!WriteData(&endpage, sizeof(endpage)))
  488. {
  489. WARNING("Failed to write out ENDPAGE record\n");
  490. return FALSE;
  491. }
  492. //
  493. // Commit the data for the current page to the spooler
  494. //
  495. DWORD size;
  496. HANDLE hNewFile;
  497. size = (DWORD) (GetTotalSize() - committedSize);
  498. TRACE_EMFSPL(("CommitSpoolData: %d bytes...\n", size));
  499. hNewFile = fpCommitSpoolData(hPrinter, hFile, size);
  500. if (hNewFile == INVALID_HANDLE_VALUE)
  501. {
  502. WARNING("CommitSpoolData failed\n");
  503. }
  504. if (hNewFile == hFile)
  505. {
  506. //
  507. // If the new handle is the same as the old handle, we
  508. // don't need to do any remapping. Simply proceed as usual.
  509. //
  510. committedSize += size;
  511. return TRUE;
  512. }
  513. else
  514. {
  515. //
  516. // Otherwise, we need to unmap the existing file
  517. // and remap the new file.
  518. //
  519. // We don't need to close existing handle here
  520. // because CommitSpoolData had already done so.
  521. //
  522. UnmapFile(FALSE);
  523. hFile = hNewFile;
  524. return MapFile();
  525. }
  526. }
  527. BOOL
  528. EMFSpoolData::WriteTempData(
  529. PTempSpoolBuf *ppBuf,
  530. PVOID data,
  531. DWORD size
  532. )
  533. /*++
  534. Routine Description:
  535. Write data into a temporary buffer
  536. Arguments:
  537. ppBuf - Points to the temporary buffer pointer
  538. data - Points to data
  539. size - Size of data to be written
  540. Return Value:
  541. TRUE if successful, FALSE if there is an error
  542. --*/
  543. #define TEMPBLOCKSIZE (4*1024)
  544. #define ALIGNTEMPBLOCK(n) (((n) + TEMPBLOCKSIZE - 1) / TEMPBLOCKSIZE * TEMPBLOCKSIZE)
  545. {
  546. PTempSpoolBuf buf = *ppBuf;
  547. DWORD bufsize;
  548. //
  549. // Check if we need to allocate or grow the temporary buffer
  550. //
  551. if (!buf || size+buf->currentSize > buf->maxSize)
  552. {
  553. if (buf == NULL)
  554. {
  555. //
  556. // Allocate a new temporary buffer
  557. //
  558. bufsize = ALIGNTEMPBLOCK(size + TEMPBUF_DATAOFFSET);
  559. buf = (PTempSpoolBuf) LocalAlloc(LMEM_FIXED, bufsize);
  560. if (buf != NULL)
  561. buf->currentSize = 0;
  562. }
  563. else
  564. {
  565. //
  566. // Reallocate an existing memory buffer
  567. //
  568. WARNING("WriteTempData: reallocating temporary buffer\n");
  569. bufsize = ALIGNTEMPBLOCK(size + TEMPBUF_DATAOFFSET + buf->currentSize);
  570. buf = (PTempSpoolBuf) LocalReAlloc((HLOCAL) *ppBuf, bufsize, LMEM_MOVEABLE);
  571. }
  572. if (buf == NULL)
  573. {
  574. WARNING("WriteTempData: memory allocation failed\n");
  575. return FALSE;
  576. }
  577. buf->maxSize = bufsize - TEMPBUF_DATAOFFSET;
  578. *ppBuf = buf;
  579. }
  580. //
  581. // Copy the data into the temporary buffer
  582. //
  583. CopyMemory(&buf->data[buf->currentSize], data, size);
  584. buf->currentSize += size;
  585. return TRUE;
  586. }
  587. VOID
  588. EMFSpoolData::FreeTempBuffers(
  589. BOOL freeMem
  590. )
  591. /*++
  592. Routine Description:
  593. Free temporary buffers
  594. Arguments:
  595. freeMem - Whether to keep or free the temporary buffer memory
  596. Return Value:
  597. NONE
  598. --*/
  599. {
  600. if (freeMem)
  601. {
  602. //
  603. // Dispose of temparary buffers
  604. //
  605. if (scratchBuf)
  606. {
  607. LocalFree((HLOCAL) scratchBuf);
  608. scratchBuf = NULL;
  609. }
  610. if (fontBuf)
  611. {
  612. LocalFree((HLOCAL) fontBuf);
  613. fontBuf = NULL;
  614. }
  615. }
  616. else
  617. {
  618. //
  619. // Empty the temporary buffers but keep the memory
  620. //
  621. if (scratchBuf)
  622. scratchBuf->currentSize = 0;
  623. if (fontBuf)
  624. fontBuf->currentSize = 0;
  625. }
  626. }
  627. BOOL
  628. EMFSpoolData::FlushTempBuffer(
  629. PTempSpoolBuf buf
  630. )
  631. /*++
  632. Routine Description:
  633. Copy the content of the temporary buffer into the spool file
  634. Arguments:
  635. NONE
  636. Return Value:
  637. TRUE if successful, FALSE if there is an error
  638. --*/
  639. {
  640. if (pmdcActive)
  641. {
  642. WARNING("FlushTempBuffer called while recording EMF data\n");
  643. return FALSE;
  644. }
  645. return (buf == NULL) ||
  646. (buf->currentSize == 0) ||
  647. WriteData(buf->data, buf->currentSize);
  648. }
  649. BOOL
  650. EMFSpoolData::AddFontExtRecord(
  651. DWORD recType,
  652. DWORD offset
  653. )
  654. /*++
  655. Routine Description:
  656. Remember where a font related EMFITEMHEADER_EXT record is
  657. Arguments:
  658. recType - Spool record type
  659. offset - Offset relative to the beginning of EMF data
  660. Return Value:
  661. TRUE if successful, FALSE if there is an error
  662. --*/
  663. {
  664. EMFITEMHEADER_EXT extrec;
  665. if (!pmdcActive)
  666. {
  667. WARNING("AddFontExtRecord: pmdcActive is NULL\n");
  668. return FALSE;
  669. }
  670. //
  671. // Map record type to its *_EXT counterpart
  672. //
  673. switch (recType)
  674. {
  675. case EMRI_ENGINE_FONT:
  676. recType = EMRI_ENGINE_FONT_EXT;
  677. break;
  678. case EMRI_TYPE1_FONT:
  679. recType = EMRI_TYPE1_FONT_EXT;
  680. break;
  681. case EMRI_DESIGNVECTOR:
  682. recType = EMRI_DESIGNVECTOR_EXT;
  683. break;
  684. case EMRI_SUBSET_FONT:
  685. recType = EMRI_SUBSET_FONT_EXT;
  686. break;
  687. case EMRI_DELTA_FONT:
  688. recType = EMRI_DELTA_FONT_EXT;
  689. break;
  690. case EMRI_EMBED_FONT_EXT:
  691. break;
  692. default:
  693. ASSERTGDI(FALSE, "AddFontExtRecord: illegal record type\n");
  694. return FALSE;
  695. }
  696. extrec.emfi.ulID = recType;
  697. extrec.emfi.cjSize = sizeof(extrec.offset);
  698. //
  699. // Remember the absolute offset relative to the beginning of file
  700. //
  701. extrec.offset = mapStart + currentOffset + offset;
  702. return WriteTempData(&fontBuf, &extrec, sizeof(extrec));
  703. }
  704. BOOL
  705. EMFSpoolData::FlushFontExtRecords()
  706. /*++
  707. Routine Description:
  708. Arguments:
  709. NONE
  710. Return Value:
  711. NONE
  712. --*/
  713. {
  714. EMFITEMHEADER_EXT *pExtRec;
  715. DWORD count;
  716. UINT64 offset;
  717. //
  718. // Don't need to do anything if the temporary font buffer is empty
  719. //
  720. if (!fontBuf || fontBuf->currentSize == 0)
  721. return TRUE;
  722. ASSERTGDI(fontBuf->currentSize % sizeof(EMFITEMHEADER_EXT) == 0,
  723. "FlushFontExtRecords: invalid size info\n");
  724. count = fontBuf->currentSize / sizeof(EMFITEMHEADER_EXT);
  725. pExtRec = (EMFITEMHEADER_EXT *) fontBuf->data;
  726. offset = mapStart + currentOffset;
  727. //
  728. // Patch the offset field in the cached EMFITEMHEADER_EXT's
  729. //
  730. while (count--)
  731. {
  732. pExtRec->offset = offset - pExtRec->offset;
  733. offset += sizeof(EMFITEMHEADER_EXT);
  734. pExtRec++;
  735. }
  736. return FlushTempBuffer(fontBuf);
  737. }
  738. /*++
  739. Routine Description:
  740. Create a temporary EMF spool file
  741. Arguments:
  742. NONE
  743. Return Value:
  744. Handle to the temporary spool file
  745. INVALID_HANDLE_VALUE if there is an error
  746. --*/
  747. HANDLE
  748. CreateTempSpoolFile()
  749. {
  750. WCHAR tempPath[MAX_PATH];
  751. WCHAR tempFilename[MAX_PATH];
  752. HANDLE hFile;
  753. //
  754. // Get a unique temporary filename
  755. //
  756. if (!GetTempPathW(MAX_PATH, tempPath) ||
  757. !GetTempFileNameW(tempPath, L"SPL", 0, tempFilename))
  758. {
  759. return INVALID_HANDLE_VALUE;
  760. }
  761. //
  762. // Open a Read/Write handle to the temporary file
  763. //
  764. hFile = CreateFileW(tempFilename,
  765. GENERIC_READ|GENERIC_WRITE,
  766. 0,
  767. NULL,
  768. CREATE_ALWAYS,
  769. FILE_ATTRIBUTE_NOT_CONTENT_INDEXED|FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_SEQUENTIAL_SCAN|FILE_FLAG_DELETE_ON_CLOSE,
  770. NULL);
  771. //
  772. // If we fail to open the file, make sure to delete it
  773. //
  774. if (hFile == INVALID_HANDLE_VALUE)
  775. {
  776. WARNING("Failed to create temporary spool file\n");
  777. DeleteFileW(tempFilename);
  778. }
  779. return hFile;
  780. }
  781. HANDLE
  782. EMFSpoolData::GetTempSpoolFileHandle()
  783. /*++
  784. Routine Description:
  785. Create a temporary EMF spool file used for banding
  786. Arguments:
  787. NONE
  788. Return Value:
  789. Handle to the temporary spool file
  790. INVALID_HANDLE_VALUE if there is an error
  791. --*/
  792. {
  793. return CreateTempSpoolFile();
  794. }
  795. //
  796. // C helper functions for working with EMFSpoolData object
  797. // (stored in the hEMFSpool field in LDC).
  798. //
  799. // NOTE: GDI doesn't new and delete operators.
  800. // So we allocate and deallocate object memory manually here.
  801. //
  802. BOOL
  803. AllocEMFSpoolData(
  804. PLDC pldc,
  805. BOOL banding
  806. )
  807. {
  808. EMFSpoolData *pEMFSpool;
  809. TRACE_EMFSPL(("AllocEMFSpoolData...\n"));
  810. //
  811. // Make sure we don't have an EMFSpoolData object
  812. // attached to LDC already
  813. //
  814. if (pldc->hEMFSpool != NULL)
  815. {
  816. WARNING("AllocEMFSpoolData: pldc->hEMFSpool is not NULL\n");
  817. DeleteEMFSpoolData(pldc);
  818. }
  819. //
  820. // Create a new EMFSpoolData object and initialize it
  821. //
  822. pEMFSpool = (EMFSpoolData *) LOCALALLOC(sizeof(EMFSpoolData));
  823. if (pEMFSpool != NULL)
  824. {
  825. if (!pEMFSpool->Init(pldc->hSpooler, banding))
  826. {
  827. pEMFSpool->Cleanup();
  828. LOCALFREE(pEMFSpool);
  829. pEMFSpool = NULL;
  830. }
  831. else
  832. pldc->hEMFSpool = (HANDLE) pEMFSpool;
  833. }
  834. return (pEMFSpool != NULL);
  835. }
  836. VOID
  837. DeleteEMFSpoolData(
  838. PLDC pldc
  839. )
  840. {
  841. EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
  842. TRACE_EMFSPL(("DeleteEMFSpoolData...\n"));
  843. if (pEMFSpool != NULL)
  844. {
  845. pldc->hEMFSpool = NULL;
  846. pEMFSpool->Cleanup();
  847. LOCALFREE(pEMFSpool);
  848. }
  849. }
  850. BOOL
  851. WriteEMFSpoolData(
  852. PLDC pldc,
  853. PVOID buffer,
  854. DWORD size
  855. )
  856. {
  857. EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
  858. TRACE_EMFSPL(("WriteEMFSpoolData...\n"));
  859. if (pEMFSpool == NULL)
  860. {
  861. ASSERTGDI(FALSE, "WriteEMFSpoolData: pldc->hEMFSpool is NULL\n");
  862. return FALSE;
  863. }
  864. else
  865. return pEMFSpool->WriteData(buffer, size);
  866. }
  867. BOOL
  868. FlushEMFSpoolData(
  869. PLDC pldc,
  870. DWORD pageType
  871. )
  872. {
  873. EMFSpoolData *pEMFSpool = (EMFSpoolData *) pldc->hEMFSpool;
  874. TRACE_EMFSPL(("FlushEMFSpoolData...\n"));
  875. if (pEMFSpool == NULL)
  876. {
  877. WARNING("FlushEMFSpoolData: pldc->hEMFSpool is NULL\n");
  878. return FALSE;
  879. }
  880. //
  881. // Ensure sure we're not actively recording EMF data
  882. //
  883. if (!pEMFSpool->AbortEMFData())
  884. return FALSE;
  885. //
  886. // If GDI is doing banding on the current DC, then
  887. // we don't need to send data to spooler. Instead,
  888. // we'll simply reuse the spool file as scratch space.
  889. //
  890. if (pEMFSpool->IsBanding())
  891. {
  892. pEMFSpool->UnmapFile(FALSE);
  893. return TRUE;
  894. }
  895. //
  896. // Finish the current page and prepare to record the next page
  897. //
  898. return pEMFSpool->FlushPage(pageType);
  899. }
  900. //
  901. // Debug code for emulating spool file handle interface
  902. //
  903. #ifdef EMULATE_SPOOLFILE_INTERFACE
  904. HANDLE emPrinterHandle = NULL;
  905. HANDLE emFileHandle = INVALID_HANDLE_VALUE;
  906. DWORD emAccumCommitSize = 0;
  907. DWORD emFileFlags = FILE_FLAG_SEQUENTIAL_SCAN;
  908. HANDLE WINAPI
  909. GetSpoolFileHandle(
  910. HANDLE hPrinter
  911. )
  912. {
  913. WCHAR tempPath[MAX_PATH];
  914. WCHAR tempFilename[MAX_PATH];
  915. HANDLE hFile;
  916. ASSERTGDI(emPrinterHandle == NULL && emFileHandle == INVALID_HANDLE_VALUE,
  917. "GetSpoolFileHandle: overlapped calls not allowed\n");
  918. if (!GetTempPathW(MAX_PATH, tempPath) ||
  919. !GetTempFileNameW(tempPath, L"SPL", 0, tempFilename))
  920. {
  921. return INVALID_HANDLE_VALUE;
  922. }
  923. hFile = CreateFileW(tempFilename,
  924. GENERIC_READ|GENERIC_WRITE,
  925. FILE_SHARE_READ|FILE_SHARE_WRITE,
  926. NULL,
  927. OPEN_EXISTING,
  928. emFileFlags,
  929. NULL);
  930. if (hFile == INVALID_HANDLE_VALUE)
  931. {
  932. WARNING("Failed to create temporary spool file\n");
  933. DeleteFileW(tempFilename);
  934. }
  935. else
  936. {
  937. emAccumCommitSize = 0;
  938. emPrinterHandle = hPrinter;
  939. emFileHandle = hFile;
  940. }
  941. return hFile;
  942. }
  943. HANDLE WINAPI
  944. CommitSpoolData(
  945. HANDLE hPrinter,
  946. HANDLE hSpoolFile,
  947. DWORD cbCommit
  948. )
  949. {
  950. ASSERTGDI(hPrinter == emPrinterHandle && hSpoolFile == emFileHandle,
  951. "CloseSpoolFileHandle: Bad handles\n");
  952. emAccumCommitSize += cbCommit;
  953. return hSpoolFile;
  954. }
  955. BOOL WINAPI
  956. CloseSpoolFileHandle(
  957. HANDLE hPrinter,
  958. HANDLE hSpoolFile
  959. )
  960. {
  961. ASSERTGDI(hPrinter == emPrinterHandle && hSpoolFile == emFileHandle,
  962. "CloseSpoolFileHandle: Bad handles\n");
  963. if (SetFilePointer(hSpoolFile, emAccumCommitSize, NULL, FILE_BEGIN) == 0xffffffff ||
  964. !SetEndOfFile(hSpoolFile))
  965. {
  966. WARNING("Couldn't set end-of-file pointer\n");
  967. }
  968. CloseHandle(hSpoolFile);
  969. emPrinterHandle = NULL;
  970. emFileHandle = INVALID_HANDLE_VALUE;
  971. return TRUE;
  972. }
  973. #endif // EMULATE_SPOOLFILE_INTERFACE