From df6df689c5b61d17c5b18607c454152b6cc9ec8a Mon Sep 17 00:00:00 2001 From: "avi@chromium.org" Date: Mon, 2 May 2011 19:50:50 +0000 Subject: Horrible hack to work around PDFKit bug. BUG=64641 TEST=attempt to print pdf linked to in comment 4; shouldn't sad-tab. Review URL: http://codereview.chromium.org/6903147 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@83765 0039d316-1c4b-4281-b951-d872f2087c98 --- printing/pdf_metafile_cg_mac.cc | 59 +++++++++++++++++++++++++++++++++++++++-- printing/pdf_metafile_cg_mac.h | 6 ++++- 2 files changed, 62 insertions(+), 3 deletions(-) (limited to 'printing') diff --git a/printing/pdf_metafile_cg_mac.cc b/printing/pdf_metafile_cg_mac.cc index eedd078..9320b9e 100644 --- a/printing/pdf_metafile_cg_mac.cc +++ b/printing/pdf_metafile_cg_mac.cc @@ -7,19 +7,74 @@ #include "base/file_path.h" #include "base/logging.h" #include "base/mac/scoped_cftyperef.h" +#include "base/sys_info.h" #include "base/sys_string_conversions.h" +#include "base/threading/thread_local.h" #include "ui/gfx/rect.h" #include "ui/gfx/size.h" using base::mac::ScopedCFTypeRef; +namespace { + +// What is up with this ugly hack? , that's what. +// The bug: Printing certain PDFs crashes. The cause: When printing, the +// renderer process assembles pages one at a time, in PDF format, to send to the +// browser process. When printing a PDF, the PDF plugin returns output in PDF +// format. There is a bug in 10.5 and 10.6 (, +// ) where reference counting is broken when +// drawing certain PDFs into PDF contexts. So at the high-level, a PdfMetafileCg +// is used to hold the destination context, and then about five layers down on +// the callstack, a PdfMetafileCg is used to hold the source PDF. If the source +// PDF is drawn into the destination PDF context and then released, accessing +// the destination PDF context will crash. So the outermost instantiation of +// PdfMetafileCg creates a pool for deeper instantiations to dump their used +// PDFs into rather than releasing them. When the top-level PDF is closed, then +// it's safe to clear the pool. A thread local is used to allow this to work in +// single-process mode. TODO(avi): This Apple bug appears fixed in 10.7; when +// 10.7 is the minimum required version for Chromium, remove this hack. + +base::ThreadLocalPointer thread_pdf_docs; + +bool PDFBugFixed() { + int32 major_version; + int32 minor_version; + int32 bugfix_version; + base::SysInfo::OperatingSystemVersionNumbers(&major_version, + &minor_version, + &bugfix_version); + return + major_version > 10 || (major_version == 10 && minor_version >= 7); +} + +} // namespace + namespace printing { PdfMetafileCg::PdfMetafileCg() - : page_is_open_(false) { + : page_is_open_(false), + thread_pdf_docs_owned_(false) { + static bool bug_fixed = PDFBugFixed(); + if (!thread_pdf_docs.Get() && !bug_fixed) { + thread_pdf_docs_owned_ = true; + thread_pdf_docs.Set(CFSetCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeSetCallBacks)); + } } -PdfMetafileCg::~PdfMetafileCg() {} +PdfMetafileCg::~PdfMetafileCg() { + DCHECK(CalledOnValidThread()); + if (pdf_doc_ && thread_pdf_docs.Get()) { + // Transfer ownership to the pool. + CFSetAddValue(thread_pdf_docs.Get(), pdf_doc_); + } + + if (thread_pdf_docs_owned_) { + CFRelease(thread_pdf_docs.Get()); + thread_pdf_docs.Set(NULL); + } +} bool PdfMetafileCg::Init() { // Ensure that Init hasn't already been called. diff --git a/printing/pdf_metafile_cg_mac.h b/printing/pdf_metafile_cg_mac.h index 92157e1..bffbce5 100644 --- a/printing/pdf_metafile_cg_mac.h +++ b/printing/pdf_metafile_cg_mac.h @@ -11,6 +11,7 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/mac/scoped_cftyperef.h" +#include "base/threading/thread_checker.h" #include "printing/metafile.h" class FilePath; @@ -24,7 +25,7 @@ class Point; namespace printing { // This class creates a graphics context that renders into a PDF data stream. -class PdfMetafileCg : public Metafile { +class PdfMetafileCg : public Metafile, public base::ThreadChecker { public: PdfMetafileCg(); virtual ~PdfMetafileCg(); @@ -80,6 +81,9 @@ class PdfMetafileCg : public Metafile { // Whether or not a page is currently open. bool page_is_open_; + // Whether this instantiation of the PdfMetafileCg owns the thread_pdf_docs. + bool thread_pdf_docs_owned_; + DISALLOW_COPY_AND_ASSIGN(PdfMetafileCg); }; -- cgit v1.1