16f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 The Android Open Source Project
36f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
66f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com */
76f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
96f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com#include "SkJpegUtility.h"
106f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
116f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com/////////////////////////////////////////////////////////////////////
126f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic void sk_init_source(j_decompress_ptr cinfo) {
136f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
146f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
156f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    src->bytes_in_buffer = 0;
16d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
17113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    src->current_offset = 0;
18113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
194d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com    if (!src->fStream->rewind()) {
204d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com        SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
214d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com        cinfo->err->error_exit((j_common_ptr)cinfo);
224d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com    }
2357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com}
2457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com
25d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
26113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.comstatic boolean sk_seek_input_data(j_decompress_ptr cinfo, long byte_offset) {
27113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
28d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    size_t bo = (size_t) byte_offset;
29113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
30d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    if (bo > src->current_offset) {
31d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com        (void)src->fStream->skip(bo - src->current_offset);
32113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    } else {
334d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com        if (!src->fStream->rewind()) {
344d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com            SkDebugf("xxxxxxxxxxxxxx failure to rewind\n");
354d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com            cinfo->err->error_exit((j_common_ptr)cinfo);
364d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com            return false;
374d213ab944d96ad60a243ac1ad21c793c1acc80ascroggo@google.com        }
38d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com        (void)src->fStream->skip(bo);
39113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    }
40113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
41d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    src->current_offset = bo;
42113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
43113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    src->bytes_in_buffer = 0;
44113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    return true;
45113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com}
46113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
47113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com
486f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic boolean sk_fill_input_buffer(j_decompress_ptr cinfo) {
496f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_source_mgr* src = (skjpeg_source_mgr*)cinfo->src;
506f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    if (src->fDecoder != NULL && src->fDecoder->shouldCancelDecode()) {
516f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        return FALSE;
526f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    }
536f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    size_t bytes = src->fStream->read(src->fBuffer, skjpeg_source_mgr::kBufferSize);
546f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    // note that JPEG is happy with less than the full read,
556f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    // as long as the result is non-zero
566f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    if (bytes == 0) {
576f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        return FALSE;
586f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    }
596f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
60d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
61113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    src->current_offset += bytes;
62113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
636f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    src->next_input_byte = (const JOCTET*)src->fBuffer;
646f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    src->bytes_in_buffer = bytes;
656f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    return TRUE;
666f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
676f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
686f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
696f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
706f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
713f1f06a26bdb2022a5c72f93ae623a57b6659464reed@android.com    if (num_bytes > (long)src->bytes_in_buffer) {
728b169311b59ab84e8ca6f3630a1e960cc1be751erobertphillips@google.com        size_t bytesToSkip = num_bytes - src->bytes_in_buffer;
73b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com        while (bytesToSkip > 0) {
748b169311b59ab84e8ca6f3630a1e960cc1be751erobertphillips@google.com            size_t bytes = src->fStream->skip(bytesToSkip);
75b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com            if (bytes <= 0 || bytes > bytesToSkip) {
76b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com//              SkDebugf("xxxxxxxxxxxxxx failure to skip request %d returned %d\n", bytesToSkip, bytes);
77b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com                cinfo->err->error_exit((j_common_ptr)cinfo);
78b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com                return;
79b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com            }
80d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
81113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com            src->current_offset += bytes;
82113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
83b8fd84b803b2a2f4d304e0763b83a90f582b449areed@android.com            bytesToSkip -= bytes;
846f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        }
856f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        src->next_input_byte = (const JOCTET*)src->fBuffer;
866f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        src->bytes_in_buffer = 0;
876f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    } else {
886f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        src->next_input_byte += num_bytes;
896f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        src->bytes_in_buffer -= num_bytes;
906f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    }
916f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
926f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
936f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic void sk_term_source(j_decompress_ptr /*cinfo*/) {}
946f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
956f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
966f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com///////////////////////////////////////////////////////////////////////////////
976f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
98d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.comskjpeg_source_mgr::skjpeg_source_mgr(SkStream* stream, SkImageDecoder* decoder)
99d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    : fStream(SkRef(stream))
100d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    , fDecoder(decoder) {
10157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com
10257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com    init_source = sk_init_source;
10357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com    fill_input_buffer = sk_fill_input_buffer;
10457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com    skip_input_data = sk_skip_input_data;
105a93489986789bdf109064884bb940ced71110349scroggo@google.com    resync_to_restart = jpeg_resync_to_restart;
10657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com    term_source = sk_term_source;
107d79277f67824392876b82cf5635cc11f819e64dfscroggo@google.com#ifdef SK_BUILD_FOR_ANDROID
108113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com    seek_input_data = sk_seek_input_data;
109113994051b41366a7b25851d05cd56e89866a33bdjsollen@google.com#endif
1106f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com//    SkDebugf("**************** use memorybase %p %d\n", fMemoryBase, fMemoryBaseSize);
1116f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
1126f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
11357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comskjpeg_source_mgr::~skjpeg_source_mgr() {
114d4c3565aac5c83ff0008453abed4c6d6009bb394scroggo@google.com    SkSafeUnref(fStream);
11557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com}
11657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com
1176f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com///////////////////////////////////////////////////////////////////////////////
1186f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1196f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic void sk_init_destination(j_compress_ptr cinfo) {
1206f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
1216f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1226f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    dest->next_output_byte = dest->fBuffer;
1236f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
1246f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
1256f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1266f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic boolean sk_empty_output_buffer(j_compress_ptr cinfo) {
1276f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
1286f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1296f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com//  if (!dest->fStream->write(dest->fBuffer, skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer))
1306f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    if (!dest->fStream->write(dest->fBuffer,
1316f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com            skjpeg_destination_mgr::kBufferSize)) {
1326f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        ERREXIT(cinfo, JERR_FILE_WRITE);
1336f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        return false;
1346f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    }
1356f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1366f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    dest->next_output_byte = dest->fBuffer;
1376f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    dest->free_in_buffer = skjpeg_destination_mgr::kBufferSize;
1386f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    return TRUE;
1396f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
1406f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1416f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comstatic void sk_term_destination (j_compress_ptr cinfo) {
1426f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_destination_mgr* dest = (skjpeg_destination_mgr*)cinfo->dest;
1436f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1446f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    size_t size = skjpeg_destination_mgr::kBufferSize - dest->free_in_buffer;
1456f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    if (size > 0) {
1466f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        if (!dest->fStream->write(dest->fBuffer, size)) {
1476f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com            ERREXIT(cinfo, JERR_FILE_WRITE);
1486f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com            return;
1496f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        }
1506f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    }
1516f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    dest->fStream->flush();
1526f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
1536f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1546f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comskjpeg_destination_mgr::skjpeg_destination_mgr(SkWStream* stream)
1556f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com        : fStream(stream) {
1566f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    this->init_destination = sk_init_destination;
1576f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    this->empty_output_buffer = sk_empty_output_buffer;
1586f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    this->term_destination = sk_term_destination;
1596f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
1606f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1616f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.comvoid skjpeg_error_exit(j_common_ptr cinfo) {
1626f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    skjpeg_error_mgr* error = (skjpeg_error_mgr*)cinfo->err;
1636f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1646f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    (*error->output_message) (cinfo);
1656f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1666f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    /* Let the memory manager delete any temp files before we die */
1676f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    jpeg_destroy(cinfo);
1686f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com
1696f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com    longjmp(error->fJmpBuf, -1);
1706f59815b3dbd19efb8a29d0115deea9c88da8ae1reed@android.com}
171