/* * Copyright (C) 2019 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "TestPDFDocument.h" #if HAVE(PDFKIT) #import #import namespace TestWebKitAPI { #if PLATFORM(MAC) CGRect toCGRect(NSRect rect) { return NSRectToCGRect(rect); } NSPoint toPlatformPoint(CGPoint point) { return NSPointFromCGPoint(point); } #else CGRect toCGRect(CGRect rect) { return rect; } NSPoint toPlatformPoint(CGPoint point) { return point; } #endif // Annotations TestPDFAnnotation::TestPDFAnnotation(PDFAnnotation *annotation) : m_annotation(annotation) { } bool TestPDFAnnotation::isLink() const { bool isLink = [m_annotation.get().type isEqualToString:@"Link"]; if (isLink) ASSERT([m_annotation.get().action isKindOfClass:[PDFActionURL class]]); return isLink; } CGRect TestPDFAnnotation::bounds() const { return toCGRect(m_annotation.get().bounds); } NSURL *TestPDFAnnotation::linkURL() const { if (!isLink()) return nil; return ((PDFActionURL *)m_annotation.get().action).URL; } // Pages Ref TestPDFPage::create(PDFPage *page) { return adoptRef(*new TestPDFPage(page)); } TestPDFPage::TestPDFPage(PDFPage *page) : m_page(page) { } const Vector& TestPDFPage::annotations() { if (!m_annotations) { m_annotations = Vector(); for (PDFAnnotation *annotation in m_page.get().annotations) m_annotations->append({ annotation }); } return *m_annotations; } size_t TestPDFPage::characterCount() const { return text().length(); } inline bool shouldStrip(UChar character) { // This is a list of trailing and leading white space characters we've seen in PDF generation. // It can be expanded if we see more popup. return character == ' ' || character == '\n'; } String TestPDFPage::text() const { if (!m_textWithoutSurroundingWhitespace) m_textWithoutSurroundingWhitespace = String(m_page.get().string).stripLeadingAndTrailingCharacters(shouldStrip); return *m_textWithoutSurroundingWhitespace; } CGRect TestPDFPage::rectForCharacterAtIndex(size_t index) const { return toCGRect([m_page characterBoundsAtIndex:index]); } size_t TestPDFPage::characterIndexAtPoint(CGPoint point) const { return [m_page characterIndexAtPoint:toPlatformPoint(point)]; } CGRect TestPDFPage::bounds() const { return toCGRect([m_page boundsForBox:kPDFDisplayBoxMediaBox]); } WebCore::Color TestPDFPage::colorAtPoint(int x, int y) const { auto boundsRect = bounds(); auto colorSpace = adoptCF(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)); auto context = adoptCF(CGBitmapContextCreate(NULL, boundsRect.size.width, boundsRect.size.height, 8, 0, colorSpace.get(), static_cast(kCGImageAlphaPremultipliedLast) | static_cast(kCGBitmapByteOrder32Big))); auto cgPage = m_page.get().pageRef; CGContextDrawPDFPageWithAnnotations(context.get(), cgPage, nullptr); const unsigned char* pixel = (const unsigned char*)CGBitmapContextGetData(context.get()); size_t i = (y * x * 4) + (x * 4); auto r = pixel[i]; auto g = pixel[i + 1]; auto b = pixel[i + 2]; auto a = pixel[i + 3]; if (!a) return WebCore::Color::transparentBlack; return WebCore::makeFromComponentsClampingExceptAlpha>(r * 255 / a, g * 255 / a, b * 255 / a, a); } // Documents Ref TestPDFDocument::createFromData(NSData *data) { return adoptRef(*new TestPDFDocument(data)); } TestPDFDocument::TestPDFDocument(NSData *data) : m_document(adoptNS([[PDFDocument alloc] initWithData:data])) , m_pages(pageCount()) { } size_t TestPDFDocument::pageCount() const { return [m_document pageCount]; } TestPDFPage* TestPDFDocument::page(size_t index) { if (index >= pageCount()) return nullptr; if (!m_pages[index]) m_pages[index] = TestPDFPage::create([m_document pageAtIndex:index]); return m_pages[index].get(); } } // namespace TestWebKitAPI #endif // HAVE(PDFKIT)