blob: 50e1cf80c8abad8aa575fd84080e7d109b4aed1b [file] [log] [blame]
/*
* 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 <WebCore/ColorMac.h>
#import <pal/spi/cg/CoreGraphicsSPI.h>
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> TestPDFPage::create(PDFPage *page)
{
return adoptRef(*new TestPDFPage(page));
}
TestPDFPage::TestPDFPage(PDFPage *page)
: m_page(page)
{
}
const Vector<TestPDFAnnotation>& TestPDFPage::annotations()
{
if (!m_annotations) {
m_annotations = Vector<TestPDFAnnotation>();
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(), kCGImageAlphaPremultipliedLast | 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<WebCore::SRGBA<uint8_t>>(r * 255 / a, g * 255 / a, b * 255 / a, a);
}
// Documents
Ref<TestPDFDocument> 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)