| Index: chrome/common/gfx/emf.cc
|
| ===================================================================
|
| --- chrome/common/gfx/emf.cc (revision 19913)
|
| +++ chrome/common/gfx/emf.cc (working copy)
|
| @@ -1,317 +0,0 @@
|
| -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/common/gfx/emf.h"
|
| -
|
| -#include "base/gfx/rect.h"
|
| -#include "base/logging.h"
|
| -
|
| -namespace gfx {
|
| -
|
| -Emf::Emf() : emf_(NULL), hdc_(NULL) {
|
| -}
|
| -
|
| -Emf::~Emf() {
|
| - CloseEmf();
|
| - DCHECK(!emf_ && !hdc_);
|
| -}
|
| -
|
| -bool Emf::CreateDc(HDC sibling, const RECT* rect) {
|
| - DCHECK(!emf_ && !hdc_);
|
| - hdc_ = CreateEnhMetaFile(sibling, NULL, rect, NULL);
|
| - DCHECK(hdc_);
|
| - return hdc_ != NULL;
|
| -}
|
| -
|
| -bool Emf::CreateFromData(const void* buffer, size_t size) {
|
| - DCHECK(!emf_ && !hdc_);
|
| - emf_ = SetEnhMetaFileBits(static_cast<unsigned>(size),
|
| - reinterpret_cast<const BYTE*>(buffer));
|
| - DCHECK(emf_);
|
| - return emf_ != NULL;
|
| -}
|
| -
|
| -bool Emf::CloseDc() {
|
| - DCHECK(!emf_ && hdc_);
|
| - emf_ = CloseEnhMetaFile(hdc_);
|
| - DCHECK(emf_);
|
| - hdc_ = NULL;
|
| - return emf_ != NULL;
|
| -}
|
| -
|
| -void Emf::CloseEmf() {
|
| - DCHECK(!hdc_);
|
| - if (emf_) {
|
| - DeleteEnhMetaFile(emf_);
|
| - emf_ = NULL;
|
| - }
|
| -}
|
| -
|
| -bool Emf::Playback(HDC hdc, const RECT* rect) const {
|
| - DCHECK(emf_ && !hdc_);
|
| - RECT bounds;
|
| - if (!rect) {
|
| - // Get the natural bounds of the EMF buffer.
|
| - bounds = GetBounds().ToRECT();
|
| - rect = &bounds;
|
| - }
|
| - return PlayEnhMetaFile(hdc, emf_, rect) != 0;
|
| -}
|
| -
|
| -bool Emf::SafePlayback(HDC context) const {
|
| - DCHECK(emf_ && !hdc_);
|
| - XFORM base_matrix;
|
| - if (!GetWorldTransform(context, &base_matrix)) {
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - return EnumEnhMetaFile(context,
|
| - emf_,
|
| - &Emf::SafePlaybackProc,
|
| - reinterpret_cast<void*>(&base_matrix),
|
| - &GetBounds().ToRECT()) != 0;
|
| -}
|
| -
|
| -gfx::Rect Emf::GetBounds() const {
|
| - DCHECK(emf_ && !hdc_);
|
| - ENHMETAHEADER header;
|
| - if (GetEnhMetaFileHeader(emf_, sizeof(header), &header) != sizeof(header)) {
|
| - NOTREACHED();
|
| - return gfx::Rect();
|
| - }
|
| - if (header.rclBounds.left == 0 &&
|
| - header.rclBounds.top == 0 &&
|
| - header.rclBounds.right == -1 &&
|
| - header.rclBounds.bottom == -1) {
|
| - // A freshly created EMF buffer that has no drawing operation has invalid
|
| - // bounds. Instead of having an (0,0) size, it has a (-1,-1) size. Detect
|
| - // this special case and returns an empty Rect instead of an invalid one.
|
| - return gfx::Rect();
|
| - }
|
| - return gfx::Rect(header.rclBounds.left,
|
| - header.rclBounds.top,
|
| - header.rclBounds.right - header.rclBounds.left,
|
| - header.rclBounds.bottom - header.rclBounds.top);
|
| -}
|
| -
|
| -unsigned Emf::GetDataSize() const {
|
| - DCHECK(emf_ && !hdc_);
|
| - return GetEnhMetaFileBits(emf_, 0, NULL);
|
| -}
|
| -
|
| -bool Emf::GetData(void* buffer, size_t size) const {
|
| - DCHECK(emf_ && !hdc_);
|
| - DCHECK(buffer && size);
|
| - unsigned size2 = GetEnhMetaFileBits(emf_, static_cast<unsigned>(size),
|
| - reinterpret_cast<BYTE*>(buffer));
|
| - DCHECK(size2 == size);
|
| - return size2 == size && size2 != 0;
|
| -}
|
| -
|
| -bool Emf::GetData(std::vector<uint8>* buffer) const {
|
| - unsigned size = GetDataSize();
|
| - if (!size)
|
| - return false;
|
| -
|
| - buffer->resize(size);
|
| - if (!GetData(&buffer->front(), size))
|
| - return false;
|
| - return true;
|
| -}
|
| -
|
| -bool Emf::SaveTo(const std::wstring& filename) const {
|
| - HANDLE file = CreateFile(filename.c_str(), GENERIC_WRITE,
|
| - FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
|
| - CREATE_ALWAYS, 0, NULL);
|
| - if (file == INVALID_HANDLE_VALUE)
|
| - return false;
|
| -
|
| - bool success = false;
|
| - std::vector<uint8> buffer;
|
| - if (GetData(&buffer)) {
|
| - DWORD written = 0;
|
| - if (WriteFile(file, &*buffer.begin(), static_cast<DWORD>(buffer.size()),
|
| - &written, NULL) &&
|
| - written == buffer.size()) {
|
| - success = true;
|
| - }
|
| - }
|
| - CloseHandle(file);
|
| - return success;
|
| -}
|
| -
|
| -int CALLBACK Emf::SafePlaybackProc(HDC hdc,
|
| - HANDLETABLE* handle_table,
|
| - const ENHMETARECORD* record,
|
| - int objects_count,
|
| - LPARAM param) {
|
| - const XFORM* base_matrix = reinterpret_cast<const XFORM*>(param);
|
| - EnumerationContext context;
|
| - context.handle_table = handle_table;
|
| - context.objects_count = objects_count;
|
| - context.hdc = hdc;
|
| - Record record_instance(&context, record);
|
| - bool success = record_instance.SafePlayback(base_matrix);
|
| - DCHECK(success);
|
| - return 1;
|
| -}
|
| -
|
| -Emf::Record::Record() {
|
| -}
|
| -
|
| -Emf::Record::Record(const EnumerationContext* context,
|
| - const ENHMETARECORD* record)
|
| - : record_(record),
|
| - context_(context) {
|
| - DCHECK(record_);
|
| -}
|
| -
|
| -bool Emf::Record::Play() const {
|
| - return 0 != PlayEnhMetaFileRecord(context_->hdc,
|
| - context_->handle_table,
|
| - record_,
|
| - context_->objects_count);
|
| -}
|
| -
|
| -bool Emf::Record::SafePlayback(const XFORM* base_matrix) const {
|
| - // For EMF field description, see [MS-EMF] Enhanced Metafile Format
|
| - // Specification.
|
| - //
|
| - // This is the second major EMF breakage I get; the first one being
|
| - // SetDCBrushColor/SetDCPenColor/DC_PEN/DC_BRUSH being silently ignored.
|
| - //
|
| - // This function is the guts of the fix for bug 1186598. Some printer drivers
|
| - // somehow choke on certain EMF records, but calling the corresponding
|
| - // function directly on the printer HDC is fine. Still, playing the EMF record
|
| - // fails. Go figure.
|
| - //
|
| - // The main issue is that SetLayout is totally unsupported on these printers
|
| - // (HP 4500/4700). I used to call SetLayout and I stopped. I found out this is
|
| - // not sufficient because GDI32!PlayEnhMetaFile internally calls SetLayout(!)
|
| - // Damn.
|
| - //
|
| - // So I resorted to manually parse the EMF records and play them one by one.
|
| - // The issue with this method compared to using PlayEnhMetaFile to play back
|
| - // an EMF buffer is that the later silently fixes the matrix to take in
|
| - // account the matrix currently loaded at the time of the call.
|
| - // The matrix magic is done transparently when using PlayEnhMetaFile but since
|
| - // I'm processing one field at a time, I need to do the fixup myself. Note
|
| - // that PlayEnhMetaFileRecord doesn't fix the matrix correctly even when
|
| - // called inside an EnumEnhMetaFile loop. Go figure (bis).
|
| - //
|
| - // So when I see a EMR_SETWORLDTRANSFORM and EMR_MODIFYWORLDTRANSFORM, I need
|
| - // to fix the matrix according to the matrix previously loaded before playing
|
| - // back the buffer. Otherwise, the previously loaded matrix would be ignored
|
| - // and the EMF buffer would always be played back at its native resolution.
|
| - // Duh.
|
| - //
|
| - // I also use this opportunity to skip over eventual EMR_SETLAYOUT record that
|
| - // could remain.
|
| - //
|
| - // Note: I should probably care about view ports and clipping, eventually.
|
| - bool res;
|
| - switch (record()->iType) {
|
| - case EMR_SETWORLDTRANSFORM: {
|
| - DCHECK_EQ(record()->nSize, sizeof(DWORD) * 2 + sizeof(XFORM));
|
| - const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
|
| - HDC hdc = context_->hdc;
|
| - if (base_matrix) {
|
| - res = 0 != SetWorldTransform(hdc, base_matrix) &&
|
| - ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
|
| - } else {
|
| - res = 0 != SetWorldTransform(hdc, xform);
|
| - }
|
| - break;
|
| - }
|
| - case EMR_MODIFYWORLDTRANSFORM: {
|
| - DCHECK_EQ(record()->nSize,
|
| - sizeof(DWORD) * 2 + sizeof(XFORM) + sizeof(DWORD));
|
| - const XFORM* xform = reinterpret_cast<const XFORM*>(record()->dParm);
|
| - const DWORD* option = reinterpret_cast<const DWORD*>(xform + 1);
|
| - HDC hdc = context_->hdc;
|
| - switch (*option) {
|
| - case MWT_IDENTITY:
|
| - if (base_matrix) {
|
| - res = 0 != SetWorldTransform(hdc, base_matrix);
|
| - } else {
|
| - res = 0 != ModifyWorldTransform(hdc, xform, MWT_IDENTITY);
|
| - }
|
| - break;
|
| - case MWT_LEFTMULTIPLY:
|
| - case MWT_RIGHTMULTIPLY:
|
| - res = 0 != ModifyWorldTransform(hdc, xform, *option);
|
| - break;
|
| - case 4: // MWT_SET
|
| - if (base_matrix) {
|
| - res = 0 != SetWorldTransform(hdc, base_matrix) &&
|
| - ModifyWorldTransform(hdc, xform, MWT_LEFTMULTIPLY);
|
| - } else {
|
| - res = 0 != SetWorldTransform(hdc, xform);
|
| - }
|
| - break;
|
| - default:
|
| - res = false;
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| - case EMR_SETLAYOUT:
|
| - // Ignore it.
|
| - res = true;
|
| - break;
|
| - default: {
|
| - res = Play();
|
| - break;
|
| - }
|
| - }
|
| - return res;
|
| -}
|
| -
|
| -Emf::Enumerator::Enumerator(const Emf& emf, HDC context, const RECT* rect) {
|
| - context_.handle_table = NULL;
|
| - context_.objects_count = 0;
|
| - context_.hdc = NULL;
|
| - items_.clear();
|
| - if (!EnumEnhMetaFile(context,
|
| - emf.emf(),
|
| - &Emf::Enumerator::EnhMetaFileProc,
|
| - reinterpret_cast<void*>(this),
|
| - rect)) {
|
| - NOTREACHED();
|
| - items_.clear();
|
| - }
|
| - DCHECK_EQ(context_.hdc, context);
|
| -}
|
| -
|
| -Emf::Enumerator::const_iterator Emf::Enumerator::begin() const {
|
| - return items_.begin();
|
| -}
|
| -
|
| -Emf::Enumerator::const_iterator Emf::Enumerator::end() const {
|
| - return items_.end();
|
| -}
|
| -
|
| -int CALLBACK Emf::Enumerator::EnhMetaFileProc(HDC hdc,
|
| - HANDLETABLE* handle_table,
|
| - const ENHMETARECORD* record,
|
| - int objects_count,
|
| - LPARAM param) {
|
| - Enumerator& emf = *reinterpret_cast<Enumerator*>(param);
|
| - if (!emf.context_.handle_table) {
|
| - DCHECK(!emf.context_.handle_table);
|
| - DCHECK(!emf.context_.objects_count);
|
| - emf.context_.handle_table = handle_table;
|
| - emf.context_.objects_count = objects_count;
|
| - emf.context_.hdc = hdc;
|
| - } else {
|
| - DCHECK_EQ(emf.context_.handle_table, handle_table);
|
| - DCHECK_EQ(emf.context_.objects_count, objects_count);
|
| - DCHECK_EQ(emf.context_.hdc, hdc);
|
| - }
|
| - emf.items_.push_back(Record(&emf.context_, record));
|
| - return 1;
|
| -}
|
| -
|
| -} // namespace gfx
|
|
|